80 lines
2.0 KiB
Go
80 lines
2.0 KiB
Go
package domain
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"time"
|
|
)
|
|
|
|
// Allowed preference keys.
|
|
var allowedKeys = map[string]bool{
|
|
"theme": true,
|
|
"language": true,
|
|
"notifications_enabled": true,
|
|
}
|
|
|
|
// Valid theme values.
|
|
var validThemes = map[string]bool{
|
|
"light": true,
|
|
"dark": true,
|
|
}
|
|
|
|
// languagePattern matches ISO 639-1 codes (two lowercase letters).
|
|
var languagePattern = regexp.MustCompile(`^[a-z]{2}$`)
|
|
|
|
// UserPreferences represents a user's stored preferences.
|
|
type UserPreferences struct {
|
|
UserID string
|
|
Preferences map[string]any
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// ValidatePreferences validates all keys and values in a preferences map.
|
|
func ValidatePreferences(prefs map[string]any) error {
|
|
for key, value := range prefs {
|
|
if err := ValidatePreferenceKey(key); err != nil {
|
|
return err
|
|
}
|
|
if err := ValidatePreferenceValue(key, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidatePreferenceKey checks that the key is in the allowed set.
|
|
func ValidatePreferenceKey(key string) error {
|
|
if !allowedKeys[key] {
|
|
return fmt.Errorf("%w: %s", ErrInvalidPreferenceKey, key)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidatePreferenceValue checks that the value is valid for the given key.
|
|
func ValidatePreferenceValue(key string, value any) error {
|
|
switch key {
|
|
case "theme":
|
|
s, ok := value.(string)
|
|
if !ok {
|
|
return fmt.Errorf("%w: theme must be a string", ErrInvalidPreferenceValue)
|
|
}
|
|
if !validThemes[s] {
|
|
return fmt.Errorf("%w: theme must be \"light\" or \"dark\", got %q", ErrInvalidPreferenceValue, s)
|
|
}
|
|
case "language":
|
|
s, ok := value.(string)
|
|
if !ok {
|
|
return fmt.Errorf("%w: language must be a string", ErrInvalidPreferenceValue)
|
|
}
|
|
if !languagePattern.MatchString(s) {
|
|
return fmt.Errorf("%w: language must be a valid ISO 639-1 code (e.g. \"en\"), got %q", ErrInvalidPreferenceValue, s)
|
|
}
|
|
case "notifications_enabled":
|
|
if _, ok := value.(bool); !ok {
|
|
return fmt.Errorf("%w: notifications_enabled must be a boolean", ErrInvalidPreferenceValue)
|
|
}
|
|
}
|
|
return nil
|
|
}
|