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