github.com/turgay/mattermost-server@v5.3.2-0.20181002173352-2945e8a2b0ce+incompatible/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_TUTORIAL_STEPS = "tutorial_step" 18 PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings" 19 PREFERENCE_CATEGORY_FLAGGED_POST = "flagged_post" 20 PREFERENCE_CATEGORY_FAVORITE_CHANNEL = "favorite_channel" 21 PREFERENCE_CATEGORY_SIDEBAR_SETTINGS = "sidebar_settings" 22 23 PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings" 24 PREFERENCE_NAME_CHANNEL_DISPLAY_MODE = "channel_display_mode" 25 PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews" 26 PREFERENCE_NAME_MESSAGE_DISPLAY = "message_display" 27 PREFERENCE_NAME_NAME_FORMAT = "name_format" 28 PREFERENCE_NAME_USE_MILITARY_TIME = "use_military_time" 29 30 PREFERENCE_CATEGORY_THEME = "theme" 31 // the name for theme props is the team id 32 33 PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP = "oauth_app" 34 // the name for oauth_app is the client_id and value is the current scope 35 36 PREFERENCE_CATEGORY_LAST = "last" 37 PREFERENCE_NAME_LAST_CHANNEL = "channel" 38 PREFERENCE_NAME_LAST_TEAM = "team" 39 40 PREFERENCE_CATEGORY_NOTIFICATIONS = "notifications" 41 PREFERENCE_NAME_EMAIL_INTERVAL = "email_interval" 42 43 PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS = "30" // the "immediate" setting is actually 30s 44 PREFERENCE_EMAIL_INTERVAL_BATCHING_SECONDS = "900" // fifteen minutes is 900 seconds 45 ) 46 47 type Preference struct { 48 UserId string `json:"user_id"` 49 Category string `json:"category"` 50 Name string `json:"name"` 51 Value string `json:"value"` 52 } 53 54 func (o *Preference) ToJson() string { 55 b, _ := json.Marshal(o) 56 return string(b) 57 } 58 59 func PreferenceFromJson(data io.Reader) *Preference { 60 var o *Preference 61 json.NewDecoder(data).Decode(&o) 62 return o 63 } 64 65 func (o *Preference) IsValid() *AppError { 66 if len(o.UserId) != 26 { 67 return NewAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest) 68 } 69 70 if len(o.Category) == 0 || len(o.Category) > 32 { 71 return NewAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category, http.StatusBadRequest) 72 } 73 74 if len(o.Name) > 32 { 75 return NewAppError("Preference.IsValid", "model.preference.is_valid.name.app_error", nil, "name="+o.Name, http.StatusBadRequest) 76 } 77 78 if utf8.RuneCountInString(o.Value) > 2000 { 79 return NewAppError("Preference.IsValid", "model.preference.is_valid.value.app_error", nil, "value="+o.Value, http.StatusBadRequest) 80 } 81 82 if o.Category == PREFERENCE_CATEGORY_THEME { 83 var unused map[string]string 84 if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&unused); err != nil { 85 return NewAppError("Preference.IsValid", "model.preference.is_valid.theme.app_error", nil, "value="+o.Value, http.StatusBadRequest) 86 } 87 } 88 89 return nil 90 } 91 92 func (o *Preference) PreUpdate() { 93 if o.Category == PREFERENCE_CATEGORY_THEME { 94 // decode the value of theme (a map of strings to string) and eliminate any invalid values 95 var props map[string]string 96 if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&props); err != nil { 97 // just continue, the invalid preference value should get caught by IsValid before saving 98 return 99 } 100 101 colorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$`) 102 103 // blank out any invalid theme values 104 for name, value := range props { 105 if name == "image" || name == "type" || name == "codeTheme" { 106 continue 107 } 108 109 if !colorPattern.MatchString(value) { 110 props[name] = "#ffffff" 111 } 112 } 113 114 if b, err := json.Marshal(props); err == nil { 115 o.Value = string(b) 116 } 117 } 118 }