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