github.com/jfrerich/mattermost-server@v5.8.0-rc2+incompatible/store/sqlstore/user_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"database/sql"
     8  	"fmt"
     9  	"net/http"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/mattermost/gorp"
    14  
    15  	"github.com/mattermost/mattermost-server/einterfaces"
    16  	"github.com/mattermost/mattermost-server/model"
    17  	"github.com/mattermost/mattermost-server/store"
    18  	"github.com/mattermost/mattermost-server/utils"
    19  )
    20  
    21  const (
    22  	PROFILES_IN_CHANNEL_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
    23  	PROFILES_IN_CHANNEL_CACHE_SEC  = 900 // 15 mins
    24  	PROFILE_BY_IDS_CACHE_SIZE      = model.SESSION_CACHE_SIZE
    25  	PROFILE_BY_IDS_CACHE_SEC       = 900 // 15 mins
    26  )
    27  
    28  var (
    29  	USER_SEARCH_TYPE_NAMES_NO_FULL_NAME = []string{"Username", "Nickname"}
    30  	USER_SEARCH_TYPE_NAMES              = []string{"Username", "FirstName", "LastName", "Nickname"}
    31  	USER_SEARCH_TYPE_ALL_NO_FULL_NAME   = []string{"Username", "Nickname", "Email"}
    32  	USER_SEARCH_TYPE_ALL                = []string{"Username", "FirstName", "LastName", "Nickname", "Email"}
    33  )
    34  
    35  type SqlUserStore struct {
    36  	SqlStore
    37  	metrics einterfaces.MetricsInterface
    38  }
    39  
    40  var profilesInChannelCache *utils.Cache = utils.NewLru(PROFILES_IN_CHANNEL_CACHE_SIZE)
    41  var profileByIdsCache *utils.Cache = utils.NewLru(PROFILE_BY_IDS_CACHE_SIZE)
    42  
    43  func (us SqlUserStore) ClearCaches() {
    44  	profilesInChannelCache.Purge()
    45  	profileByIdsCache.Purge()
    46  
    47  	if us.metrics != nil {
    48  		us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Purge")
    49  		us.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Purge")
    50  	}
    51  }
    52  
    53  func (us SqlUserStore) InvalidatProfileCacheForUser(userId string) {
    54  	profileByIdsCache.Remove(userId)
    55  
    56  	if us.metrics != nil {
    57  		us.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Remove")
    58  	}
    59  }
    60  
    61  func NewSqlUserStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.UserStore {
    62  	us := &SqlUserStore{
    63  		SqlStore: sqlStore,
    64  		metrics:  metrics,
    65  	}
    66  
    67  	for _, db := range sqlStore.GetAllConns() {
    68  		table := db.AddTableWithName(model.User{}, "Users").SetKeys(false, "Id")
    69  		table.ColMap("Id").SetMaxSize(26)
    70  		table.ColMap("Username").SetMaxSize(64).SetUnique(true)
    71  		table.ColMap("Password").SetMaxSize(128)
    72  		table.ColMap("AuthData").SetMaxSize(128).SetUnique(true)
    73  		table.ColMap("AuthService").SetMaxSize(32)
    74  		table.ColMap("Email").SetMaxSize(128).SetUnique(true)
    75  		table.ColMap("Nickname").SetMaxSize(64)
    76  		table.ColMap("FirstName").SetMaxSize(64)
    77  		table.ColMap("LastName").SetMaxSize(64)
    78  		table.ColMap("Roles").SetMaxSize(256)
    79  		table.ColMap("Props").SetMaxSize(4000)
    80  		table.ColMap("NotifyProps").SetMaxSize(2000)
    81  		table.ColMap("Locale").SetMaxSize(5)
    82  		table.ColMap("MfaSecret").SetMaxSize(128)
    83  		table.ColMap("Position").SetMaxSize(128)
    84  		table.ColMap("Timezone").SetMaxSize(256)
    85  	}
    86  
    87  	return us
    88  }
    89  
    90  func (us SqlUserStore) CreateIndexesIfNotExists() {
    91  	us.CreateIndexIfNotExists("idx_users_email", "Users", "Email")
    92  	us.CreateIndexIfNotExists("idx_users_update_at", "Users", "UpdateAt")
    93  	us.CreateIndexIfNotExists("idx_users_create_at", "Users", "CreateAt")
    94  	us.CreateIndexIfNotExists("idx_users_delete_at", "Users", "DeleteAt")
    95  
    96  	if us.DriverName() == model.DATABASE_DRIVER_POSTGRES {
    97  		us.CreateIndexIfNotExists("idx_users_email_lower_textpattern", "Users", "lower(Email) text_pattern_ops")
    98  		us.CreateIndexIfNotExists("idx_users_username_lower_textpattern", "Users", "lower(Username) text_pattern_ops")
    99  		us.CreateIndexIfNotExists("idx_users_nickname_lower_textpattern", "Users", "lower(Nickname) text_pattern_ops")
   100  		us.CreateIndexIfNotExists("idx_users_firstname_lower_textpattern", "Users", "lower(FirstName) text_pattern_ops")
   101  		us.CreateIndexIfNotExists("idx_users_lastname_lower_textpattern", "Users", "lower(LastName) text_pattern_ops")
   102  	}
   103  
   104  	us.CreateFullTextIndexIfNotExists("idx_users_all_txt", "Users", strings.Join(USER_SEARCH_TYPE_ALL, ", "))
   105  	us.CreateFullTextIndexIfNotExists("idx_users_all_no_full_name_txt", "Users", strings.Join(USER_SEARCH_TYPE_ALL_NO_FULL_NAME, ", "))
   106  	us.CreateFullTextIndexIfNotExists("idx_users_names_txt", "Users", strings.Join(USER_SEARCH_TYPE_NAMES, ", "))
   107  	us.CreateFullTextIndexIfNotExists("idx_users_names_no_full_name_txt", "Users", strings.Join(USER_SEARCH_TYPE_NAMES_NO_FULL_NAME, ", "))
   108  }
   109  
   110  func (us SqlUserStore) Save(user *model.User) store.StoreChannel {
   111  	return store.Do(func(result *store.StoreResult) {
   112  		if len(user.Id) > 0 {
   113  			result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.existing.app_error", nil, "user_id="+user.Id, http.StatusBadRequest)
   114  			return
   115  		}
   116  
   117  		user.PreSave()
   118  		if result.Err = user.IsValid(); result.Err != nil {
   119  			return
   120  		}
   121  
   122  		if err := us.GetMaster().Insert(user); err != nil {
   123  			if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) {
   124  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.email_exists.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest)
   125  			} else if IsUniqueConstraintError(err, []string{"Username", "users_username_key", "idx_users_username_unique"}) {
   126  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.username_exists.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest)
   127  			} else {
   128  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusInternalServerError)
   129  			}
   130  		} else {
   131  			result.Data = user
   132  		}
   133  	})
   134  }
   135  
   136  func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) store.StoreChannel {
   137  	return store.Do(func(result *store.StoreResult) {
   138  		user.PreUpdate()
   139  
   140  		if result.Err = user.IsValid(); result.Err != nil {
   141  			return
   142  		}
   143  
   144  		if oldUserResult, err := us.GetMaster().Get(model.User{}, user.Id); err != nil {
   145  			result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.finding.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusInternalServerError)
   146  		} else if oldUserResult == nil {
   147  			result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.find.app_error", nil, "user_id="+user.Id, http.StatusBadRequest)
   148  		} else {
   149  			oldUser := oldUserResult.(*model.User)
   150  			user.CreateAt = oldUser.CreateAt
   151  			user.AuthData = oldUser.AuthData
   152  			user.AuthService = oldUser.AuthService
   153  			user.Password = oldUser.Password
   154  			user.LastPasswordUpdate = oldUser.LastPasswordUpdate
   155  			user.LastPictureUpdate = oldUser.LastPictureUpdate
   156  			user.EmailVerified = oldUser.EmailVerified
   157  			user.FailedAttempts = oldUser.FailedAttempts
   158  			user.MfaSecret = oldUser.MfaSecret
   159  			user.MfaActive = oldUser.MfaActive
   160  
   161  			if !trustedUpdateData {
   162  				user.Roles = oldUser.Roles
   163  				user.DeleteAt = oldUser.DeleteAt
   164  			}
   165  
   166  			if user.IsOAuthUser() {
   167  				if !trustedUpdateData {
   168  					user.Email = oldUser.Email
   169  				}
   170  			} else if user.IsLDAPUser() && !trustedUpdateData {
   171  				if user.Username != oldUser.Username ||
   172  					user.Email != oldUser.Email {
   173  					result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.can_not_change_ldap.app_error", nil, "user_id="+user.Id, http.StatusBadRequest)
   174  					return
   175  				}
   176  			} else if user.Email != oldUser.Email {
   177  				user.EmailVerified = false
   178  			}
   179  
   180  			if user.Username != oldUser.Username {
   181  				user.UpdateMentionKeysFromUsername(oldUser.Username)
   182  			}
   183  
   184  			if count, err := us.GetMaster().Update(user); err != nil {
   185  				if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) {
   186  					result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.email_taken.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest)
   187  				} else if IsUniqueConstraintError(err, []string{"Username", "users_username_key", "idx_users_username_unique"}) {
   188  					result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.username_taken.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest)
   189  				} else {
   190  					result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.updating.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusInternalServerError)
   191  				}
   192  			} else if count != 1 {
   193  				result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.app_error", nil, fmt.Sprintf("user_id=%v, count=%v", user.Id, count), http.StatusInternalServerError)
   194  			} else {
   195  				user.Sanitize(map[string]bool{})
   196  				oldUser.Sanitize(map[string]bool{})
   197  				result.Data = [2]*model.User{user, oldUser}
   198  			}
   199  		}
   200  	})
   201  }
   202  
   203  func (us SqlUserStore) UpdateLastPictureUpdate(userId string) store.StoreChannel {
   204  	return store.Do(func(result *store.StoreResult) {
   205  		curTime := model.GetMillis()
   206  
   207  		if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil {
   208  			result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_last_picture_update.app_error", nil, "user_id="+userId, http.StatusInternalServerError)
   209  		} else {
   210  			result.Data = userId
   211  		}
   212  	})
   213  }
   214  
   215  func (us SqlUserStore) ResetLastPictureUpdate(userId string) store.StoreChannel {
   216  	return store.Do(func(result *store.StoreResult) {
   217  		if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": 0, "UserId": userId}); err != nil {
   218  			result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_last_picture_update.app_error", nil, "user_id="+userId, http.StatusInternalServerError)
   219  		} else {
   220  			result.Data = userId
   221  		}
   222  	})
   223  }
   224  
   225  func (us SqlUserStore) UpdateUpdateAt(userId string) store.StoreChannel {
   226  	return store.Do(func(result *store.StoreResult) {
   227  		curTime := model.GetMillis()
   228  
   229  		if _, err := us.GetMaster().Exec("UPDATE Users SET UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil {
   230  			result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_update.app_error", nil, "user_id="+userId, http.StatusInternalServerError)
   231  		} else {
   232  			result.Data = userId
   233  		}
   234  	})
   235  }
   236  
   237  func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) store.StoreChannel {
   238  	return store.Do(func(result *store.StoreResult) {
   239  		updateAt := model.GetMillis()
   240  
   241  		if _, err := us.GetMaster().Exec("UPDATE Users SET Password = :Password, LastPasswordUpdate = :LastPasswordUpdate, UpdateAt = :UpdateAt, AuthData = NULL, AuthService = '', EmailVerified = true, FailedAttempts = 0 WHERE Id = :UserId", map[string]interface{}{"Password": hashedPassword, "LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId}); err != nil {
   242  			result.Err = model.NewAppError("SqlUserStore.UpdatePassword", "store.sql_user.update_password.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   243  		} else {
   244  			result.Data = userId
   245  		}
   246  	})
   247  }
   248  
   249  func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int) store.StoreChannel {
   250  	return store.Do(func(result *store.StoreResult) {
   251  		if _, err := us.GetMaster().Exec("UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId", map[string]interface{}{"FailedAttempts": attempts, "UserId": userId}); err != nil {
   252  			result.Err = model.NewAppError("SqlUserStore.UpdateFailedPasswordAttempts", "store.sql_user.update_failed_pwd_attempts.app_error", nil, "user_id="+userId, http.StatusInternalServerError)
   253  		} else {
   254  			result.Data = userId
   255  		}
   256  	})
   257  }
   258  
   259  func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *string, email string, resetMfa bool) store.StoreChannel {
   260  	return store.Do(func(result *store.StoreResult) {
   261  		email = strings.ToLower(email)
   262  
   263  		updateAt := model.GetMillis()
   264  
   265  		query := `
   266  			UPDATE
   267  			     Users
   268  			SET
   269  			     Password = '',
   270  			     LastPasswordUpdate = :LastPasswordUpdate,
   271  			     UpdateAt = :UpdateAt,
   272  			     FailedAttempts = 0,
   273  			     AuthService = :AuthService,
   274  			     AuthData = :AuthData`
   275  
   276  		if len(email) != 0 {
   277  			query += ", Email = :Email"
   278  		}
   279  
   280  		if resetMfa {
   281  			query += ", MfaActive = false, MfaSecret = ''"
   282  		}
   283  
   284  		query += " WHERE Id = :UserId"
   285  
   286  		if _, err := us.GetMaster().Exec(query, map[string]interface{}{"LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId, "AuthService": service, "AuthData": authData, "Email": email}); err != nil {
   287  			if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique", "AuthData", "users_authdata_key"}) {
   288  				result.Err = model.NewAppError("SqlUserStore.UpdateAuthData", "store.sql_user.update_auth_data.email_exists.app_error", map[string]interface{}{"Service": service, "Email": email}, "user_id="+userId+", "+err.Error(), http.StatusBadRequest)
   289  			} else {
   290  				result.Err = model.NewAppError("SqlUserStore.UpdateAuthData", "store.sql_user.update_auth_data.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   291  			}
   292  		} else {
   293  			result.Data = userId
   294  		}
   295  	})
   296  }
   297  
   298  func (us SqlUserStore) UpdateMfaSecret(userId, secret string) store.StoreChannel {
   299  	return store.Do(func(result *store.StoreResult) {
   300  		updateAt := model.GetMillis()
   301  
   302  		if _, err := us.GetMaster().Exec("UPDATE Users SET MfaSecret = :Secret, UpdateAt = :UpdateAt WHERE Id = :UserId", map[string]interface{}{"Secret": secret, "UpdateAt": updateAt, "UserId": userId}); err != nil {
   303  			result.Err = model.NewAppError("SqlUserStore.UpdateMfaSecret", "store.sql_user.update_mfa_secret.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   304  		} else {
   305  			result.Data = userId
   306  		}
   307  	})
   308  }
   309  
   310  func (us SqlUserStore) UpdateMfaActive(userId string, active bool) store.StoreChannel {
   311  	return store.Do(func(result *store.StoreResult) {
   312  		updateAt := model.GetMillis()
   313  
   314  		if _, err := us.GetMaster().Exec("UPDATE Users SET MfaActive = :Active, UpdateAt = :UpdateAt WHERE Id = :UserId", map[string]interface{}{"Active": active, "UpdateAt": updateAt, "UserId": userId}); err != nil {
   315  			result.Err = model.NewAppError("SqlUserStore.UpdateMfaActive", "store.sql_user.update_mfa_active.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   316  		} else {
   317  			result.Data = userId
   318  		}
   319  	})
   320  }
   321  
   322  func (us SqlUserStore) Get(id string) store.StoreChannel {
   323  	return store.Do(func(result *store.StoreResult) {
   324  		if obj, err := us.GetReplica().Get(model.User{}, id); err != nil {
   325  			result.Err = model.NewAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, "user_id="+id+", "+err.Error(), http.StatusInternalServerError)
   326  		} else if obj == nil {
   327  			result.Err = model.NewAppError("SqlUserStore.Get", store.MISSING_ACCOUNT_ERROR, nil, "user_id="+id, http.StatusNotFound)
   328  		} else {
   329  			result.Data = obj.(*model.User)
   330  		}
   331  	})
   332  }
   333  
   334  func (us SqlUserStore) GetAll() store.StoreChannel {
   335  	return store.Do(func(result *store.StoreResult) {
   336  		var data []*model.User
   337  		if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users"); err != nil {
   338  			result.Err = model.NewAppError("SqlUserStore.GetAll", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
   339  		}
   340  
   341  		result.Data = data
   342  	})
   343  }
   344  
   345  func (us SqlUserStore) GetAllAfter(limit int, afterId string) store.StoreChannel {
   346  	return store.Do(func(result *store.StoreResult) {
   347  		var data []*model.User
   348  		if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE Id > :AfterId ORDER BY Id LIMIT :Limit", map[string]interface{}{"AfterId": afterId, "Limit": limit}); err != nil {
   349  			result.Err = model.NewAppError("SqlUserStore.GetAllAfter", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
   350  		}
   351  
   352  		result.Data = data
   353  	})
   354  }
   355  
   356  func (s SqlUserStore) GetEtagForAllProfiles() store.StoreChannel {
   357  	return store.Do(func(result *store.StoreResult) {
   358  		updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1")
   359  		if err != nil {
   360  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
   361  		} else {
   362  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
   363  		}
   364  	})
   365  }
   366  
   367  func (us SqlUserStore) GetAllProfiles(options *model.UserGetOptions) store.StoreChannel {
   368  	isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES
   369  	return store.Do(func(result *store.StoreResult) {
   370  		var users []*model.User
   371  		offset := options.Page * options.PerPage
   372  		limit := options.PerPage
   373  
   374  		searchQuery := `
   375  			SELECT * FROM Users
   376  			WHERE_CONDITION
   377  			ORDER BY Username ASC LIMIT :Limit OFFSET :Offset
   378  		`
   379  
   380  		parameters := map[string]interface{}{"Offset": offset, "Limit": limit}
   381  		searchQuery = substituteWhereClause(searchQuery, options, parameters, isPostgreSQL)
   382  
   383  		if _, err := us.GetReplica().Select(&users, searchQuery, parameters); err != nil {
   384  			result.Err = model.NewAppError("SqlUserStore.GetAllProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   385  		} else {
   386  
   387  			for _, u := range users {
   388  				u.Sanitize(map[string]bool{})
   389  			}
   390  
   391  			result.Data = users
   392  		}
   393  	})
   394  }
   395  
   396  func substituteWhereClause(searchQuery string, options *model.UserGetOptions, parameters map[string]interface{}, isPostgreSQL bool) string {
   397  	whereClause := ""
   398  	whereClauses := []string{}
   399  	if options.Role != "" {
   400  		whereClauses = append(whereClauses, getRoleFilter(isPostgreSQL))
   401  		parameters["Role"] = fmt.Sprintf("%%%s%%", options.Role)
   402  	}
   403  	if options.Inactive {
   404  		whereClauses = append(whereClauses, " Users.DeleteAt != 0 ")
   405  	}
   406  
   407  	if len(whereClauses) > 0 {
   408  		whereClause = strings.Join(whereClauses, " AND ")
   409  		searchQuery = strings.Replace(searchQuery, "WHERE_CONDITION", fmt.Sprintf(" WHERE %s ", whereClause), 1)
   410  		searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", fmt.Sprintf(" AND %s ", whereClause), 1)
   411  	} else {
   412  		searchQuery = strings.Replace(searchQuery, "WHERE_CONDITION", "", 1)
   413  		searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1)
   414  	}
   415  
   416  	return searchQuery
   417  }
   418  
   419  func getRoleFilter(isPostgreSQL bool) string {
   420  	if isPostgreSQL {
   421  		return fmt.Sprintf("Users.Roles like lower(%s)", ":Role")
   422  	} else {
   423  		return fmt.Sprintf("Users.Roles LIKE %s escape '*' ", ":Role")
   424  	}
   425  }
   426  
   427  func (s SqlUserStore) GetEtagForProfiles(teamId string) store.StoreChannel {
   428  	return store.Do(func(result *store.StoreResult) {
   429  		updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId})
   430  		if err != nil {
   431  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
   432  		} else {
   433  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
   434  		}
   435  	})
   436  }
   437  
   438  func (us SqlUserStore) GetProfiles(options *model.UserGetOptions) store.StoreChannel {
   439  	isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES
   440  	teamId := options.InTeamId
   441  	offset := options.Page * options.PerPage
   442  	limit := options.PerPage
   443  
   444  	searchQuery := `
   445  		SELECT Users.* FROM Users, TeamMembers 
   446  		WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId AND TeamMembers.DeleteAt = 0
   447  		SEARCH_CLAUSE
   448  		ORDER BY Users.Username ASC LIMIT :Limit OFFSET :Offset
   449  		`
   450  
   451  	parameters := map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}
   452  	searchQuery = substituteWhereClause(searchQuery, options, parameters, isPostgreSQL)
   453  
   454  	return store.Do(func(result *store.StoreResult) {
   455  		var users []*model.User
   456  
   457  		if _, err := us.GetReplica().Select(&users, searchQuery, parameters); err != nil {
   458  			result.Err = model.NewAppError("SqlUserStore.GetProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   459  		} else {
   460  
   461  			for _, u := range users {
   462  				u.Sanitize(map[string]bool{})
   463  			}
   464  
   465  			result.Data = users
   466  		}
   467  	})
   468  }
   469  
   470  func (us SqlUserStore) InvalidateProfilesInChannelCacheByUser(userId string) {
   471  	keys := profilesInChannelCache.Keys()
   472  
   473  	for _, key := range keys {
   474  		if cacheItem, ok := profilesInChannelCache.Get(key); ok {
   475  			userMap := cacheItem.(map[string]*model.User)
   476  			if _, userInCache := userMap[userId]; userInCache {
   477  				profilesInChannelCache.Remove(key)
   478  				if us.metrics != nil {
   479  					us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User")
   480  				}
   481  			}
   482  		}
   483  	}
   484  }
   485  
   486  func (us SqlUserStore) InvalidateProfilesInChannelCache(channelId string) {
   487  	profilesInChannelCache.Remove(channelId)
   488  	if us.metrics != nil {
   489  		us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by Channel")
   490  	}
   491  }
   492  
   493  func (us SqlUserStore) GetProfilesInChannel(channelId string, offset int, limit int) store.StoreChannel {
   494  	return store.Do(func(result *store.StoreResult) {
   495  		var users []*model.User
   496  
   497  		query := `
   498  				SELECT 
   499  					Users.* 
   500  				FROM 
   501  					Users, ChannelMembers 
   502  				WHERE 
   503  					ChannelMembers.ChannelId = :ChannelId 
   504  					AND Users.Id = ChannelMembers.UserId 
   505  				ORDER BY 
   506  					Users.Username ASC 
   507  				LIMIT :Limit OFFSET :Offset
   508  		`
   509  
   510  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   511  			result.Err = model.NewAppError("SqlUserStore.GetProfilesInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   512  		} else {
   513  
   514  			for _, u := range users {
   515  				u.Sanitize(map[string]bool{})
   516  			}
   517  
   518  			result.Data = users
   519  		}
   520  	})
   521  }
   522  
   523  func (us SqlUserStore) GetProfilesInChannelByStatus(channelId string, offset int, limit int) store.StoreChannel {
   524  	return store.Do(func(result *store.StoreResult) {
   525  		var users []*model.User
   526  
   527  		query := `
   528  			SELECT 
   529  				Users.*
   530  			FROM Users
   531  				INNER JOIN ChannelMembers ON Users.Id = ChannelMembers.UserId
   532  				LEFT JOIN Status  ON Users.Id = Status.UserId
   533  			WHERE
   534  				ChannelMembers.ChannelId = :ChannelId
   535  			ORDER BY 
   536  				CASE Status
   537  					WHEN 'online' THEN 1
   538  					WHEN 'away' THEN 2
   539  					WHEN 'dnd' THEN 3
   540  					ELSE 4
   541  				END,
   542  				Users.Username ASC 
   543  			LIMIT :Limit OFFSET :Offset
   544  		`
   545  
   546  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   547  			result.Err = model.NewAppError("SqlUserStore.GetProfilesInChannelByStatus", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   548  		} else {
   549  
   550  			for _, u := range users {
   551  				u.Sanitize(map[string]bool{})
   552  			}
   553  
   554  			result.Data = users
   555  		}
   556  	})
   557  }
   558  
   559  func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) store.StoreChannel {
   560  	return store.Do(func(result *store.StoreResult) {
   561  		if allowFromCache {
   562  			if cacheItem, ok := profilesInChannelCache.Get(channelId); ok {
   563  				if us.metrics != nil {
   564  					us.metrics.IncrementMemCacheHitCounter("Profiles in Channel")
   565  				}
   566  				result.Data = cacheItem.(map[string]*model.User)
   567  				return
   568  			} else {
   569  				if us.metrics != nil {
   570  					us.metrics.IncrementMemCacheMissCounter("Profiles in Channel")
   571  				}
   572  			}
   573  		} else {
   574  			if us.metrics != nil {
   575  				us.metrics.IncrementMemCacheMissCounter("Profiles in Channel")
   576  			}
   577  		}
   578  
   579  		var users []*model.User
   580  
   581  		query := "SELECT Users.* FROM Users, ChannelMembers WHERE ChannelMembers.ChannelId = :ChannelId AND Users.Id = ChannelMembers.UserId AND Users.DeleteAt = 0"
   582  
   583  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId}); err != nil {
   584  			result.Err = model.NewAppError("SqlUserStore.GetAllProfilesInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   585  		} else {
   586  
   587  			userMap := make(map[string]*model.User)
   588  
   589  			for _, u := range users {
   590  				u.Sanitize(map[string]bool{})
   591  				userMap[u.Id] = u
   592  			}
   593  
   594  			result.Data = userMap
   595  
   596  			if allowFromCache {
   597  				profilesInChannelCache.AddWithExpiresInSecs(channelId, userMap, PROFILES_IN_CHANNEL_CACHE_SEC)
   598  			}
   599  		}
   600  	})
   601  }
   602  
   603  func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) store.StoreChannel {
   604  	return store.Do(func(result *store.StoreResult) {
   605  		var users []*model.User
   606  
   607  		if _, err := us.GetReplica().Select(&users, `
   608              SELECT
   609                  u.*
   610              FROM Users u
   611              INNER JOIN TeamMembers tm
   612                  ON tm.UserId = u.Id
   613                  AND tm.TeamId = :TeamId
   614                  AND tm.DeleteAt = 0
   615              LEFT JOIN ChannelMembers cm
   616                  ON cm.UserId = u.Id
   617                  AND cm.ChannelId = :ChannelId
   618              WHERE cm.UserId IS NULL
   619              ORDER BY u.Username ASC
   620              LIMIT :Limit OFFSET :Offset
   621              `, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   622  			result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   623  		} else {
   624  
   625  			for _, u := range users {
   626  				u.Sanitize(map[string]bool{})
   627  			}
   628  
   629  			result.Data = users
   630  		}
   631  	})
   632  }
   633  
   634  func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreChannel {
   635  	return store.Do(func(result *store.StoreResult) {
   636  		var users []*model.User
   637  
   638  		query := `
   639  		SELECT
   640  			*
   641  		FROM
   642  			Users
   643  		WHERE
   644  			(SELECT
   645  				COUNT(0)
   646  			FROM
   647  				TeamMembers
   648  			WHERE
   649  				TeamMembers.UserId = Users.Id
   650  				AND TeamMembers.DeleteAt = 0) = 0
   651  		ORDER BY
   652  			Username ASC
   653  		LIMIT
   654  			:Limit
   655  		OFFSET
   656  			:Offset`
   657  
   658  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   659  			result.Err = model.NewAppError("SqlUserStore.GetProfilesWithoutTeam", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   660  		} else {
   661  
   662  			for _, u := range users {
   663  				u.Sanitize(map[string]bool{})
   664  			}
   665  
   666  			result.Data = users
   667  		}
   668  	})
   669  }
   670  
   671  func (us SqlUserStore) GetProfilesByUsernames(usernames []string, teamId string) store.StoreChannel {
   672  	return store.Do(func(result *store.StoreResult) {
   673  		var users []*model.User
   674  		props := make(map[string]interface{})
   675  		idQuery := ""
   676  
   677  		for index, usernames := range usernames {
   678  			if len(idQuery) > 0 {
   679  				idQuery += ", "
   680  			}
   681  
   682  			props["username"+strconv.Itoa(index)] = usernames
   683  			idQuery += ":username" + strconv.Itoa(index)
   684  		}
   685  
   686  		var query string
   687  		if teamId == "" {
   688  			query = `SELECT * FROM Users WHERE Username IN (` + idQuery + `)`
   689  		} else {
   690  			query = `SELECT Users.* FROM Users INNER JOIN TeamMembers ON
   691  				Users.Id = TeamMembers.UserId AND Users.Username IN (` + idQuery + `) AND TeamMembers.TeamId = :TeamId `
   692  			props["TeamId"] = teamId
   693  		}
   694  
   695  		if _, err := us.GetReplica().Select(&users, query, props); err != nil {
   696  			result.Err = model.NewAppError("SqlUserStore.GetProfilesByUsernames", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   697  		} else {
   698  			result.Data = users
   699  		}
   700  	})
   701  }
   702  
   703  type UserWithLastActivityAt struct {
   704  	model.User
   705  	LastActivityAt int64
   706  }
   707  
   708  func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limit int) store.StoreChannel {
   709  	return store.Do(func(result *store.StoreResult) {
   710  		var users []*UserWithLastActivityAt
   711  
   712  		if _, err := us.GetReplica().Select(&users, `
   713              SELECT
   714                  u.*,
   715                  s.LastActivityAt
   716              FROM Users AS u
   717                  INNER JOIN TeamMembers AS t ON u.Id = t.UserId
   718                  INNER JOIN Status AS s ON s.UserId = t.UserId
   719              WHERE t.TeamId = :TeamId
   720              ORDER BY s.LastActivityAt DESC
   721              LIMIT :Limit OFFSET :Offset
   722              `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
   723  			result.Err = model.NewAppError("SqlUserStore.GetRecentlyActiveUsers", "store.sql_user.get_recently_active_users.app_error", nil, err.Error(), http.StatusInternalServerError)
   724  		} else {
   725  
   726  			userList := []*model.User{}
   727  
   728  			for _, userWithLastActivityAt := range users {
   729  				u := userWithLastActivityAt.User
   730  				u.Sanitize(map[string]bool{})
   731  				u.LastActivityAt = userWithLastActivityAt.LastActivityAt
   732  				userList = append(userList, &u)
   733  			}
   734  
   735  			result.Data = userList
   736  		}
   737  	})
   738  }
   739  
   740  func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) store.StoreChannel {
   741  	return store.Do(func(result *store.StoreResult) {
   742  		var users []*model.User
   743  
   744  		if _, err := us.GetReplica().Select(&users, `
   745              SELECT
   746                  u.*
   747              FROM Users AS u
   748                  INNER JOIN TeamMembers AS t ON u.Id = t.UserId
   749              WHERE t.TeamId = :TeamId
   750              ORDER BY u.CreateAt DESC
   751              LIMIT :Limit OFFSET :Offset
   752              `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
   753  			result.Err = model.NewAppError("SqlUserStore.GetNewUsersForTeam", "store.sql_user.get_new_users.app_error", nil, err.Error(), http.StatusInternalServerError)
   754  		} else {
   755  			for _, u := range users {
   756  				u.Sanitize(map[string]bool{})
   757  			}
   758  
   759  			result.Data = users
   760  		}
   761  	})
   762  }
   763  
   764  func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) store.StoreChannel {
   765  	return store.Do(func(result *store.StoreResult) {
   766  		users := []*model.User{}
   767  		props := make(map[string]interface{})
   768  		idQuery := ""
   769  		remainingUserIds := make([]string, 0)
   770  
   771  		if allowFromCache {
   772  			for _, userId := range userIds {
   773  				if cacheItem, ok := profileByIdsCache.Get(userId); ok {
   774  					u := &model.User{}
   775  					*u = *cacheItem.(*model.User)
   776  					users = append(users, u)
   777  				} else {
   778  					remainingUserIds = append(remainingUserIds, userId)
   779  				}
   780  			}
   781  			if us.metrics != nil {
   782  				us.metrics.AddMemCacheHitCounter("Profile By Ids", float64(len(users)))
   783  				us.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds)))
   784  			}
   785  		} else {
   786  			remainingUserIds = userIds
   787  			if us.metrics != nil {
   788  				us.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds)))
   789  			}
   790  		}
   791  
   792  		// If everything came from the cache then just return
   793  		if len(remainingUserIds) == 0 {
   794  			result.Data = users
   795  			return
   796  		}
   797  
   798  		for index, userId := range remainingUserIds {
   799  			if len(idQuery) > 0 {
   800  				idQuery += ", "
   801  			}
   802  
   803  			props["userId"+strconv.Itoa(index)] = userId
   804  			idQuery += ":userId" + strconv.Itoa(index)
   805  		}
   806  
   807  		if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Users.Id IN ("+idQuery+")", props); err != nil {
   808  			result.Err = model.NewAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   809  		} else {
   810  
   811  			for _, u := range users {
   812  				u.Sanitize(map[string]bool{})
   813  
   814  				cpy := &model.User{}
   815  				*cpy = *u
   816  				profileByIdsCache.AddWithExpiresInSecs(cpy.Id, cpy, PROFILE_BY_IDS_CACHE_SEC)
   817  			}
   818  
   819  			result.Data = users
   820  		}
   821  	})
   822  }
   823  
   824  func (us SqlUserStore) GetSystemAdminProfiles() store.StoreChannel {
   825  	return store.Do(func(result *store.StoreResult) {
   826  		var users []*model.User
   827  
   828  		if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Roles LIKE :Roles", map[string]interface{}{"Roles": "%system_admin%"}); err != nil {
   829  			result.Err = model.NewAppError("SqlUserStore.GetSystemAdminProfiles", "store.sql_user.get_sysadmin_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   830  		} else {
   831  
   832  			userMap := make(map[string]*model.User)
   833  
   834  			for _, u := range users {
   835  				u.Sanitize(map[string]bool{})
   836  				userMap[u.Id] = u
   837  			}
   838  
   839  			result.Data = userMap
   840  		}
   841  	})
   842  }
   843  
   844  func (us SqlUserStore) GetByEmail(email string) store.StoreChannel {
   845  	return store.Do(func(result *store.StoreResult) {
   846  		email = strings.ToLower(email)
   847  
   848  		user := model.User{}
   849  
   850  		if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Email = :Email", map[string]interface{}{"Email": email}); err != nil {
   851  			result.Err = model.NewAppError("SqlUserStore.GetByEmail", store.MISSING_ACCOUNT_ERROR, nil, "email="+email+", "+err.Error(), http.StatusInternalServerError)
   852  		}
   853  
   854  		result.Data = &user
   855  	})
   856  }
   857  
   858  func (us SqlUserStore) GetByAuth(authData *string, authService string) store.StoreChannel {
   859  	return store.Do(func(result *store.StoreResult) {
   860  		if authData == nil || *authData == "" {
   861  			result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData='', authService="+authService, http.StatusBadRequest)
   862  			return
   863  		}
   864  
   865  		user := model.User{}
   866  
   867  		if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE AuthData = :AuthData AND AuthService = :AuthService", map[string]interface{}{"AuthData": authData, "AuthService": authService}); err != nil {
   868  			if err == sql.ErrNoRows {
   869  				result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData="+*authData+", authService="+authService+", "+err.Error(), http.StatusInternalServerError)
   870  			} else {
   871  				result.Err = model.NewAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authData="+*authData+", authService="+authService+", "+err.Error(), http.StatusInternalServerError)
   872  			}
   873  		}
   874  
   875  		result.Data = &user
   876  	})
   877  }
   878  
   879  func (us SqlUserStore) GetAllUsingAuthService(authService string) store.StoreChannel {
   880  	return store.Do(func(result *store.StoreResult) {
   881  		var data []*model.User
   882  
   883  		if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE AuthService = :AuthService", map[string]interface{}{"AuthService": authService}); err != nil {
   884  			result.Err = model.NewAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authService="+authService+", "+err.Error(), http.StatusInternalServerError)
   885  		}
   886  
   887  		result.Data = data
   888  	})
   889  }
   890  
   891  func (us SqlUserStore) GetByUsername(username string) store.StoreChannel {
   892  	return store.Do(func(result *store.StoreResult) {
   893  		user := model.User{}
   894  
   895  		if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Username = :Username", map[string]interface{}{"Username": username}); err != nil {
   896  			result.Err = model.NewAppError("SqlUserStore.GetByUsername", "store.sql_user.get_by_username.app_error", nil, err.Error(), http.StatusInternalServerError)
   897  		}
   898  
   899  		result.Data = &user
   900  	})
   901  }
   902  
   903  func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail bool) store.StoreChannel {
   904  	return store.Do(func(result *store.StoreResult) {
   905  		params := map[string]interface{}{
   906  			"LoginId":                 loginId,
   907  			"AllowSignInWithUsername": allowSignInWithUsername,
   908  			"AllowSignInWithEmail":    allowSignInWithEmail,
   909  		}
   910  
   911  		users := []*model.User{}
   912  		if _, err := us.GetReplica().Select(
   913  			&users,
   914  			`SELECT
   915  				*
   916  			FROM
   917  				Users
   918  			WHERE
   919  				(:AllowSignInWithUsername AND Username = :LoginId)
   920  				OR (:AllowSignInWithEmail AND Email = :LoginId)`,
   921  			params); err != nil {
   922  			result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, err.Error(), http.StatusInternalServerError)
   923  		} else if len(users) == 1 {
   924  			result.Data = users[0]
   925  		} else if len(users) > 1 {
   926  			result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.multiple_users", nil, "", http.StatusInternalServerError)
   927  		} else {
   928  			result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, "", http.StatusInternalServerError)
   929  		}
   930  	})
   931  }
   932  
   933  func (us SqlUserStore) VerifyEmail(userId string) store.StoreChannel {
   934  	return store.Do(func(result *store.StoreResult) {
   935  		if _, err := us.GetMaster().Exec("UPDATE Users SET EmailVerified = true WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
   936  			result.Err = model.NewAppError("SqlUserStore.VerifyEmail", "store.sql_user.verify_email.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError)
   937  		}
   938  
   939  		result.Data = userId
   940  	})
   941  }
   942  
   943  func (us SqlUserStore) GetTotalUsersCount() store.StoreChannel {
   944  	return store.Do(func(result *store.StoreResult) {
   945  		if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users"); err != nil {
   946  			result.Err = model.NewAppError("SqlUserStore.GetTotalUsersCount", "store.sql_user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   947  		} else {
   948  			result.Data = count
   949  		}
   950  	})
   951  }
   952  
   953  func (us SqlUserStore) PermanentDelete(userId string) store.StoreChannel {
   954  	return store.Do(func(result *store.StoreResult) {
   955  		if _, err := us.GetMaster().Exec("DELETE FROM Users WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
   956  			result.Err = model.NewAppError("SqlUserStore.PermanentDelete", "store.sql_user.permanent_delete.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError)
   957  		}
   958  	})
   959  }
   960  
   961  func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) store.StoreChannel {
   962  	return store.Do(func(result *store.StoreResult) {
   963  		query := ""
   964  		if len(teamId) > 0 {
   965  			query = "SELECT COUNT(DISTINCT Users.Email) From Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId AND TeamMembers.DeleteAt = 0 AND Users.DeleteAt = 0"
   966  		} else {
   967  			query = "SELECT COUNT(DISTINCT Email) FROM Users WHERE DeleteAt = 0"
   968  		}
   969  
   970  		v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId})
   971  		if err != nil {
   972  			result.Err = model.NewAppError("SqlUserStore.AnalyticsUniqueUserCount", "store.sql_user.analytics_unique_user_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   973  		} else {
   974  			result.Data = v
   975  		}
   976  	})
   977  }
   978  
   979  func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64) store.StoreChannel {
   980  	return store.Do(func(result *store.StoreResult) {
   981  		time := model.GetMillis() - timePeriod
   982  
   983  		query := "SELECT COUNT(*) FROM Status WHERE LastActivityAt > :Time"
   984  
   985  		v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"Time": time})
   986  		if err != nil {
   987  			result.Err = model.NewAppError("SqlUserStore.AnalyticsDailyActiveUsers", "store.sql_user.analytics_daily_active_users.app_error", nil, err.Error(), http.StatusInternalServerError)
   988  		} else {
   989  			result.Data = v
   990  		}
   991  	})
   992  }
   993  
   994  func (us SqlUserStore) GetUnreadCount(userId string) store.StoreChannel {
   995  	return store.Do(func(result *store.StoreResult) {
   996  		if count, err := us.GetReplica().SelectInt(`
   997  		SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END)
   998  		FROM Channels c
   999  		INNER JOIN ChannelMembers cm
  1000  		      ON cm.ChannelId = c.Id
  1001  		      AND cm.UserId = :UserId
  1002  		      AND c.DeleteAt = 0`, map[string]interface{}{"UserId": userId}); err != nil {
  1003  			result.Err = model.NewAppError("SqlUserStore.GetMentionCount", "store.sql_user.get_unread_count.app_error", nil, err.Error(), http.StatusInternalServerError)
  1004  		} else {
  1005  			result.Data = count
  1006  		}
  1007  	})
  1008  }
  1009  
  1010  func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) store.StoreChannel {
  1011  	return store.Do(func(result *store.StoreResult) {
  1012  		if count, err := us.GetReplica().SelectInt("SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = :ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
  1013  			result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError)
  1014  		} else {
  1015  			result.Data = count
  1016  		}
  1017  	})
  1018  }
  1019  
  1020  func (us SqlUserStore) GetAnyUnreadPostCountForChannel(userId string, channelId string) store.StoreChannel {
  1021  	return store.Do(func(result *store.StoreResult) {
  1022  		if count, err := us.GetReplica().SelectInt("SELECT SUM(c.TotalMsgCount - cm.MsgCount) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = :ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
  1023  			result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError)
  1024  		} else {
  1025  			result.Data = count
  1026  		}
  1027  	})
  1028  }
  1029  
  1030  func (us SqlUserStore) Search(teamId string, term string, options *model.UserSearchOptions) store.StoreChannel {
  1031  	return store.Do(func(result *store.StoreResult) {
  1032  		searchQuery := ""
  1033  
  1034  		if teamId == "" {
  1035  			// Id != '' is added because both SEARCH_CLAUSE and INACTIVE_CLAUSE start with an AND
  1036  			searchQuery = `
  1037  			SELECT
  1038  				*
  1039  			FROM
  1040  				Users
  1041  			WHERE
  1042  				Id != ''
  1043  				SEARCH_CLAUSE
  1044  				INACTIVE_CLAUSE
  1045  			ORDER BY Username ASC
  1046  			LIMIT :Limit`
  1047  		} else {
  1048  			searchQuery = `
  1049  			SELECT
  1050  				Users.*
  1051  			FROM
  1052  				Users, TeamMembers
  1053  			WHERE
  1054  				TeamMembers.TeamId = :TeamId
  1055  				AND Users.Id = TeamMembers.UserId
  1056  				AND TeamMembers.DeleteAt = 0
  1057  				SEARCH_CLAUSE
  1058  				INACTIVE_CLAUSE
  1059  			ORDER BY Users.Username ASC
  1060  			LIMIT :Limit`
  1061  		}
  1062  
  1063  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{
  1064  			"TeamId": teamId,
  1065  			"Limit":  options.Limit,
  1066  		})
  1067  
  1068  	})
  1069  }
  1070  
  1071  func (us SqlUserStore) SearchWithoutTeam(term string, options *model.UserSearchOptions) store.StoreChannel {
  1072  	return store.Do(func(result *store.StoreResult) {
  1073  		searchQuery := `
  1074  		SELECT
  1075  			*
  1076  		FROM
  1077  			Users
  1078  		WHERE
  1079  			(SELECT
  1080  				COUNT(0)
  1081  			FROM
  1082  				TeamMembers
  1083  			WHERE
  1084  				TeamMembers.UserId = Users.Id
  1085  				AND TeamMembers.DeleteAt = 0) = 0
  1086  			SEARCH_CLAUSE
  1087  			INACTIVE_CLAUSE
  1088  			ORDER BY Username ASC
  1089  		LIMIT :Limit`
  1090  
  1091  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{
  1092  			"Limit": options.Limit,
  1093  		})
  1094  
  1095  	})
  1096  }
  1097  
  1098  func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options *model.UserSearchOptions) store.StoreChannel {
  1099  	return store.Do(func(result *store.StoreResult) {
  1100  		searchQuery := `
  1101  			SELECT
  1102  				Users.*
  1103  			FROM Users
  1104  			LEFT JOIN TeamMembers tm
  1105  				ON tm.UserId = Users.Id
  1106  				AND tm.TeamId = :NotInTeamId
  1107  			WHERE
  1108  				(tm.UserId IS NULL OR tm.DeleteAt != 0)
  1109  				SEARCH_CLAUSE
  1110  				INACTIVE_CLAUSE
  1111  			ORDER BY Users.Username ASC
  1112  			LIMIT :Limit`
  1113  
  1114  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{
  1115  			"NotInTeamId": notInTeamId,
  1116  			"Limit":       options.Limit,
  1117  		})
  1118  
  1119  	})
  1120  }
  1121  
  1122  func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) store.StoreChannel {
  1123  	return store.Do(func(result *store.StoreResult) {
  1124  		searchQuery := ""
  1125  		if teamId == "" {
  1126  			searchQuery = `
  1127  			SELECT
  1128  				Users.*
  1129  			FROM Users
  1130  			LEFT JOIN ChannelMembers cm
  1131  				ON cm.UserId = Users.Id
  1132  				AND cm.ChannelId = :ChannelId
  1133  			WHERE
  1134  				cm.UserId IS NULL
  1135  				SEARCH_CLAUSE
  1136  				INACTIVE_CLAUSE
  1137  			ORDER BY Users.Username ASC
  1138  			LIMIT :Limit`
  1139  		} else {
  1140  			searchQuery = `
  1141  			SELECT
  1142  				Users.*
  1143  			FROM Users
  1144  			INNER JOIN TeamMembers tm
  1145  				ON tm.UserId = Users.Id
  1146  				AND tm.TeamId = :TeamId
  1147  				AND tm.DeleteAt = 0
  1148  			LEFT JOIN ChannelMembers cm
  1149  				ON cm.UserId = Users.Id
  1150  				AND cm.ChannelId = :ChannelId
  1151  			WHERE
  1152  				cm.UserId IS NULL
  1153  				SEARCH_CLAUSE
  1154  				INACTIVE_CLAUSE
  1155  			ORDER BY Users.Username ASC
  1156  			LIMIT :Limit`
  1157  		}
  1158  
  1159  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{
  1160  			"TeamId":    teamId,
  1161  			"ChannelId": channelId,
  1162  			"Limit":     options.Limit,
  1163  		})
  1164  	})
  1165  }
  1166  
  1167  func (us SqlUserStore) SearchInChannel(channelId string, term string, options *model.UserSearchOptions) store.StoreChannel {
  1168  	return store.Do(func(result *store.StoreResult) {
  1169  		searchQuery := `
  1170  			SELECT
  1171  			    Users.*
  1172  			FROM
  1173  			    Users, ChannelMembers
  1174  			WHERE
  1175  			    ChannelMembers.ChannelId = :ChannelId
  1176  			    AND ChannelMembers.UserId = Users.Id
  1177  			    SEARCH_CLAUSE
  1178  			    INACTIVE_CLAUSE
  1179  			    ORDER BY Users.Username ASC
  1180  		    LIMIT :Limit
  1181  		`
  1182  
  1183  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{
  1184  			"ChannelId": channelId,
  1185  			"Limit":     options.Limit,
  1186  		})
  1187  
  1188  	})
  1189  }
  1190  
  1191  var escapeLikeSearchChar = []string{
  1192  	"%",
  1193  	"_",
  1194  }
  1195  
  1196  var ignoreLikeSearchChar = []string{
  1197  	"*",
  1198  }
  1199  
  1200  var spaceFulltextSearchChar = []string{
  1201  	"<",
  1202  	">",
  1203  	"+",
  1204  	"-",
  1205  	"(",
  1206  	")",
  1207  	"~",
  1208  	":",
  1209  	"*",
  1210  	"\"",
  1211  	"!",
  1212  	"@",
  1213  }
  1214  
  1215  func generateSearchQuery(searchQuery string, terms []string, fields []string, parameters map[string]interface{}, isPostgreSQL bool, role string) string {
  1216  	searchTerms := []string{}
  1217  	for i, term := range terms {
  1218  		searchFields := []string{}
  1219  		for _, field := range fields {
  1220  			if isPostgreSQL {
  1221  				searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*' ", field, fmt.Sprintf(":Term%d", i)))
  1222  			} else {
  1223  				searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*' ", field, fmt.Sprintf(":Term%d", i)))
  1224  			}
  1225  		}
  1226  		searchTerms = append(searchTerms, fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")))
  1227  		parameters[fmt.Sprintf("Term%d", i)] = fmt.Sprintf("%s%%", strings.TrimLeft(term, "@"))
  1228  	}
  1229  
  1230  	if role != "" {
  1231  		searchTerms = append(searchTerms, getRoleFilter(isPostgreSQL))
  1232  		parameters["Role"] = fmt.Sprintf("%%%s%%", role)
  1233  	}
  1234  
  1235  	searchClause := strings.Join(searchTerms, " AND ")
  1236  	return strings.Replace(searchQuery, "SEARCH_CLAUSE", fmt.Sprintf(" AND %s ", searchClause), 1)
  1237  }
  1238  
  1239  func (us SqlUserStore) performSearch(searchQuery string, term string, options *model.UserSearchOptions, parameters map[string]interface{}) store.StoreResult {
  1240  	result := store.StoreResult{}
  1241  
  1242  	// These chars must be removed from the like query.
  1243  	for _, c := range ignoreLikeSearchChar {
  1244  		term = strings.Replace(term, c, "", -1)
  1245  	}
  1246  
  1247  	// These chars must be escaped in the like query.
  1248  	for _, c := range escapeLikeSearchChar {
  1249  		term = strings.Replace(term, c, "*"+c, -1)
  1250  	}
  1251  
  1252  	searchType := USER_SEARCH_TYPE_NAMES_NO_FULL_NAME
  1253  	if options.AllowEmails {
  1254  		if options.AllowFullNames {
  1255  			searchType = USER_SEARCH_TYPE_ALL
  1256  		} else {
  1257  			searchType = USER_SEARCH_TYPE_ALL_NO_FULL_NAME
  1258  		}
  1259  	} else {
  1260  		if options.AllowFullNames {
  1261  			searchType = USER_SEARCH_TYPE_NAMES
  1262  		} else {
  1263  			searchType = USER_SEARCH_TYPE_NAMES_NO_FULL_NAME
  1264  		}
  1265  	}
  1266  
  1267  	role := ""
  1268  	if options.Role != "" {
  1269  		role = options.Role
  1270  	}
  1271  
  1272  	if ok := options.AllowInactive; ok {
  1273  		searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "", 1)
  1274  	} else {
  1275  		searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "AND Users.DeleteAt = 0", 1)
  1276  	}
  1277  
  1278  	if strings.TrimSpace(term) == "" {
  1279  		searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1)
  1280  	} else {
  1281  		isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES
  1282  		searchQuery = generateSearchQuery(searchQuery, strings.Fields(term), searchType, parameters, isPostgreSQL, role)
  1283  	}
  1284  
  1285  	var users []*model.User
  1286  
  1287  	if _, err := us.GetReplica().Select(&users, searchQuery, parameters); err != nil {
  1288  		result.Err = model.NewAppError("SqlUserStore.Search", "store.sql_user.search.app_error", nil,
  1289  			fmt.Sprintf("term=%v, search_type=%v, %v", term, searchType, err.Error()), http.StatusInternalServerError)
  1290  	} else {
  1291  		for _, u := range users {
  1292  			u.Sanitize(map[string]bool{})
  1293  		}
  1294  
  1295  		result.Data = users
  1296  	}
  1297  
  1298  	return result
  1299  }
  1300  
  1301  func (us SqlUserStore) AnalyticsGetInactiveUsersCount() store.StoreChannel {
  1302  	return store.Do(func(result *store.StoreResult) {
  1303  		if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0"); err != nil {
  1304  			result.Err = model.NewAppError("SqlUserStore.AnalyticsGetInactiveUsersCount", "store.sql_user.analytics_get_inactive_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
  1305  		} else {
  1306  			result.Data = count
  1307  		}
  1308  	})
  1309  }
  1310  
  1311  func (us SqlUserStore) AnalyticsGetSystemAdminCount() store.StoreChannel {
  1312  	return store.Do(func(result *store.StoreResult) {
  1313  		if count, err := us.GetReplica().SelectInt("SELECT count(*) FROM Users WHERE Roles LIKE :Roles and DeleteAt = 0", map[string]interface{}{"Roles": "%system_admin%"}); err != nil {
  1314  			result.Err = model.NewAppError("SqlUserStore.AnalyticsGetSystemAdminCount", "store.sql_user.analytics_get_system_admin_count.app_error", nil, err.Error(), http.StatusInternalServerError)
  1315  		} else {
  1316  			result.Data = count
  1317  		}
  1318  	})
  1319  }
  1320  
  1321  func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int) store.StoreChannel {
  1322  	return store.Do(func(result *store.StoreResult) {
  1323  		var users []*model.User
  1324  
  1325  		if _, err := us.GetReplica().Select(&users, `
  1326              SELECT
  1327                  u.*
  1328              FROM Users u
  1329              LEFT JOIN TeamMembers tm
  1330                  ON tm.UserId = u.Id
  1331                  AND tm.TeamId = :TeamId
  1332                  AND tm.DeleteAt = 0
  1333              WHERE tm.UserId IS NULL
  1334              ORDER BY u.Username ASC
  1335              LIMIT :Limit OFFSET :Offset
  1336              `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
  1337  			result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInTeam", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
  1338  		} else {
  1339  
  1340  			for _, u := range users {
  1341  				u.Sanitize(map[string]bool{})
  1342  			}
  1343  
  1344  			result.Data = users
  1345  		}
  1346  	})
  1347  }
  1348  
  1349  func (us SqlUserStore) GetEtagForProfilesNotInTeam(teamId string) store.StoreChannel {
  1350  	return store.Do(func(result *store.StoreResult) {
  1351  		updateAt, err := us.GetReplica().SelectInt(`
  1352              SELECT
  1353                  u.UpdateAt
  1354              FROM Users u
  1355              LEFT JOIN TeamMembers tm
  1356                  ON tm.UserId = u.Id
  1357                  AND tm.TeamId = :TeamId
  1358                  AND tm.DeleteAt = 0
  1359              WHERE tm.UserId IS NULL
  1360              ORDER BY u.UpdateAt DESC
  1361              LIMIT 1
  1362              `, map[string]interface{}{"TeamId": teamId})
  1363  
  1364  		if err != nil {
  1365  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
  1366  		} else {
  1367  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
  1368  		}
  1369  	})
  1370  }
  1371  
  1372  func (us SqlUserStore) ClearAllCustomRoleAssignments() store.StoreChannel {
  1373  	return store.Do(func(result *store.StoreResult) {
  1374  		builtInRoles := model.MakeDefaultRoles()
  1375  		lastUserId := strings.Repeat("0", 26)
  1376  
  1377  		for {
  1378  			var transaction *gorp.Transaction
  1379  			var err error
  1380  
  1381  			if transaction, err = us.GetMaster().Begin(); err != nil {
  1382  				result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
  1383  				return
  1384  			}
  1385  
  1386  			var users []*model.User
  1387  			if _, err := transaction.Select(&users, "SELECT * from Users WHERE Id > :Id ORDER BY Id LIMIT 1000", map[string]interface{}{"Id": lastUserId}); err != nil {
  1388  				if err2 := transaction.Rollback(); err2 != nil {
  1389  					result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
  1390  					return
  1391  				}
  1392  				result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.select.app_error", nil, err.Error(), http.StatusInternalServerError)
  1393  				return
  1394  			}
  1395  
  1396  			if len(users) == 0 {
  1397  				break
  1398  			}
  1399  
  1400  			for _, user := range users {
  1401  				lastUserId = user.Id
  1402  
  1403  				var newRoles []string
  1404  
  1405  				for _, role := range strings.Fields(user.Roles) {
  1406  					for name := range builtInRoles {
  1407  						if name == role {
  1408  							newRoles = append(newRoles, role)
  1409  							break
  1410  						}
  1411  					}
  1412  				}
  1413  
  1414  				newRolesString := strings.Join(newRoles, " ")
  1415  				if newRolesString != user.Roles {
  1416  					if _, err := transaction.Exec("UPDATE Users SET Roles = :Roles WHERE Id = :Id", map[string]interface{}{"Roles": newRolesString, "Id": user.Id}); err != nil {
  1417  						if err2 := transaction.Rollback(); err2 != nil {
  1418  							result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
  1419  							return
  1420  						}
  1421  						result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.update.app_error", nil, err.Error(), http.StatusInternalServerError)
  1422  						return
  1423  					}
  1424  				}
  1425  			}
  1426  
  1427  			if err := transaction.Commit(); err != nil {
  1428  				if err2 := transaction.Rollback(); err2 != nil {
  1429  					result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
  1430  					return
  1431  				}
  1432  				result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
  1433  				return
  1434  			}
  1435  		}
  1436  	})
  1437  }
  1438  
  1439  func (us SqlUserStore) InferSystemInstallDate() store.StoreChannel {
  1440  	return store.Do(func(result *store.StoreResult) {
  1441  		createAt, err := us.GetReplica().SelectInt("SELECT CreateAt FROM Users WHERE CreateAt IS NOT NULL ORDER BY CreateAt ASC LIMIT 1")
  1442  		if err != nil {
  1443  			result.Err = model.NewAppError("SqlUserStore.GetSystemInstallDate", "store.sql_user.get_system_install_date.app_error", nil, err.Error(), http.StatusInternalServerError)
  1444  			return
  1445  		}
  1446  		result.Data = createAt
  1447  	})
  1448  }