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