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