github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/model/preference.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package model 5 6 import ( 7 "encoding/json" 8 "io" 9 "net/http" 10 "regexp" 11 "strings" 12 "unicode/utf8" 13 ) 14 15 const ( 16 PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show" 17 PREFERENCE_CATEGORY_GROUP_CHANNEL_SHOW = "group_channel_show" 18 PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step" 19 PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings" 20 PREFERENCE_CATEGORY_FLAGGED_POST = "flagged_post" 21 PREFERENCE_CATEGORY_FAVORITE_CHANNEL = "favorite_channel" 22 PREFERENCE_CATEGORY_SIDEBAR_SETTINGS = "sidebar_settings" 23 24 PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings" 25 PREFERENCE_NAME_CHANNEL_DISPLAY_MODE = "channel_display_mode" 26 PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews" 27 PREFERENCE_NAME_MESSAGE_DISPLAY = "message_display" 28 PREFERENCE_NAME_NAME_FORMAT = "name_format" 29 PREFERENCE_NAME_USE_MILITARY_TIME = "use_military_time" 30 31 PREFERENCE_CATEGORY_THEME = "theme" 32 // the name for theme props is the team id 33 34 PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP = "oauth_app" 35 // the name for oauth_app is the client_id and value is the current scope 36 37 PREFERENCE_CATEGORY_LAST = "last" 38 PREFERENCE_NAME_LAST_CHANNEL = "channel" 39 PREFERENCE_NAME_LAST_TEAM = "team" 40 41 PREFERENCE_CATEGORY_NOTIFICATIONS = "notifications" 42 PREFERENCE_NAME_EMAIL_INTERVAL = "email_interval" 43 44 PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS = "30" // the "immediate" setting is actually 30s 45 PREFERENCE_EMAIL_INTERVAL_BATCHING_SECONDS = "900" // fifteen minutes is 900 seconds 46 PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY = "immediately" 47 PREFERENCE_EMAIL_INTERVAL_FIFTEEN = "fifteen" 48 PREFERENCE_EMAIL_INTERVAL_FIFTEEN_AS_SECONDS = "900" 49 PREFERENCE_EMAIL_INTERVAL_HOUR = "hour" 50 PREFERENCE_EMAIL_INTERVAL_HOUR_AS_SECONDS = "3600" 51 ) 52 53 type Preference struct { 54 UserId string `json:"user_id"` 55 Category string `json:"category"` 56 Name string `json:"name"` 57 Value string `json:"value"` 58 } 59 60 func (o *Preference) ToJson() string { 61 b, _ := json.Marshal(o) 62 return string(b) 63 } 64 65 func PreferenceFromJson(data io.Reader) *Preference { 66 var o *Preference 67 json.NewDecoder(data).Decode(&o) 68 return o 69 } 70 71 func (o *Preference) IsValid() *AppError { 72 if !IsValidId(o.UserId) { 73 return NewAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest) 74 } 75 76 if len(o.Category) == 0 || len(o.Category) > 32 { 77 return NewAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category, http.StatusBadRequest) 78 } 79 80 if len(o.Name) > 32 { 81 return NewAppError("Preference.IsValid", "model.preference.is_valid.name.app_error", nil, "name="+o.Name, http.StatusBadRequest) 82 } 83 84 if utf8.RuneCountInString(o.Value) > 2000 { 85 return NewAppError("Preference.IsValid", "model.preference.is_valid.value.app_error", nil, "value="+o.Value, http.StatusBadRequest) 86 } 87 88 if o.Category == PREFERENCE_CATEGORY_THEME { 89 var unused map[string]string 90 if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&unused); err != nil { 91 return NewAppError("Preference.IsValid", "model.preference.is_valid.theme.app_error", nil, "value="+o.Value, http.StatusBadRequest) 92 } 93 } 94 95 return nil 96 } 97 98 func (o *Preference) PreUpdate() { 99 if o.Category == PREFERENCE_CATEGORY_THEME { 100 // decode the value of theme (a map of strings to string) and eliminate any invalid values 101 var props map[string]string 102 if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&props); err != nil { 103 // just continue, the invalid preference value should get caught by IsValid before saving 104 return 105 } 106 107 colorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$`) 108 109 // blank out any invalid theme values 110 for name, value := range props { 111 if name == "image" || name == "type" || name == "codeTheme" { 112 continue 113 } 114 115 if !colorPattern.MatchString(value) { 116 props[name] = "#ffffff" 117 } 118 } 119 120 if b, err := json.Marshal(props); err == nil { 121 o.Value = string(b) 122 } 123 } 124 }