mirror of
https://github.com/ghostersk/gowebmail.git
synced 2026-04-17 08:36:01 +01:00
292 lines
10 KiB
Go
292 lines
10 KiB
Go
package models
|
|
|
|
import "time"
|
|
|
|
// ---- Users ----
|
|
|
|
// UserRole controls access level within GoWebMail.
|
|
type UserRole string
|
|
|
|
const (
|
|
RoleAdmin UserRole = "admin"
|
|
RoleUser UserRole = "user"
|
|
)
|
|
|
|
// User represents a GoWebMail application user.
|
|
type User struct {
|
|
ID int64 `json:"id"`
|
|
Email string `json:"email"`
|
|
Username string `json:"username"`
|
|
PasswordHash string `json:"-"`
|
|
Role UserRole `json:"role"`
|
|
IsActive bool `json:"is_active"`
|
|
// MFA
|
|
MFAEnabled bool `json:"mfa_enabled"`
|
|
MFASecret string `json:"-"` // TOTP secret, stored encrypted
|
|
// Pending MFA setup (secret generated but not yet verified)
|
|
MFAPending string `json:"-"`
|
|
// Preferences
|
|
SyncInterval int `json:"sync_interval"`
|
|
ComposePopup bool `json:"compose_popup"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
LastLoginAt *time.Time `json:"last_login_at,omitempty"`
|
|
}
|
|
|
|
// ---- Audit Log ----
|
|
|
|
// AuditEventType categorises log events.
|
|
type AuditEventType string
|
|
|
|
const (
|
|
AuditLogin AuditEventType = "login"
|
|
AuditLoginFail AuditEventType = "login_fail"
|
|
AuditLogout AuditEventType = "logout"
|
|
AuditMFASuccess AuditEventType = "mfa_success"
|
|
AuditMFAFail AuditEventType = "mfa_fail"
|
|
AuditMFAEnable AuditEventType = "mfa_enable"
|
|
AuditMFADisable AuditEventType = "mfa_disable"
|
|
AuditUserCreate AuditEventType = "user_create"
|
|
AuditUserDelete AuditEventType = "user_delete"
|
|
AuditUserUpdate AuditEventType = "user_update"
|
|
AuditAccountAdd AuditEventType = "account_add"
|
|
AuditAccountDel AuditEventType = "account_delete"
|
|
AuditSyncRun AuditEventType = "sync_run"
|
|
AuditConfigChange AuditEventType = "config_change"
|
|
AuditAppError AuditEventType = "app_error"
|
|
)
|
|
|
|
// AuditLog is a single audit event.
|
|
type AuditLog struct {
|
|
ID int64 `json:"id"`
|
|
UserID *int64 `json:"user_id,omitempty"`
|
|
UserEmail string `json:"user_email,omitempty"`
|
|
Event AuditEventType `json:"event"`
|
|
Detail string `json:"detail,omitempty"`
|
|
IPAddress string `json:"ip_address,omitempty"`
|
|
UserAgent string `json:"user_agent,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// AuditPage is a paginated audit log result.
|
|
type AuditPage struct {
|
|
Logs []AuditLog `json:"logs"`
|
|
Total int `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
HasMore bool `json:"has_more"`
|
|
}
|
|
|
|
// ---- Email Accounts ----
|
|
|
|
// AccountProvider indicates the email provider type.
|
|
type AccountProvider string
|
|
|
|
const (
|
|
ProviderGmail AccountProvider = "gmail"
|
|
ProviderOutlook AccountProvider = "outlook"
|
|
ProviderOutlookPersonal AccountProvider = "outlook_personal" // personal outlook.com via Graph API
|
|
ProviderIMAPSMTP AccountProvider = "imap_smtp"
|
|
)
|
|
|
|
// EmailAccount represents a connected email account (Gmail, Outlook, IMAP).
|
|
type EmailAccount struct {
|
|
ID int64 `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
Provider AccountProvider `json:"provider"`
|
|
EmailAddress string `json:"email_address"`
|
|
DisplayName string `json:"display_name"`
|
|
// OAuth tokens (stored encrypted in DB)
|
|
AccessToken string `json:"-"`
|
|
RefreshToken string `json:"-"`
|
|
TokenExpiry time.Time `json:"-"`
|
|
// IMAP/SMTP settings (optional, stored encrypted)
|
|
IMAPHost string `json:"imap_host,omitempty"`
|
|
IMAPPort int `json:"imap_port,omitempty"`
|
|
SMTPHost string `json:"smtp_host,omitempty"`
|
|
SMTPPort int `json:"smtp_port,omitempty"`
|
|
// Sync settings
|
|
SyncDays int `json:"sync_days"` // how many days back to fetch (0 = all)
|
|
SyncMode string `json:"sync_mode"` // "days" or "all"
|
|
// SyncInterval is populated from the owning user's setting during background sync
|
|
SyncInterval int `json:"-"`
|
|
LastError string `json:"last_error,omitempty"`
|
|
// Display
|
|
Color string `json:"color"`
|
|
IsActive bool `json:"is_active"`
|
|
SortOrder int `json:"sort_order"`
|
|
LastSync time.Time `json:"last_sync"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
// Folder represents a mailbox folder or Gmail label.
|
|
type Folder struct {
|
|
ID int64 `json:"id"`
|
|
AccountID int64 `json:"account_id"`
|
|
Name string `json:"name"` // Display name
|
|
FullPath string `json:"full_path"` // e.g. "INBOX", "[Gmail]/Sent Mail"
|
|
FolderType string `json:"folder_type"` // inbox, sent, drafts, trash, spam, custom
|
|
UnreadCount int `json:"unread_count"`
|
|
TotalCount int `json:"total_count"`
|
|
IsHidden bool `json:"is_hidden"`
|
|
SyncEnabled bool `json:"sync_enabled"`
|
|
}
|
|
|
|
// ---- Messages ----
|
|
|
|
// MessageFlag represents IMAP message flags.
|
|
type MessageFlag string
|
|
|
|
const (
|
|
FlagSeen MessageFlag = "\\Seen"
|
|
FlagAnswered MessageFlag = "\\Answered"
|
|
FlagFlagged MessageFlag = "\\Flagged"
|
|
FlagDeleted MessageFlag = "\\Deleted"
|
|
FlagDraft MessageFlag = "\\Draft"
|
|
)
|
|
|
|
// Attachment holds metadata for email attachments.
|
|
type Attachment struct {
|
|
ID int64 `json:"id"`
|
|
MessageID int64 `json:"message_id"`
|
|
Filename string `json:"filename"`
|
|
ContentType string `json:"content_type"`
|
|
Size int64 `json:"size"`
|
|
ContentID string `json:"content_id,omitempty"` // for inline attachments
|
|
Data []byte `json:"-"` // actual bytes, loaded on demand
|
|
}
|
|
|
|
// Message represents a cached email message.
|
|
type Message struct {
|
|
ID int64 `json:"id"`
|
|
AccountID int64 `json:"account_id"`
|
|
FolderID int64 `json:"folder_id"`
|
|
RemoteUID string `json:"remote_uid"` // UID from provider (IMAP UID or Gmail message ID)
|
|
ThreadID string `json:"thread_id,omitempty"`
|
|
MessageID string `json:"message_id"` // RFC 2822 Message-ID header
|
|
// Encrypted fields (stored encrypted, decrypted on read)
|
|
Subject string `json:"subject"`
|
|
FromName string `json:"from_name"`
|
|
FromEmail string `json:"from_email"`
|
|
ToList string `json:"to"` // comma-separated
|
|
CCList string `json:"cc"`
|
|
BCCList string `json:"bcc"`
|
|
ReplyTo string `json:"reply_to"`
|
|
BodyText string `json:"body_text,omitempty"`
|
|
BodyHTML string `json:"body_html,omitempty"`
|
|
// Metadata (not encrypted)
|
|
Date time.Time `json:"date"`
|
|
IsRead bool `json:"is_read"`
|
|
IsStarred bool `json:"is_starred"`
|
|
IsDraft bool `json:"is_draft"`
|
|
HasAttachment bool `json:"has_attachment"`
|
|
Attachments []Attachment `json:"attachments,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// MessageSummary is a lightweight version for list views.
|
|
type MessageSummary struct {
|
|
ID int64 `json:"id"`
|
|
AccountID int64 `json:"account_id"`
|
|
AccountEmail string `json:"account_email"`
|
|
AccountColor string `json:"account_color"`
|
|
FolderID int64 `json:"folder_id"`
|
|
FolderName string `json:"folder_name"`
|
|
Subject string `json:"subject"`
|
|
FromName string `json:"from_name"`
|
|
FromEmail string `json:"from_email"`
|
|
Preview string `json:"preview"` // first ~100 chars of body
|
|
Date time.Time `json:"date"`
|
|
IsRead bool `json:"is_read"`
|
|
IsStarred bool `json:"is_starred"`
|
|
HasAttachment bool `json:"has_attachment"`
|
|
}
|
|
|
|
// ---- Compose ----
|
|
|
|
// ComposeRequest is the payload for sending/replying/forwarding.
|
|
type ComposeRequest struct {
|
|
AccountID int64 `json:"account_id"`
|
|
To []string `json:"to"`
|
|
CC []string `json:"cc"`
|
|
BCC []string `json:"bcc"`
|
|
Subject string `json:"subject"`
|
|
BodyHTML string `json:"body_html"`
|
|
BodyText string `json:"body_text"`
|
|
// For reply/forward
|
|
InReplyToID int64 `json:"in_reply_to_id,omitempty"`
|
|
ForwardFromID int64 `json:"forward_from_id,omitempty"`
|
|
// Attachments: populated from multipart/form-data or inline base64
|
|
Attachments []Attachment `json:"attachments,omitempty"`
|
|
}
|
|
|
|
// ---- Search ----
|
|
|
|
// SearchQuery parameters.
|
|
type SearchQuery struct {
|
|
Query string `json:"query"`
|
|
AccountID int64 `json:"account_id"` // 0 = all accounts
|
|
FolderID int64 `json:"folder_id"` // 0 = all folders
|
|
From string `json:"from"`
|
|
To string `json:"to"`
|
|
HasAttachment bool `json:"has_attachment"`
|
|
IsUnread bool `json:"is_unread"`
|
|
IsStarred bool `json:"is_starred"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
}
|
|
|
|
// PagedMessages is a paginated message result.
|
|
type PagedMessages struct {
|
|
Messages []MessageSummary `json:"messages"`
|
|
Total int `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
HasMore bool `json:"has_more"`
|
|
}
|
|
|
|
// ---- Contacts ----
|
|
|
|
type Contact struct {
|
|
ID int64 `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
DisplayName string `json:"display_name"`
|
|
Email string `json:"email"`
|
|
Phone string `json:"phone"`
|
|
Company string `json:"company"`
|
|
Notes string `json:"notes"`
|
|
AvatarColor string `json:"avatar_color"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// ---- Calendar ----
|
|
|
|
type CalendarEvent struct {
|
|
ID int64 `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
AccountID *int64 `json:"account_id,omitempty"`
|
|
UID string `json:"uid"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
Location string `json:"location"`
|
|
StartTime string `json:"start_time"`
|
|
EndTime string `json:"end_time"`
|
|
AllDay bool `json:"all_day"`
|
|
RecurrenceRule string `json:"recurrence_rule"`
|
|
Color string `json:"color"`
|
|
Status string `json:"status"`
|
|
OrganizerEmail string `json:"organizer_email"`
|
|
Attendees string `json:"attendees"`
|
|
AccountColor string `json:"account_color,omitempty"`
|
|
AccountEmail string `json:"account_email,omitempty"`
|
|
}
|
|
|
|
type CalDAVToken struct {
|
|
ID int64 `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
Token string `json:"token"`
|
|
Label string `json:"label"`
|
|
CreatedAt string `json:"created_at"`
|
|
LastUsed string `json:"last_used,omitempty"`
|
|
}
|