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  }