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