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  }