github.com/hahmadia/mattermost-server@v5.11.1+incompatible/model/user.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  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"regexp"
    12  	"strings"
    13  	"unicode/utf8"
    14  
    15  	"github.com/mattermost/mattermost-server/services/timezones"
    16  	"golang.org/x/crypto/bcrypt"
    17  	"golang.org/x/text/language"
    18  )
    19  
    20  const (
    21  	ME                                 = "me"
    22  	USER_NOTIFY_ALL                    = "all"
    23  	USER_NOTIFY_MENTION                = "mention"
    24  	USER_NOTIFY_NONE                   = "none"
    25  	DESKTOP_NOTIFY_PROP                = "desktop"
    26  	DESKTOP_SOUND_NOTIFY_PROP          = "desktop_sound"
    27  	MARK_UNREAD_NOTIFY_PROP            = "mark_unread"
    28  	PUSH_NOTIFY_PROP                   = "push"
    29  	PUSH_STATUS_NOTIFY_PROP            = "push_status"
    30  	EMAIL_NOTIFY_PROP                  = "email"
    31  	CHANNEL_MENTIONS_NOTIFY_PROP       = "channel"
    32  	COMMENTS_NOTIFY_PROP               = "comments"
    33  	MENTION_KEYS_NOTIFY_PROP           = "mention_keys"
    34  	COMMENTS_NOTIFY_NEVER              = "never"
    35  	COMMENTS_NOTIFY_ROOT               = "root"
    36  	COMMENTS_NOTIFY_ANY                = "any"
    37  	FIRST_NAME_NOTIFY_PROP             = "first_name"
    38  	AUTO_RESPONDER_ACTIVE_NOTIFY_PROP  = "auto_responder_active"
    39  	AUTO_RESPONDER_MESSAGE_NOTIFY_PROP = "auto_responder_message"
    40  
    41  	DEFAULT_LOCALE          = "en"
    42  	USER_AUTH_SERVICE_EMAIL = "email"
    43  
    44  	USER_EMAIL_MAX_LENGTH     = 128
    45  	USER_NICKNAME_MAX_RUNES   = 64
    46  	USER_POSITION_MAX_RUNES   = 128
    47  	USER_FIRST_NAME_MAX_RUNES = 64
    48  	USER_LAST_NAME_MAX_RUNES  = 64
    49  	USER_AUTH_DATA_MAX_LENGTH = 128
    50  	USER_NAME_MAX_LENGTH      = 64
    51  	USER_NAME_MIN_LENGTH      = 1
    52  	USER_PASSWORD_MAX_LENGTH  = 72
    53  	USER_LOCALE_MAX_LENGTH    = 5
    54  )
    55  
    56  type User struct {
    57  	Id                     string    `json:"id"`
    58  	CreateAt               int64     `json:"create_at,omitempty"`
    59  	UpdateAt               int64     `json:"update_at,omitempty"`
    60  	DeleteAt               int64     `json:"delete_at"`
    61  	Username               string    `json:"username"`
    62  	Password               string    `json:"password,omitempty"`
    63  	AuthData               *string   `json:"auth_data,omitempty"`
    64  	AuthService            string    `json:"auth_service"`
    65  	Email                  string    `json:"email"`
    66  	EmailVerified          bool      `json:"email_verified,omitempty"`
    67  	Nickname               string    `json:"nickname"`
    68  	FirstName              string    `json:"first_name"`
    69  	LastName               string    `json:"last_name"`
    70  	Position               string    `json:"position"`
    71  	Roles                  string    `json:"roles"`
    72  	AllowMarketing         bool      `json:"allow_marketing,omitempty"`
    73  	Props                  StringMap `json:"props,omitempty"`
    74  	NotifyProps            StringMap `json:"notify_props,omitempty"`
    75  	LastPasswordUpdate     int64     `json:"last_password_update,omitempty"`
    76  	LastPictureUpdate      int64     `json:"last_picture_update,omitempty"`
    77  	FailedAttempts         int       `json:"failed_attempts,omitempty"`
    78  	Locale                 string    `json:"locale"`
    79  	Timezone               StringMap `json:"timezone"`
    80  	MfaActive              bool      `json:"mfa_active,omitempty"`
    81  	MfaSecret              string    `json:"mfa_secret,omitempty"`
    82  	LastActivityAt         int64     `db:"-" json:"last_activity_at,omitempty"`
    83  	IsBot                  bool      `db:"-" json:"is_bot,omitempty"`
    84  	TermsOfServiceId       string    `db:"-" json:"terms_of_service_id,omitempty"`
    85  	TermsOfServiceCreateAt int64     `db:"-" json:"terms_of_service_create_at,omitempty"`
    86  }
    87  
    88  type UserPatch struct {
    89  	Username    *string   `json:"username"`
    90  	Password    *string   `json:"password,omitempty"`
    91  	Nickname    *string   `json:"nickname"`
    92  	FirstName   *string   `json:"first_name"`
    93  	LastName    *string   `json:"last_name"`
    94  	Position    *string   `json:"position"`
    95  	Email       *string   `json:"email"`
    96  	Props       StringMap `json:"props,omitempty"`
    97  	NotifyProps StringMap `json:"notify_props,omitempty"`
    98  	Locale      *string   `json:"locale"`
    99  	Timezone    StringMap `json:"timezone"`
   100  }
   101  
   102  type UserAuth struct {
   103  	Password    string  `json:"password,omitempty"`
   104  	AuthData    *string `json:"auth_data,omitempty"`
   105  	AuthService string  `json:"auth_service,omitempty"`
   106  }
   107  
   108  type UserForIndexing struct {
   109  	Id          string   `json:"id"`
   110  	Username    string   `json:"username"`
   111  	Nickname    string   `json:"nickname"`
   112  	FirstName   string   `json:"first_name"`
   113  	LastName    string   `json:"last_name"`
   114  	CreateAt    int64    `json:"create_at"`
   115  	DeleteAt    int64    `json:"delete_at"`
   116  	TeamsIds    []string `json:"team_id"`
   117  	ChannelsIds []string `json:"channel_id"`
   118  }
   119  
   120  func (u *User) DeepCopy() *User {
   121  	copyUser := *u
   122  	if u.AuthData != nil {
   123  		copyUser.AuthData = NewString(*u.AuthData)
   124  	}
   125  	if u.Props != nil {
   126  		copyUser.Props = CopyStringMap(u.Props)
   127  	}
   128  	if u.NotifyProps != nil {
   129  		copyUser.NotifyProps = CopyStringMap(u.NotifyProps)
   130  	}
   131  	if u.Timezone != nil {
   132  		copyUser.Timezone = CopyStringMap(u.Timezone)
   133  	}
   134  	return &copyUser
   135  }
   136  
   137  // IsValid validates the user and returns an error if it isn't configured
   138  // correctly.
   139  func (u *User) IsValid() *AppError {
   140  
   141  	if len(u.Id) != 26 {
   142  		return InvalidUserError("id", "")
   143  	}
   144  
   145  	if u.CreateAt == 0 {
   146  		return InvalidUserError("create_at", u.Id)
   147  	}
   148  
   149  	if u.UpdateAt == 0 {
   150  		return InvalidUserError("update_at", u.Id)
   151  	}
   152  
   153  	if !IsValidUsername(u.Username) {
   154  		return InvalidUserError("username", u.Id)
   155  	}
   156  
   157  	if len(u.Email) > USER_EMAIL_MAX_LENGTH || len(u.Email) == 0 || !IsValidEmail(u.Email) {
   158  		return InvalidUserError("email", u.Id)
   159  	}
   160  
   161  	if utf8.RuneCountInString(u.Nickname) > USER_NICKNAME_MAX_RUNES {
   162  		return InvalidUserError("nickname", u.Id)
   163  	}
   164  
   165  	if utf8.RuneCountInString(u.Position) > USER_POSITION_MAX_RUNES {
   166  		return InvalidUserError("position", u.Id)
   167  	}
   168  
   169  	if utf8.RuneCountInString(u.FirstName) > USER_FIRST_NAME_MAX_RUNES {
   170  		return InvalidUserError("first_name", u.Id)
   171  	}
   172  
   173  	if utf8.RuneCountInString(u.LastName) > USER_LAST_NAME_MAX_RUNES {
   174  		return InvalidUserError("last_name", u.Id)
   175  	}
   176  
   177  	if u.AuthData != nil && len(*u.AuthData) > USER_AUTH_DATA_MAX_LENGTH {
   178  		return InvalidUserError("auth_data", u.Id)
   179  	}
   180  
   181  	if u.AuthData != nil && len(*u.AuthData) > 0 && len(u.AuthService) == 0 {
   182  		return InvalidUserError("auth_data_type", u.Id)
   183  	}
   184  
   185  	if len(u.Password) > 0 && u.AuthData != nil && len(*u.AuthData) > 0 {
   186  		return InvalidUserError("auth_data_pwd", u.Id)
   187  	}
   188  
   189  	if len(u.Password) > USER_PASSWORD_MAX_LENGTH {
   190  		return InvalidUserError("password_limit", u.Id)
   191  	}
   192  
   193  	if !IsValidLocale(u.Locale) {
   194  		return InvalidUserError("locale", u.Id)
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  func InvalidUserError(fieldName string, userId string) *AppError {
   201  	id := fmt.Sprintf("model.user.is_valid.%s.app_error", fieldName)
   202  	details := ""
   203  	if userId != "" {
   204  		details = "user_id=" + userId
   205  	}
   206  	return NewAppError("User.IsValid", id, nil, details, http.StatusBadRequest)
   207  }
   208  
   209  func NormalizeUsername(username string) string {
   210  	return strings.ToLower(username)
   211  }
   212  
   213  func NormalizeEmail(email string) string {
   214  	return strings.ToLower(email)
   215  }
   216  
   217  // PreSave will set the Id and Username if missing.  It will also fill
   218  // in the CreateAt, UpdateAt times.  It will also hash the password.  It should
   219  // be run before saving the user to the db.
   220  func (u *User) PreSave() {
   221  	if u.Id == "" {
   222  		u.Id = NewId()
   223  	}
   224  
   225  	if u.Username == "" {
   226  		u.Username = NewId()
   227  	}
   228  
   229  	if u.AuthData != nil && *u.AuthData == "" {
   230  		u.AuthData = nil
   231  	}
   232  
   233  	u.Username = NormalizeUsername(u.Username)
   234  	u.Email = NormalizeEmail(u.Email)
   235  
   236  	u.CreateAt = GetMillis()
   237  	u.UpdateAt = u.CreateAt
   238  
   239  	u.LastPasswordUpdate = u.CreateAt
   240  
   241  	u.MfaActive = false
   242  
   243  	if u.Locale == "" {
   244  		u.Locale = DEFAULT_LOCALE
   245  	}
   246  
   247  	if u.Props == nil {
   248  		u.Props = make(map[string]string)
   249  	}
   250  
   251  	if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
   252  		u.SetDefaultNotifications()
   253  	}
   254  
   255  	if u.Timezone == nil {
   256  		u.Timezone = timezones.DefaultUserTimezone()
   257  	}
   258  
   259  	if len(u.Password) > 0 {
   260  		u.Password = HashPassword(u.Password)
   261  	}
   262  }
   263  
   264  // PreUpdate should be run before updating the user in the db.
   265  func (u *User) PreUpdate() {
   266  	u.Username = NormalizeUsername(u.Username)
   267  	u.Email = NormalizeEmail(u.Email)
   268  	u.UpdateAt = GetMillis()
   269  
   270  	if u.AuthData != nil && *u.AuthData == "" {
   271  		u.AuthData = nil
   272  	}
   273  
   274  	if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
   275  		u.SetDefaultNotifications()
   276  	} else if _, ok := u.NotifyProps[MENTION_KEYS_NOTIFY_PROP]; ok {
   277  		// Remove any blank mention keys
   278  		splitKeys := strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",")
   279  		goodKeys := []string{}
   280  		for _, key := range splitKeys {
   281  			if len(key) > 0 {
   282  				goodKeys = append(goodKeys, strings.ToLower(key))
   283  			}
   284  		}
   285  		u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = strings.Join(goodKeys, ",")
   286  	}
   287  }
   288  
   289  func (u *User) SetDefaultNotifications() {
   290  	u.NotifyProps = make(map[string]string)
   291  	u.NotifyProps[EMAIL_NOTIFY_PROP] = "true"
   292  	u.NotifyProps[PUSH_NOTIFY_PROP] = USER_NOTIFY_MENTION
   293  	u.NotifyProps[DESKTOP_NOTIFY_PROP] = USER_NOTIFY_MENTION
   294  	u.NotifyProps[DESKTOP_SOUND_NOTIFY_PROP] = "true"
   295  	u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = u.Username + ",@" + u.Username
   296  	u.NotifyProps[CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
   297  	u.NotifyProps[PUSH_STATUS_NOTIFY_PROP] = STATUS_AWAY
   298  	u.NotifyProps[COMMENTS_NOTIFY_PROP] = COMMENTS_NOTIFY_NEVER
   299  	u.NotifyProps[FIRST_NAME_NOTIFY_PROP] = "false"
   300  }
   301  
   302  func (user *User) UpdateMentionKeysFromUsername(oldUsername string) {
   303  	nonUsernameKeys := []string{}
   304  	splitKeys := strings.Split(user.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",")
   305  	for _, key := range splitKeys {
   306  		if key != oldUsername && key != "@"+oldUsername {
   307  			nonUsernameKeys = append(nonUsernameKeys, key)
   308  		}
   309  	}
   310  
   311  	user.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = user.Username + ",@" + user.Username
   312  	if len(nonUsernameKeys) > 0 {
   313  		user.NotifyProps[MENTION_KEYS_NOTIFY_PROP] += "," + strings.Join(nonUsernameKeys, ",")
   314  	}
   315  }
   316  
   317  func (u *User) Patch(patch *UserPatch) {
   318  	if patch.Username != nil {
   319  		u.Username = *patch.Username
   320  	}
   321  
   322  	if patch.Nickname != nil {
   323  		u.Nickname = *patch.Nickname
   324  	}
   325  
   326  	if patch.FirstName != nil {
   327  		u.FirstName = *patch.FirstName
   328  	}
   329  
   330  	if patch.LastName != nil {
   331  		u.LastName = *patch.LastName
   332  	}
   333  
   334  	if patch.Position != nil {
   335  		u.Position = *patch.Position
   336  	}
   337  
   338  	if patch.Email != nil {
   339  		u.Email = *patch.Email
   340  	}
   341  
   342  	if patch.Props != nil {
   343  		u.Props = patch.Props
   344  	}
   345  
   346  	if patch.NotifyProps != nil {
   347  		u.NotifyProps = patch.NotifyProps
   348  	}
   349  
   350  	if patch.Locale != nil {
   351  		u.Locale = *patch.Locale
   352  	}
   353  
   354  	if patch.Timezone != nil {
   355  		u.Timezone = patch.Timezone
   356  	}
   357  }
   358  
   359  // ToJson convert a User to a json string
   360  func (u *User) ToJson() string {
   361  	b, _ := json.Marshal(u)
   362  	return string(b)
   363  }
   364  
   365  func (u *UserPatch) ToJson() string {
   366  	b, _ := json.Marshal(u)
   367  	return string(b)
   368  }
   369  
   370  func (u *UserAuth) ToJson() string {
   371  	b, _ := json.Marshal(u)
   372  	return string(b)
   373  }
   374  
   375  // Generate a valid strong etag so the browser can cache the results
   376  func (u *User) Etag(showFullName, showEmail bool) string {
   377  	return Etag(u.Id, u.UpdateAt, u.TermsOfServiceId, u.TermsOfServiceCreateAt, showFullName, showEmail)
   378  }
   379  
   380  // Remove any private data from the user object
   381  func (u *User) Sanitize(options map[string]bool) {
   382  	u.Password = ""
   383  	u.AuthData = NewString("")
   384  	u.MfaSecret = ""
   385  
   386  	if len(options) != 0 && !options["email"] {
   387  		u.Email = ""
   388  	}
   389  	if len(options) != 0 && !options["fullname"] {
   390  		u.FirstName = ""
   391  		u.LastName = ""
   392  	}
   393  	if len(options) != 0 && !options["passwordupdate"] {
   394  		u.LastPasswordUpdate = 0
   395  	}
   396  	if len(options) != 0 && !options["authservice"] {
   397  		u.AuthService = ""
   398  	}
   399  }
   400  
   401  func (u *User) ClearNonProfileFields() {
   402  	u.Password = ""
   403  	u.AuthData = NewString("")
   404  	u.MfaSecret = ""
   405  	u.EmailVerified = false
   406  	u.AllowMarketing = false
   407  	u.NotifyProps = StringMap{}
   408  	u.LastPasswordUpdate = 0
   409  	u.FailedAttempts = 0
   410  }
   411  
   412  func (u *User) SanitizeProfile(options map[string]bool) {
   413  	u.ClearNonProfileFields()
   414  
   415  	u.Sanitize(options)
   416  }
   417  
   418  func (u *User) MakeNonNil() {
   419  	if u.Props == nil {
   420  		u.Props = make(map[string]string)
   421  	}
   422  
   423  	if u.NotifyProps == nil {
   424  		u.NotifyProps = make(map[string]string)
   425  	}
   426  }
   427  
   428  func (u *User) AddNotifyProp(key string, value string) {
   429  	u.MakeNonNil()
   430  
   431  	u.NotifyProps[key] = value
   432  }
   433  
   434  func (u *User) GetFullName() string {
   435  	if len(u.FirstName) > 0 && len(u.LastName) > 0 {
   436  		return u.FirstName + " " + u.LastName
   437  	} else if len(u.FirstName) > 0 {
   438  		return u.FirstName
   439  	} else if len(u.LastName) > 0 {
   440  		return u.LastName
   441  	} else {
   442  		return ""
   443  	}
   444  }
   445  
   446  func (u *User) GetDisplayName(nameFormat string) string {
   447  	displayName := u.Username
   448  
   449  	if nameFormat == SHOW_NICKNAME_FULLNAME {
   450  		if len(u.Nickname) > 0 {
   451  			displayName = u.Nickname
   452  		} else if fullName := u.GetFullName(); len(fullName) > 0 {
   453  			displayName = fullName
   454  		}
   455  	} else if nameFormat == SHOW_FULLNAME {
   456  		if fullName := u.GetFullName(); len(fullName) > 0 {
   457  			displayName = fullName
   458  		}
   459  	}
   460  
   461  	return displayName
   462  }
   463  
   464  func (u *User) GetRoles() []string {
   465  	return strings.Fields(u.Roles)
   466  }
   467  
   468  func (u *User) GetRawRoles() string {
   469  	return u.Roles
   470  }
   471  
   472  func IsValidUserRoles(userRoles string) bool {
   473  
   474  	roles := strings.Fields(userRoles)
   475  
   476  	for _, r := range roles {
   477  		if !IsValidRoleName(r) {
   478  			return false
   479  		}
   480  	}
   481  
   482  	// Exclude just the system_admin role explicitly to prevent mistakes
   483  	if len(roles) == 1 && roles[0] == "system_admin" {
   484  		return false
   485  	}
   486  
   487  	return true
   488  }
   489  
   490  // Make sure you acually want to use this function. In context.go there are functions to check permissions
   491  // This function should not be used to check permissions.
   492  func (u *User) IsInRole(inRole string) bool {
   493  	return IsInRole(u.Roles, inRole)
   494  }
   495  
   496  // Make sure you acually want to use this function. In context.go there are functions to check permissions
   497  // This function should not be used to check permissions.
   498  func IsInRole(userRoles string, inRole string) bool {
   499  	roles := strings.Split(userRoles, " ")
   500  
   501  	for _, r := range roles {
   502  		if r == inRole {
   503  			return true
   504  		}
   505  	}
   506  
   507  	return false
   508  }
   509  
   510  func (u *User) IsSSOUser() bool {
   511  	return u.AuthService != "" && u.AuthService != USER_AUTH_SERVICE_EMAIL
   512  }
   513  
   514  func (u *User) IsOAuthUser() bool {
   515  	return u.AuthService == USER_AUTH_SERVICE_GITLAB
   516  }
   517  
   518  func (u *User) IsLDAPUser() bool {
   519  	return u.AuthService == USER_AUTH_SERVICE_LDAP
   520  }
   521  
   522  func (u *User) IsSAMLUser() bool {
   523  	return u.AuthService == USER_AUTH_SERVICE_SAML
   524  }
   525  
   526  func (u *User) GetPreferredTimezone() string {
   527  	return GetPreferredTimezone(u.Timezone)
   528  }
   529  
   530  // UserFromJson will decode the input and return a User
   531  func UserFromJson(data io.Reader) *User {
   532  	var user *User
   533  	json.NewDecoder(data).Decode(&user)
   534  	return user
   535  }
   536  
   537  func UserPatchFromJson(data io.Reader) *UserPatch {
   538  	var user *UserPatch
   539  	json.NewDecoder(data).Decode(&user)
   540  	return user
   541  }
   542  
   543  func UserAuthFromJson(data io.Reader) *UserAuth {
   544  	var user *UserAuth
   545  	json.NewDecoder(data).Decode(&user)
   546  	return user
   547  }
   548  
   549  func UserMapToJson(u map[string]*User) string {
   550  	b, _ := json.Marshal(u)
   551  	return string(b)
   552  }
   553  
   554  func UserMapFromJson(data io.Reader) map[string]*User {
   555  	var users map[string]*User
   556  	json.NewDecoder(data).Decode(&users)
   557  	return users
   558  }
   559  
   560  func UserListToJson(u []*User) string {
   561  	b, _ := json.Marshal(u)
   562  	return string(b)
   563  }
   564  
   565  func UserListFromJson(data io.Reader) []*User {
   566  	var users []*User
   567  	json.NewDecoder(data).Decode(&users)
   568  	return users
   569  }
   570  
   571  // HashPassword generates a hash using the bcrypt.GenerateFromPassword
   572  func HashPassword(password string) string {
   573  	hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
   574  	if err != nil {
   575  		panic(err)
   576  	}
   577  
   578  	return string(hash)
   579  }
   580  
   581  // ComparePassword compares the hash
   582  func ComparePassword(hash string, password string) bool {
   583  
   584  	if len(password) == 0 || len(hash) == 0 {
   585  		return false
   586  	}
   587  
   588  	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
   589  	return err == nil
   590  }
   591  
   592  var validUsernameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`)
   593  
   594  var restrictedUsernames = []string{
   595  	"all",
   596  	"channel",
   597  	"matterbot",
   598  	"system",
   599  }
   600  
   601  func IsValidUsername(s string) bool {
   602  	if len(s) < USER_NAME_MIN_LENGTH || len(s) > USER_NAME_MAX_LENGTH {
   603  		return false
   604  	}
   605  
   606  	if !validUsernameChars.MatchString(s) {
   607  		return false
   608  	}
   609  
   610  	for _, restrictedUsername := range restrictedUsernames {
   611  		if s == restrictedUsername {
   612  			return false
   613  		}
   614  	}
   615  
   616  	return true
   617  }
   618  
   619  func CleanUsername(s string) string {
   620  	s = NormalizeUsername(strings.Replace(s, " ", "-", -1))
   621  
   622  	for _, value := range reservedName {
   623  		if s == value {
   624  			s = strings.Replace(s, value, "", -1)
   625  		}
   626  	}
   627  
   628  	s = strings.TrimSpace(s)
   629  
   630  	for _, c := range s {
   631  		char := fmt.Sprintf("%c", c)
   632  		if !validUsernameChars.MatchString(char) {
   633  			s = strings.Replace(s, char, "-", -1)
   634  		}
   635  	}
   636  
   637  	s = strings.Trim(s, "-")
   638  
   639  	if !IsValidUsername(s) {
   640  		s = "a" + NewId()
   641  	}
   642  
   643  	return s
   644  }
   645  
   646  func IsValidUserNotifyLevel(notifyLevel string) bool {
   647  	return notifyLevel == CHANNEL_NOTIFY_ALL ||
   648  		notifyLevel == CHANNEL_NOTIFY_MENTION ||
   649  		notifyLevel == CHANNEL_NOTIFY_NONE
   650  }
   651  
   652  func IsValidPushStatusNotifyLevel(notifyLevel string) bool {
   653  	return notifyLevel == STATUS_ONLINE ||
   654  		notifyLevel == STATUS_AWAY ||
   655  		notifyLevel == STATUS_OFFLINE
   656  }
   657  
   658  func IsValidCommentsNotifyLevel(notifyLevel string) bool {
   659  	return notifyLevel == COMMENTS_NOTIFY_ANY ||
   660  		notifyLevel == COMMENTS_NOTIFY_ROOT ||
   661  		notifyLevel == COMMENTS_NOTIFY_NEVER
   662  }
   663  
   664  func IsValidEmailBatchingInterval(emailInterval string) bool {
   665  	return emailInterval == PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY ||
   666  		emailInterval == PREFERENCE_EMAIL_INTERVAL_FIFTEEN ||
   667  		emailInterval == PREFERENCE_EMAIL_INTERVAL_HOUR
   668  }
   669  
   670  func IsValidLocale(locale string) bool {
   671  	if locale != "" {
   672  		if len(locale) > USER_LOCALE_MAX_LENGTH {
   673  			return false
   674  		} else if _, err := language.Parse(locale); err != nil {
   675  			return false
   676  		}
   677  	}
   678  
   679  	return true
   680  }