ultisuite-backend/internal/api/mail/validate_settings.go
2026-05-24 00:03:36 +02:00

160 lines
4.6 KiB
Go

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...)
}