github.com/levb/mattermost-server@v5.3.1+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", "Users", "lower(Email)")
    98  		us.CreateIndexIfNotExists("idx_users_username_lower", "Users", "lower(Username)")
    99  		us.CreateIndexIfNotExists("idx_users_nickname_lower", "Users", "lower(Nickname)")
   100  		us.CreateIndexIfNotExists("idx_users_firstname_lower", "Users", "lower(FirstName)")
   101  		us.CreateIndexIfNotExists("idx_users_lastname_lower", "Users", "lower(LastName)")
   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) UpdateUpdateAt(userId string) store.StoreChannel {
   216  	return store.Do(func(result *store.StoreResult) {
   217  		curTime := model.GetMillis()
   218  
   219  		if _, err := us.GetMaster().Exec("UPDATE Users SET UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil {
   220  			result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_update.app_error", nil, "user_id="+userId, http.StatusInternalServerError)
   221  		} else {
   222  			result.Data = userId
   223  		}
   224  	})
   225  }
   226  
   227  func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) store.StoreChannel {
   228  	return store.Do(func(result *store.StoreResult) {
   229  		updateAt := model.GetMillis()
   230  
   231  		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 {
   232  			result.Err = model.NewAppError("SqlUserStore.UpdatePassword", "store.sql_user.update_password.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   233  		} else {
   234  			result.Data = userId
   235  		}
   236  	})
   237  }
   238  
   239  func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int) store.StoreChannel {
   240  	return store.Do(func(result *store.StoreResult) {
   241  		if _, err := us.GetMaster().Exec("UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId", map[string]interface{}{"FailedAttempts": attempts, "UserId": userId}); err != nil {
   242  			result.Err = model.NewAppError("SqlUserStore.UpdateFailedPasswordAttempts", "store.sql_user.update_failed_pwd_attempts.app_error", nil, "user_id="+userId, http.StatusInternalServerError)
   243  		} else {
   244  			result.Data = userId
   245  		}
   246  	})
   247  }
   248  
   249  func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *string, email string, resetMfa bool) store.StoreChannel {
   250  	return store.Do(func(result *store.StoreResult) {
   251  		email = strings.ToLower(email)
   252  
   253  		updateAt := model.GetMillis()
   254  
   255  		query := `
   256  			UPDATE
   257  			     Users
   258  			SET
   259  			     Password = '',
   260  			     LastPasswordUpdate = :LastPasswordUpdate,
   261  			     UpdateAt = :UpdateAt,
   262  			     FailedAttempts = 0,
   263  			     AuthService = :AuthService,
   264  			     AuthData = :AuthData`
   265  
   266  		if len(email) != 0 {
   267  			query += ", Email = :Email"
   268  		}
   269  
   270  		if resetMfa {
   271  			query += ", MfaActive = false, MfaSecret = ''"
   272  		}
   273  
   274  		query += " WHERE Id = :UserId"
   275  
   276  		if _, err := us.GetMaster().Exec(query, map[string]interface{}{"LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId, "AuthService": service, "AuthData": authData, "Email": email}); err != nil {
   277  			if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique", "AuthData", "users_authdata_key"}) {
   278  				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)
   279  			} else {
   280  				result.Err = model.NewAppError("SqlUserStore.UpdateAuthData", "store.sql_user.update_auth_data.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   281  			}
   282  		} else {
   283  			result.Data = userId
   284  		}
   285  	})
   286  }
   287  
   288  func (us SqlUserStore) UpdateMfaSecret(userId, secret string) store.StoreChannel {
   289  	return store.Do(func(result *store.StoreResult) {
   290  		updateAt := model.GetMillis()
   291  
   292  		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 {
   293  			result.Err = model.NewAppError("SqlUserStore.UpdateMfaSecret", "store.sql_user.update_mfa_secret.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   294  		} else {
   295  			result.Data = userId
   296  		}
   297  	})
   298  }
   299  
   300  func (us SqlUserStore) UpdateMfaActive(userId string, active bool) store.StoreChannel {
   301  	return store.Do(func(result *store.StoreResult) {
   302  		updateAt := model.GetMillis()
   303  
   304  		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 {
   305  			result.Err = model.NewAppError("SqlUserStore.UpdateMfaActive", "store.sql_user.update_mfa_active.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError)
   306  		} else {
   307  			result.Data = userId
   308  		}
   309  	})
   310  }
   311  
   312  func (us SqlUserStore) Get(id string) store.StoreChannel {
   313  	return store.Do(func(result *store.StoreResult) {
   314  		if obj, err := us.GetReplica().Get(model.User{}, id); err != nil {
   315  			result.Err = model.NewAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, "user_id="+id+", "+err.Error(), http.StatusInternalServerError)
   316  		} else if obj == nil {
   317  			result.Err = model.NewAppError("SqlUserStore.Get", store.MISSING_ACCOUNT_ERROR, nil, "user_id="+id, http.StatusNotFound)
   318  		} else {
   319  			result.Data = obj.(*model.User)
   320  		}
   321  	})
   322  }
   323  
   324  func (us SqlUserStore) GetAll() store.StoreChannel {
   325  	return store.Do(func(result *store.StoreResult) {
   326  		var data []*model.User
   327  		if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users"); err != nil {
   328  			result.Err = model.NewAppError("SqlUserStore.GetAll", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
   329  		}
   330  
   331  		result.Data = data
   332  	})
   333  }
   334  
   335  func (s SqlUserStore) GetEtagForAllProfiles() store.StoreChannel {
   336  	return store.Do(func(result *store.StoreResult) {
   337  		updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1")
   338  		if err != nil {
   339  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
   340  		} else {
   341  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
   342  		}
   343  	})
   344  }
   345  
   346  func (us SqlUserStore) GetAllProfiles(offset int, limit int) store.StoreChannel {
   347  	return store.Do(func(result *store.StoreResult) {
   348  		var users []*model.User
   349  
   350  		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 {
   351  			result.Err = model.NewAppError("SqlUserStore.GetAllProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   352  		} else {
   353  
   354  			for _, u := range users {
   355  				u.Sanitize(map[string]bool{})
   356  			}
   357  
   358  			result.Data = users
   359  		}
   360  	})
   361  }
   362  
   363  func (s SqlUserStore) GetEtagForProfiles(teamId string) store.StoreChannel {
   364  	return store.Do(func(result *store.StoreResult) {
   365  		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})
   366  		if err != nil {
   367  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
   368  		} else {
   369  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
   370  		}
   371  	})
   372  }
   373  
   374  func (us SqlUserStore) GetProfiles(teamId string, offset int, limit int) store.StoreChannel {
   375  	return store.Do(func(result *store.StoreResult) {
   376  		var users []*model.User
   377  
   378  		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 {
   379  			result.Err = model.NewAppError("SqlUserStore.GetProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   380  		} else {
   381  
   382  			for _, u := range users {
   383  				u.Sanitize(map[string]bool{})
   384  			}
   385  
   386  			result.Data = users
   387  		}
   388  	})
   389  }
   390  
   391  func (us SqlUserStore) InvalidateProfilesInChannelCacheByUser(userId string) {
   392  	keys := profilesInChannelCache.Keys()
   393  
   394  	for _, key := range keys {
   395  		if cacheItem, ok := profilesInChannelCache.Get(key); ok {
   396  			userMap := cacheItem.(map[string]*model.User)
   397  			if _, userInCache := userMap[userId]; userInCache {
   398  				profilesInChannelCache.Remove(key)
   399  				if us.metrics != nil {
   400  					us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User")
   401  				}
   402  			}
   403  		}
   404  	}
   405  }
   406  
   407  func (us SqlUserStore) InvalidateProfilesInChannelCache(channelId string) {
   408  	profilesInChannelCache.Remove(channelId)
   409  	if us.metrics != nil {
   410  		us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by Channel")
   411  	}
   412  }
   413  
   414  func (us SqlUserStore) GetProfilesInChannel(channelId string, offset int, limit int) store.StoreChannel {
   415  	return store.Do(func(result *store.StoreResult) {
   416  		var users []*model.User
   417  
   418  		query := `
   419  				SELECT 
   420  					Users.* 
   421  				FROM 
   422  					Users, ChannelMembers 
   423  				WHERE 
   424  					ChannelMembers.ChannelId = :ChannelId 
   425  					AND Users.Id = ChannelMembers.UserId 
   426  				ORDER BY 
   427  					Users.Username ASC 
   428  				LIMIT :Limit OFFSET :Offset
   429  		`
   430  
   431  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   432  			result.Err = model.NewAppError("SqlUserStore.GetProfilesInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   433  		} else {
   434  
   435  			for _, u := range users {
   436  				u.Sanitize(map[string]bool{})
   437  			}
   438  
   439  			result.Data = users
   440  		}
   441  	})
   442  }
   443  
   444  func (us SqlUserStore) GetProfilesInChannelByStatus(channelId string, offset int, limit int) store.StoreChannel {
   445  	return store.Do(func(result *store.StoreResult) {
   446  		var users []*model.User
   447  
   448  		query := `
   449  			SELECT 
   450  				Users.*
   451  			FROM Users
   452  				INNER JOIN ChannelMembers ON Users.Id = ChannelMembers.UserId
   453  				LEFT JOIN Status  ON Users.Id = Status.UserId
   454  			WHERE
   455  				ChannelMembers.ChannelId = :ChannelId
   456  			ORDER BY 
   457  				CASE Status
   458  					WHEN 'online' THEN 1
   459  					WHEN 'away' THEN 2
   460  					WHEN 'dnd' THEN 3
   461  					ELSE 4
   462  				END,
   463  				Users.Username ASC 
   464  			LIMIT :Limit OFFSET :Offset
   465  		`
   466  
   467  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   468  			result.Err = model.NewAppError("SqlUserStore.GetProfilesInChannelByStatus", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   469  		} else {
   470  
   471  			for _, u := range users {
   472  				u.Sanitize(map[string]bool{})
   473  			}
   474  
   475  			result.Data = users
   476  		}
   477  	})
   478  }
   479  
   480  func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) store.StoreChannel {
   481  	return store.Do(func(result *store.StoreResult) {
   482  		if allowFromCache {
   483  			if cacheItem, ok := profilesInChannelCache.Get(channelId); ok {
   484  				if us.metrics != nil {
   485  					us.metrics.IncrementMemCacheHitCounter("Profiles in Channel")
   486  				}
   487  				result.Data = cacheItem.(map[string]*model.User)
   488  				return
   489  			} else {
   490  				if us.metrics != nil {
   491  					us.metrics.IncrementMemCacheMissCounter("Profiles in Channel")
   492  				}
   493  			}
   494  		} else {
   495  			if us.metrics != nil {
   496  				us.metrics.IncrementMemCacheMissCounter("Profiles in Channel")
   497  			}
   498  		}
   499  
   500  		var users []*model.User
   501  
   502  		query := "SELECT Users.* FROM Users, ChannelMembers WHERE ChannelMembers.ChannelId = :ChannelId AND Users.Id = ChannelMembers.UserId AND Users.DeleteAt = 0"
   503  
   504  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId}); err != nil {
   505  			result.Err = model.NewAppError("SqlUserStore.GetAllProfilesInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   506  		} else {
   507  
   508  			userMap := make(map[string]*model.User)
   509  
   510  			for _, u := range users {
   511  				u.Sanitize(map[string]bool{})
   512  				userMap[u.Id] = u
   513  			}
   514  
   515  			result.Data = userMap
   516  
   517  			if allowFromCache {
   518  				profilesInChannelCache.AddWithExpiresInSecs(channelId, userMap, PROFILES_IN_CHANNEL_CACHE_SEC)
   519  			}
   520  		}
   521  	})
   522  }
   523  
   524  func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) store.StoreChannel {
   525  	return store.Do(func(result *store.StoreResult) {
   526  		var users []*model.User
   527  
   528  		if _, err := us.GetReplica().Select(&users, `
   529              SELECT
   530                  u.*
   531              FROM Users u
   532              INNER JOIN TeamMembers tm
   533                  ON tm.UserId = u.Id
   534                  AND tm.TeamId = :TeamId
   535                  AND tm.DeleteAt = 0
   536              LEFT JOIN ChannelMembers cm
   537                  ON cm.UserId = u.Id
   538                  AND cm.ChannelId = :ChannelId
   539              WHERE cm.UserId IS NULL
   540              ORDER BY u.Username ASC
   541              LIMIT :Limit OFFSET :Offset
   542              `, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   543  			result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   544  		} else {
   545  
   546  			for _, u := range users {
   547  				u.Sanitize(map[string]bool{})
   548  			}
   549  
   550  			result.Data = users
   551  		}
   552  	})
   553  }
   554  
   555  func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreChannel {
   556  	return store.Do(func(result *store.StoreResult) {
   557  		var users []*model.User
   558  
   559  		query := `
   560  		SELECT
   561  			*
   562  		FROM
   563  			Users
   564  		WHERE
   565  			(SELECT
   566  				COUNT(0)
   567  			FROM
   568  				TeamMembers
   569  			WHERE
   570  				TeamMembers.UserId = Users.Id
   571  				AND TeamMembers.DeleteAt = 0) = 0
   572  		ORDER BY
   573  			Username ASC
   574  		LIMIT
   575  			:Limit
   576  		OFFSET
   577  			:Offset`
   578  
   579  		if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   580  			result.Err = model.NewAppError("SqlUserStore.GetProfilesWithoutTeam", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   581  		} else {
   582  
   583  			for _, u := range users {
   584  				u.Sanitize(map[string]bool{})
   585  			}
   586  
   587  			result.Data = users
   588  		}
   589  	})
   590  }
   591  
   592  func (us SqlUserStore) GetProfilesByUsernames(usernames []string, teamId string) store.StoreChannel {
   593  	return store.Do(func(result *store.StoreResult) {
   594  		var users []*model.User
   595  		props := make(map[string]interface{})
   596  		idQuery := ""
   597  
   598  		for index, usernames := range usernames {
   599  			if len(idQuery) > 0 {
   600  				idQuery += ", "
   601  			}
   602  
   603  			props["username"+strconv.Itoa(index)] = usernames
   604  			idQuery += ":username" + strconv.Itoa(index)
   605  		}
   606  
   607  		var query string
   608  		if teamId == "" {
   609  			query = `SELECT * FROM Users WHERE Username IN (` + idQuery + `)`
   610  		} else {
   611  			query = `SELECT Users.* FROM Users INNER JOIN TeamMembers ON
   612  				Users.Id = TeamMembers.UserId AND Users.Username IN (` + idQuery + `) AND TeamMembers.TeamId = :TeamId `
   613  			props["TeamId"] = teamId
   614  		}
   615  
   616  		if _, err := us.GetReplica().Select(&users, query, props); err != nil {
   617  			result.Err = model.NewAppError("SqlUserStore.GetProfilesByUsernames", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   618  		} else {
   619  			result.Data = users
   620  		}
   621  	})
   622  }
   623  
   624  type UserWithLastActivityAt struct {
   625  	model.User
   626  	LastActivityAt int64
   627  }
   628  
   629  func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limit int) store.StoreChannel {
   630  	return store.Do(func(result *store.StoreResult) {
   631  		var users []*UserWithLastActivityAt
   632  
   633  		if _, err := us.GetReplica().Select(&users, `
   634              SELECT
   635                  u.*,
   636                  s.LastActivityAt
   637              FROM Users AS u
   638                  INNER JOIN TeamMembers AS t ON u.Id = t.UserId
   639                  INNER JOIN Status AS s ON s.UserId = t.UserId
   640              WHERE t.TeamId = :TeamId
   641              ORDER BY s.LastActivityAt DESC
   642              LIMIT :Limit OFFSET :Offset
   643              `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
   644  			result.Err = model.NewAppError("SqlUserStore.GetRecentlyActiveUsers", "store.sql_user.get_recently_active_users.app_error", nil, err.Error(), http.StatusInternalServerError)
   645  		} else {
   646  
   647  			userList := []*model.User{}
   648  
   649  			for _, userWithLastActivityAt := range users {
   650  				u := userWithLastActivityAt.User
   651  				u.Sanitize(map[string]bool{})
   652  				u.LastActivityAt = userWithLastActivityAt.LastActivityAt
   653  				userList = append(userList, &u)
   654  			}
   655  
   656  			result.Data = userList
   657  		}
   658  	})
   659  }
   660  
   661  func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) store.StoreChannel {
   662  	return store.Do(func(result *store.StoreResult) {
   663  		var users []*model.User
   664  
   665  		if _, err := us.GetReplica().Select(&users, `
   666              SELECT
   667                  u.*
   668              FROM Users AS u
   669                  INNER JOIN TeamMembers AS t ON u.Id = t.UserId
   670              WHERE t.TeamId = :TeamId
   671              ORDER BY u.CreateAt DESC
   672              LIMIT :Limit OFFSET :Offset
   673              `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
   674  			result.Err = model.NewAppError("SqlUserStore.GetNewUsersForTeam", "store.sql_user.get_new_users.app_error", nil, err.Error(), http.StatusInternalServerError)
   675  		} else {
   676  			for _, u := range users {
   677  				u.Sanitize(map[string]bool{})
   678  			}
   679  
   680  			result.Data = users
   681  		}
   682  	})
   683  }
   684  
   685  func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) store.StoreChannel {
   686  	return store.Do(func(result *store.StoreResult) {
   687  		users := []*model.User{}
   688  		props := make(map[string]interface{})
   689  		idQuery := ""
   690  		remainingUserIds := make([]string, 0)
   691  
   692  		if allowFromCache {
   693  			for _, userId := range userIds {
   694  				if cacheItem, ok := profileByIdsCache.Get(userId); ok {
   695  					u := &model.User{}
   696  					*u = *cacheItem.(*model.User)
   697  					users = append(users, u)
   698  				} else {
   699  					remainingUserIds = append(remainingUserIds, userId)
   700  				}
   701  			}
   702  			if us.metrics != nil {
   703  				us.metrics.AddMemCacheHitCounter("Profile By Ids", float64(len(users)))
   704  				us.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds)))
   705  			}
   706  		} else {
   707  			remainingUserIds = userIds
   708  			if us.metrics != nil {
   709  				us.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds)))
   710  			}
   711  		}
   712  
   713  		// If everything came from the cache then just return
   714  		if len(remainingUserIds) == 0 {
   715  			result.Data = users
   716  			return
   717  		}
   718  
   719  		for index, userId := range remainingUserIds {
   720  			if len(idQuery) > 0 {
   721  				idQuery += ", "
   722  			}
   723  
   724  			props["userId"+strconv.Itoa(index)] = userId
   725  			idQuery += ":userId" + strconv.Itoa(index)
   726  		}
   727  
   728  		if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Users.Id IN ("+idQuery+")", props); err != nil {
   729  			result.Err = model.NewAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   730  		} else {
   731  
   732  			for _, u := range users {
   733  				u.Sanitize(map[string]bool{})
   734  
   735  				cpy := &model.User{}
   736  				*cpy = *u
   737  				profileByIdsCache.AddWithExpiresInSecs(cpy.Id, cpy, PROFILE_BY_IDS_CACHE_SEC)
   738  			}
   739  
   740  			result.Data = users
   741  		}
   742  	})
   743  }
   744  
   745  func (us SqlUserStore) GetSystemAdminProfiles() store.StoreChannel {
   746  	return store.Do(func(result *store.StoreResult) {
   747  		var users []*model.User
   748  
   749  		if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Roles LIKE :Roles", map[string]interface{}{"Roles": "%system_admin%"}); err != nil {
   750  			result.Err = model.NewAppError("SqlUserStore.GetSystemAdminProfiles", "store.sql_user.get_sysadmin_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
   751  		} else {
   752  
   753  			userMap := make(map[string]*model.User)
   754  
   755  			for _, u := range users {
   756  				u.Sanitize(map[string]bool{})
   757  				userMap[u.Id] = u
   758  			}
   759  
   760  			result.Data = userMap
   761  		}
   762  	})
   763  }
   764  
   765  func (us SqlUserStore) GetByEmail(email string) store.StoreChannel {
   766  	return store.Do(func(result *store.StoreResult) {
   767  		email = strings.ToLower(email)
   768  
   769  		user := model.User{}
   770  
   771  		if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Email = :Email", map[string]interface{}{"Email": email}); err != nil {
   772  			result.Err = model.NewAppError("SqlUserStore.GetByEmail", store.MISSING_ACCOUNT_ERROR, nil, "email="+email+", "+err.Error(), http.StatusInternalServerError)
   773  		}
   774  
   775  		result.Data = &user
   776  	})
   777  }
   778  
   779  func (us SqlUserStore) GetByAuth(authData *string, authService string) store.StoreChannel {
   780  	return store.Do(func(result *store.StoreResult) {
   781  		if authData == nil || *authData == "" {
   782  			result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData='', authService="+authService, http.StatusBadRequest)
   783  			return
   784  		}
   785  
   786  		user := model.User{}
   787  
   788  		if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE AuthData = :AuthData AND AuthService = :AuthService", map[string]interface{}{"AuthData": authData, "AuthService": authService}); err != nil {
   789  			if err == sql.ErrNoRows {
   790  				result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData="+*authData+", authService="+authService+", "+err.Error(), http.StatusInternalServerError)
   791  			} else {
   792  				result.Err = model.NewAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authData="+*authData+", authService="+authService+", "+err.Error(), http.StatusInternalServerError)
   793  			}
   794  		}
   795  
   796  		result.Data = &user
   797  	})
   798  }
   799  
   800  func (us SqlUserStore) GetAllUsingAuthService(authService string) store.StoreChannel {
   801  	return store.Do(func(result *store.StoreResult) {
   802  		var data []*model.User
   803  
   804  		if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE AuthService = :AuthService", map[string]interface{}{"AuthService": authService}); err != nil {
   805  			result.Err = model.NewAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authService="+authService+", "+err.Error(), http.StatusInternalServerError)
   806  		}
   807  
   808  		result.Data = data
   809  	})
   810  }
   811  
   812  func (us SqlUserStore) GetByUsername(username string) store.StoreChannel {
   813  	return store.Do(func(result *store.StoreResult) {
   814  		user := model.User{}
   815  
   816  		if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Username = :Username", map[string]interface{}{"Username": username}); err != nil {
   817  			result.Err = model.NewAppError("SqlUserStore.GetByUsername", "store.sql_user.get_by_username.app_error", nil, err.Error(), http.StatusInternalServerError)
   818  		}
   819  
   820  		result.Data = &user
   821  	})
   822  }
   823  
   824  func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail bool) store.StoreChannel {
   825  	return store.Do(func(result *store.StoreResult) {
   826  		params := map[string]interface{}{
   827  			"LoginId":                 loginId,
   828  			"AllowSignInWithUsername": allowSignInWithUsername,
   829  			"AllowSignInWithEmail":    allowSignInWithEmail,
   830  		}
   831  
   832  		users := []*model.User{}
   833  		if _, err := us.GetReplica().Select(
   834  			&users,
   835  			`SELECT
   836  				*
   837  			FROM
   838  				Users
   839  			WHERE
   840  				(:AllowSignInWithUsername AND Username = :LoginId)
   841  				OR (:AllowSignInWithEmail AND Email = :LoginId)`,
   842  			params); err != nil {
   843  			result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, err.Error(), http.StatusInternalServerError)
   844  		} else if len(users) == 1 {
   845  			result.Data = users[0]
   846  		} else if len(users) > 1 {
   847  			result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.multiple_users", nil, "", http.StatusInternalServerError)
   848  		} else {
   849  			result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, "", http.StatusInternalServerError)
   850  		}
   851  	})
   852  }
   853  
   854  func (us SqlUserStore) VerifyEmail(userId string) store.StoreChannel {
   855  	return store.Do(func(result *store.StoreResult) {
   856  		if _, err := us.GetMaster().Exec("UPDATE Users SET EmailVerified = true WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
   857  			result.Err = model.NewAppError("SqlUserStore.VerifyEmail", "store.sql_user.verify_email.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError)
   858  		}
   859  
   860  		result.Data = userId
   861  	})
   862  }
   863  
   864  func (us SqlUserStore) GetTotalUsersCount() store.StoreChannel {
   865  	return store.Do(func(result *store.StoreResult) {
   866  		if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users"); err != nil {
   867  			result.Err = model.NewAppError("SqlUserStore.GetTotalUsersCount", "store.sql_user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   868  		} else {
   869  			result.Data = count
   870  		}
   871  	})
   872  }
   873  
   874  func (us SqlUserStore) PermanentDelete(userId string) store.StoreChannel {
   875  	return store.Do(func(result *store.StoreResult) {
   876  		if _, err := us.GetMaster().Exec("DELETE FROM Users WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
   877  			result.Err = model.NewAppError("SqlUserStore.PermanentDelete", "store.sql_user.permanent_delete.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError)
   878  		}
   879  	})
   880  }
   881  
   882  func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) store.StoreChannel {
   883  	return store.Do(func(result *store.StoreResult) {
   884  		query := ""
   885  		if len(teamId) > 0 {
   886  			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"
   887  		} else {
   888  			query = "SELECT COUNT(DISTINCT Email) FROM Users WHERE DeleteAt = 0"
   889  		}
   890  
   891  		v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId})
   892  		if err != nil {
   893  			result.Err = model.NewAppError("SqlUserStore.AnalyticsUniqueUserCount", "store.sql_user.analytics_unique_user_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   894  		} else {
   895  			result.Data = v
   896  		}
   897  	})
   898  }
   899  
   900  func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64) store.StoreChannel {
   901  	return store.Do(func(result *store.StoreResult) {
   902  		time := model.GetMillis() - timePeriod
   903  
   904  		query := "SELECT COUNT(*) FROM Status WHERE LastActivityAt > :Time"
   905  
   906  		v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"Time": time})
   907  		if err != nil {
   908  			result.Err = model.NewAppError("SqlUserStore.AnalyticsDailyActiveUsers", "store.sql_user.analytics_daily_active_users.app_error", nil, err.Error(), http.StatusInternalServerError)
   909  		} else {
   910  			result.Data = v
   911  		}
   912  	})
   913  }
   914  
   915  func (us SqlUserStore) GetUnreadCount(userId string) store.StoreChannel {
   916  	return store.Do(func(result *store.StoreResult) {
   917  		if count, err := us.GetReplica().SelectInt(`
   918  		SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END)
   919  		FROM Channels c
   920  		INNER JOIN ChannelMembers cm
   921  		      ON cm.ChannelId = c.Id
   922  		      AND cm.UserId = :UserId
   923  		      AND c.DeleteAt = 0`, map[string]interface{}{"UserId": userId}); err != nil {
   924  			result.Err = model.NewAppError("SqlUserStore.GetMentionCount", "store.sql_user.get_unread_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   925  		} else {
   926  			result.Data = count
   927  		}
   928  	})
   929  }
   930  
   931  func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) store.StoreChannel {
   932  	return store.Do(func(result *store.StoreResult) {
   933  		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 {
   934  			result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError)
   935  		} else {
   936  			result.Data = count
   937  		}
   938  	})
   939  }
   940  
   941  func (us SqlUserStore) Search(teamId string, term string, options map[string]bool) store.StoreChannel {
   942  	return store.Do(func(result *store.StoreResult) {
   943  		searchQuery := ""
   944  
   945  		if teamId == "" {
   946  
   947  			// Id != '' is added because both SEARCH_CLAUSE and INACTIVE_CLAUSE start with an AND
   948  			searchQuery = `
   949  			SELECT
   950  				*
   951  			FROM
   952  				Users
   953  			WHERE
   954  				Id != ''
   955  				SEARCH_CLAUSE
   956  				INACTIVE_CLAUSE
   957  				ORDER BY Username ASC
   958  			LIMIT 100`
   959  		} else {
   960  			searchQuery = `
   961  			SELECT
   962  				Users.*
   963  			FROM
   964  				Users, TeamMembers
   965  			WHERE
   966  				TeamMembers.TeamId = :TeamId
   967  				AND Users.Id = TeamMembers.UserId
   968  				AND TeamMembers.DeleteAt = 0
   969  				SEARCH_CLAUSE
   970  				INACTIVE_CLAUSE
   971  				ORDER BY Users.Username ASC
   972  			LIMIT 100`
   973  		}
   974  
   975  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId})
   976  
   977  	})
   978  }
   979  
   980  func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) store.StoreChannel {
   981  	return store.Do(func(result *store.StoreResult) {
   982  		searchQuery := `
   983  		SELECT
   984  			*
   985  		FROM
   986  			Users
   987  		WHERE
   988  			(SELECT
   989  				COUNT(0)
   990  			FROM
   991  				TeamMembers
   992  			WHERE
   993  				TeamMembers.UserId = Users.Id
   994  				AND TeamMembers.DeleteAt = 0) = 0
   995  			SEARCH_CLAUSE
   996  			INACTIVE_CLAUSE
   997  			ORDER BY Username ASC
   998  		LIMIT 100`
   999  
  1000  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{})
  1001  
  1002  	})
  1003  }
  1004  
  1005  func (us SqlUserStore) SearchNotInTeam(notInTeamId 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 Users
  1011  			LEFT JOIN TeamMembers tm
  1012  				ON tm.UserId = Users.Id
  1013  				AND tm.TeamId = :NotInTeamId
  1014  			WHERE
  1015  				(tm.UserId IS NULL OR tm.DeleteAt != 0)
  1016  				SEARCH_CLAUSE
  1017  				INACTIVE_CLAUSE
  1018  			ORDER BY Users.Username ASC
  1019  			LIMIT 100`
  1020  
  1021  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{"NotInTeamId": notInTeamId})
  1022  
  1023  	})
  1024  }
  1025  
  1026  func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) store.StoreChannel {
  1027  	return store.Do(func(result *store.StoreResult) {
  1028  		searchQuery := ""
  1029  		if teamId == "" {
  1030  			searchQuery = `
  1031  			SELECT
  1032  				Users.*
  1033  			FROM Users
  1034  			LEFT JOIN ChannelMembers cm
  1035  				ON cm.UserId = Users.Id
  1036  				AND cm.ChannelId = :ChannelId
  1037  			WHERE
  1038  				cm.UserId IS NULL
  1039  				SEARCH_CLAUSE
  1040  				INACTIVE_CLAUSE
  1041  			ORDER BY Users.Username ASC
  1042  			LIMIT 100`
  1043  		} else {
  1044  			searchQuery = `
  1045  			SELECT
  1046  				Users.*
  1047  			FROM Users
  1048  			INNER JOIN TeamMembers tm
  1049  				ON tm.UserId = Users.Id
  1050  				AND tm.TeamId = :TeamId
  1051  				AND tm.DeleteAt = 0
  1052  			LEFT JOIN ChannelMembers cm
  1053  				ON cm.UserId = Users.Id
  1054  				AND cm.ChannelId = :ChannelId
  1055  			WHERE
  1056  				cm.UserId IS NULL
  1057  				SEARCH_CLAUSE
  1058  				INACTIVE_CLAUSE
  1059  			ORDER BY Users.Username ASC
  1060  			LIMIT 100`
  1061  		}
  1062  
  1063  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId})
  1064  
  1065  	})
  1066  }
  1067  
  1068  func (us SqlUserStore) SearchInChannel(channelId string, term string, options map[string]bool) store.StoreChannel {
  1069  	return store.Do(func(result *store.StoreResult) {
  1070  		searchQuery := `
  1071          SELECT
  1072              Users.*
  1073          FROM
  1074              Users, ChannelMembers
  1075          WHERE
  1076              ChannelMembers.ChannelId = :ChannelId
  1077              AND ChannelMembers.UserId = Users.Id
  1078              SEARCH_CLAUSE
  1079              INACTIVE_CLAUSE
  1080              ORDER BY Users.Username ASC
  1081          LIMIT 100`
  1082  
  1083  		*result = us.performSearch(searchQuery, term, options, map[string]interface{}{"ChannelId": channelId})
  1084  
  1085  	})
  1086  }
  1087  
  1088  var escapeLikeSearchChar = []string{
  1089  	"%",
  1090  	"_",
  1091  }
  1092  
  1093  var ignoreLikeSearchChar = []string{
  1094  	"*",
  1095  }
  1096  
  1097  var spaceFulltextSearchChar = []string{
  1098  	"<",
  1099  	">",
  1100  	"+",
  1101  	"-",
  1102  	"(",
  1103  	")",
  1104  	"~",
  1105  	":",
  1106  	"*",
  1107  	"\"",
  1108  	"!",
  1109  	"@",
  1110  }
  1111  
  1112  func generateSearchQuery(searchQuery string, terms []string, fields []string, parameters map[string]interface{}, isPostgreSQL bool) string {
  1113  	searchTerms := []string{}
  1114  	for i, term := range terms {
  1115  		searchFields := []string{}
  1116  		for _, field := range fields {
  1117  			if isPostgreSQL {
  1118  				searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*' ", field, fmt.Sprintf(":Term%d", i)))
  1119  			} else {
  1120  				searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*' ", field, fmt.Sprintf(":Term%d", i)))
  1121  			}
  1122  		}
  1123  		searchTerms = append(searchTerms, fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")))
  1124  		parameters[fmt.Sprintf("Term%d", i)] = fmt.Sprintf("%s%%", term)
  1125  	}
  1126  
  1127  	searchClause := strings.Join(searchTerms, " AND ")
  1128  	return strings.Replace(searchQuery, "SEARCH_CLAUSE", fmt.Sprintf(" AND %s ", searchClause), 1)
  1129  }
  1130  
  1131  func (us SqlUserStore) performSearch(searchQuery string, term string, options map[string]bool, parameters map[string]interface{}) store.StoreResult {
  1132  	result := store.StoreResult{}
  1133  
  1134  	// These chars must be removed from the like query.
  1135  	for _, c := range ignoreLikeSearchChar {
  1136  		term = strings.Replace(term, c, "", -1)
  1137  	}
  1138  
  1139  	// These chars must be escaped in the like query.
  1140  	for _, c := range escapeLikeSearchChar {
  1141  		term = strings.Replace(term, c, "*"+c, -1)
  1142  	}
  1143  
  1144  	searchType := USER_SEARCH_TYPE_ALL
  1145  	if ok := options[store.USER_SEARCH_OPTION_NAMES_ONLY]; ok {
  1146  		searchType = USER_SEARCH_TYPE_NAMES
  1147  	} else if ok = options[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME]; ok {
  1148  		searchType = USER_SEARCH_TYPE_NAMES_NO_FULL_NAME
  1149  	} else if ok = options[store.USER_SEARCH_OPTION_ALL_NO_FULL_NAME]; ok {
  1150  		searchType = USER_SEARCH_TYPE_ALL_NO_FULL_NAME
  1151  	}
  1152  
  1153  	if ok := options[store.USER_SEARCH_OPTION_ALLOW_INACTIVE]; ok {
  1154  		searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "", 1)
  1155  	} else {
  1156  		searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "AND Users.DeleteAt = 0", 1)
  1157  	}
  1158  
  1159  	if strings.TrimSpace(term) == "" {
  1160  		searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1)
  1161  	} else {
  1162  		isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES
  1163  		searchQuery = generateSearchQuery(searchQuery, strings.Fields(term), searchType, parameters, isPostgreSQL)
  1164  	}
  1165  
  1166  	var users []*model.User
  1167  
  1168  	if _, err := us.GetReplica().Select(&users, searchQuery, parameters); err != nil {
  1169  		result.Err = model.NewAppError("SqlUserStore.Search", "store.sql_user.search.app_error", nil,
  1170  			fmt.Sprintf("term=%v, search_type=%v, %v", term, searchType, err.Error()), http.StatusInternalServerError)
  1171  	} else {
  1172  		for _, u := range users {
  1173  			u.Sanitize(map[string]bool{})
  1174  		}
  1175  
  1176  		result.Data = users
  1177  	}
  1178  
  1179  	return result
  1180  }
  1181  
  1182  func (us SqlUserStore) AnalyticsGetInactiveUsersCount() store.StoreChannel {
  1183  	return store.Do(func(result *store.StoreResult) {
  1184  		if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0"); err != nil {
  1185  			result.Err = model.NewAppError("SqlUserStore.AnalyticsGetInactiveUsersCount", "store.sql_user.analytics_get_inactive_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
  1186  		} else {
  1187  			result.Data = count
  1188  		}
  1189  	})
  1190  }
  1191  
  1192  func (us SqlUserStore) AnalyticsGetSystemAdminCount() store.StoreChannel {
  1193  	return store.Do(func(result *store.StoreResult) {
  1194  		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 {
  1195  			result.Err = model.NewAppError("SqlUserStore.AnalyticsGetSystemAdminCount", "store.sql_user.analytics_get_system_admin_count.app_error", nil, err.Error(), http.StatusInternalServerError)
  1196  		} else {
  1197  			result.Data = count
  1198  		}
  1199  	})
  1200  }
  1201  
  1202  func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int) store.StoreChannel {
  1203  	return store.Do(func(result *store.StoreResult) {
  1204  		var users []*model.User
  1205  
  1206  		if _, err := us.GetReplica().Select(&users, `
  1207              SELECT
  1208                  u.*
  1209              FROM Users u
  1210              LEFT JOIN TeamMembers tm
  1211                  ON tm.UserId = u.Id
  1212                  AND tm.TeamId = :TeamId
  1213                  AND tm.DeleteAt = 0
  1214              WHERE tm.UserId IS NULL
  1215              ORDER BY u.Username ASC
  1216              LIMIT :Limit OFFSET :Offset
  1217              `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
  1218  			result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInTeam", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
  1219  		} else {
  1220  
  1221  			for _, u := range users {
  1222  				u.Sanitize(map[string]bool{})
  1223  			}
  1224  
  1225  			result.Data = users
  1226  		}
  1227  	})
  1228  }
  1229  
  1230  func (us SqlUserStore) GetEtagForProfilesNotInTeam(teamId string) store.StoreChannel {
  1231  	return store.Do(func(result *store.StoreResult) {
  1232  		updateAt, err := us.GetReplica().SelectInt(`
  1233              SELECT
  1234                  u.UpdateAt
  1235              FROM Users u
  1236              LEFT JOIN TeamMembers tm
  1237                  ON tm.UserId = u.Id
  1238                  AND tm.TeamId = :TeamId
  1239                  AND tm.DeleteAt = 0
  1240              WHERE tm.UserId IS NULL
  1241              ORDER BY u.UpdateAt DESC
  1242              LIMIT 1
  1243              `, map[string]interface{}{"TeamId": teamId})
  1244  
  1245  		if err != nil {
  1246  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
  1247  		} else {
  1248  			result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
  1249  		}
  1250  	})
  1251  }
  1252  
  1253  func (us SqlUserStore) ClearAllCustomRoleAssignments() store.StoreChannel {
  1254  	return store.Do(func(result *store.StoreResult) {
  1255  		builtInRoles := model.MakeDefaultRoles()
  1256  		lastUserId := strings.Repeat("0", 26)
  1257  
  1258  		for true {
  1259  			var transaction *gorp.Transaction
  1260  			var err error
  1261  
  1262  			if transaction, err = us.GetMaster().Begin(); err != nil {
  1263  				result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
  1264  				return
  1265  			}
  1266  
  1267  			var users []*model.User
  1268  			if _, err := transaction.Select(&users, "SELECT * from Users WHERE Id > :Id ORDER BY Id LIMIT 1000", map[string]interface{}{"Id": lastUserId}); err != nil {
  1269  				if err2 := transaction.Rollback(); err2 != nil {
  1270  					result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
  1271  					return
  1272  				}
  1273  				result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.select.app_error", nil, err.Error(), http.StatusInternalServerError)
  1274  				return
  1275  			}
  1276  
  1277  			if len(users) == 0 {
  1278  				break
  1279  			}
  1280  
  1281  			for _, user := range users {
  1282  				lastUserId = user.Id
  1283  
  1284  				var newRoles []string
  1285  
  1286  				for _, role := range strings.Fields(user.Roles) {
  1287  					for name := range builtInRoles {
  1288  						if name == role {
  1289  							newRoles = append(newRoles, role)
  1290  							break
  1291  						}
  1292  					}
  1293  				}
  1294  
  1295  				newRolesString := strings.Join(newRoles, " ")
  1296  				if newRolesString != user.Roles {
  1297  					if _, err := transaction.Exec("UPDATE Users SET Roles = :Roles WHERE Id = :Id", map[string]interface{}{"Roles": newRolesString, "Id": user.Id}); err != nil {
  1298  						if err2 := transaction.Rollback(); err2 != nil {
  1299  							result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
  1300  							return
  1301  						}
  1302  						result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.update.app_error", nil, err.Error(), http.StatusInternalServerError)
  1303  						return
  1304  					}
  1305  				}
  1306  			}
  1307  
  1308  			if err := transaction.Commit(); err != nil {
  1309  				if err2 := transaction.Rollback(); err2 != nil {
  1310  					result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
  1311  					return
  1312  				}
  1313  				result.Err = model.NewAppError("SqlUserStore.ClearAllCustomRoleAssignments", "store.sql_user.clear_all_custom_role_assignments.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
  1314  				return
  1315  			}
  1316  		}
  1317  	})
  1318  }
  1319  
  1320  func (us SqlUserStore) InferSystemInstallDate() store.StoreChannel {
  1321  	return store.Do(func(result *store.StoreResult) {
  1322  		createAt, err := us.GetReplica().SelectInt("SELECT CreateAt FROM Users WHERE CreateAt IS NOT NULL ORDER BY CreateAt ASC LIMIT 1")
  1323  		if err != nil {
  1324  			result.Err = model.NewAppError("SqlUserStore.GetSystemInstallDate", "store.sql_user.get_system_install_date.app_error", nil, err.Error(), http.StatusInternalServerError)
  1325  			return
  1326  		}
  1327  		result.Data = createAt
  1328  	})
  1329  }