package mail import ( "strings" "github.com/ultisuite/ulti-backend/internal/api/apivalidate" ) const maxSettingsRequestBody = 4 << 10 // 4 KiB var ( allowedDensities = map[string]struct{}{ "default": {}, "normal": {}, "compact": {}, } allowedThemeModes = map[string]struct{}{ "light": {}, "dark": {}, "system": {}, } allowedBackgroundIDs = map[string]struct{}{ "none": {}, "gradient-aurora": {}, "gradient-sunset": {}, "gradient-ocean": {}, "gradient-blossom": {}, "photo-mountains": {}, "photo-ocean": {}, "photo-city": {}, "photo-nature": {}, } allowedInboxSorts = map[string]struct{}{ "default": {}, "important": {}, "unread": {}, "starred": {}, } allowedReadingPanes = map[string]struct{}{ "none": {}, "right": {}, "below": {}, } ) type MailNotificationSettings struct { DesktopNewMail bool `json:"desktop_new_mail"` DesktopMentions bool `json:"desktop_mentions"` EmailDigest bool `json:"email_digest"` SoundEnabled bool `json:"sound_enabled"` } type MailSettings struct { Density string `json:"density"` ThemeMode string `json:"theme_mode"` BackgroundID string `json:"background_id"` InboxSort string `json:"inbox_sort"` ReadingPane string `json:"reading_pane"` ConversationMode bool `json:"conversation_mode"` Notifications MailNotificationSettings `json:"notifications"` UpdatedAt any `json:"updated_at,omitempty"` } type patchMailNotificationSettings struct { DesktopNewMail *bool `json:"desktop_new_mail"` DesktopMentions *bool `json:"desktop_mentions"` EmailDigest *bool `json:"email_digest"` SoundEnabled *bool `json:"sound_enabled"` } type patchMailSettingsRequest struct { Density *string `json:"density"` ThemeMode *string `json:"theme_mode"` BackgroundID *string `json:"background_id"` InboxSort *string `json:"inbox_sort"` ReadingPane *string `json:"reading_pane"` ConversationMode *bool `json:"conversation_mode"` Notifications *patchMailNotificationSettings `json:"notifications"` } func defaultMailNotificationSettings() MailNotificationSettings { return MailNotificationSettings{ DesktopNewMail: true, DesktopMentions: true, EmailDigest: false, SoundEnabled: false, } } func defaultMailSettings() MailSettings { return MailSettings{ Density: "default", ThemeMode: "system", BackgroundID: "none", InboxSort: "default", ReadingPane: "none", ConversationMode: true, Notifications: defaultMailNotificationSettings(), } } func validateEnum(field, value string, allowed map[string]struct{}) *apivalidate.FieldDetail { value = strings.TrimSpace(strings.ToLower(value)) if value == "" { return &apivalidate.FieldDetail{Field: field, Message: "required"} } if _, ok := allowed[value]; !ok { return &apivalidate.FieldDetail{Field: field, Message: "invalid"} } return nil } func validatePatchMailSettings(req *patchMailSettingsRequest) *apivalidate.ValidationError { if req == nil { return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "body", Message: "required"}) } hasField := req.Density != nil || req.ThemeMode != nil || req.BackgroundID != nil || req.InboxSort != nil || req.ReadingPane != nil || req.ConversationMode != nil || req.Notifications != nil if !hasField { return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "body", Message: "at least one field required"}) } var details []apivalidate.FieldDetail if req.Density != nil { if d := validateEnum("density", *req.Density, allowedDensities); d != nil { details = append(details, *d) } } if req.ThemeMode != nil { if d := validateEnum("theme_mode", *req.ThemeMode, allowedThemeModes); d != nil { details = append(details, *d) } } if req.BackgroundID != nil { if d := validateEnum("background_id", *req.BackgroundID, allowedBackgroundIDs); d != nil { details = append(details, *d) } } if req.InboxSort != nil { if d := validateEnum("inbox_sort", *req.InboxSort, allowedInboxSorts); d != nil { details = append(details, *d) } } if req.ReadingPane != nil { if d := validateEnum("reading_pane", *req.ReadingPane, allowedReadingPanes); d != nil { details = append(details, *d) } } if len(details) == 0 { return nil } return apivalidate.NewValidationError(details...) }