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