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