github.com/keys-pub/mattermost-server@v4.10.10+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/mattermost-server/einterfaces" 14 "github.com/mattermost/mattermost-server/model" 15 "github.com/mattermost/mattermost-server/store" 16 "github.com/mattermost/mattermost-server/utils" 17 ) 18 19 const ( 20 PROFILES_IN_CHANNEL_CACHE_SIZE = model.CHANNEL_CACHE_SIZE 21 PROFILES_IN_CHANNEL_CACHE_SEC = 900 // 15 mins 22 PROFILE_BY_IDS_CACHE_SIZE = model.SESSION_CACHE_SIZE 23 PROFILE_BY_IDS_CACHE_SEC = 900 // 15 mins 24 ) 25 26 var ( 27 USER_SEARCH_TYPE_NAMES_NO_FULL_NAME = []string{"Username", "Nickname"} 28 USER_SEARCH_TYPE_NAMES = []string{"Username", "FirstName", "LastName", "Nickname"} 29 USER_SEARCH_TYPE_ALL_NO_FULL_NAME = []string{"Username", "Nickname", "Email"} 30 USER_SEARCH_TYPE_ALL = []string{"Username", "FirstName", "LastName", "Nickname", "Email"} 31 ) 32 33 type SqlUserStore struct { 34 SqlStore 35 metrics einterfaces.MetricsInterface 36 } 37 38 var profilesInChannelCache *utils.Cache = utils.NewLru(PROFILES_IN_CHANNEL_CACHE_SIZE) 39 var profileByIdsCache *utils.Cache = utils.NewLru(PROFILE_BY_IDS_CACHE_SIZE) 40 41 func (us SqlUserStore) ClearCaches() { 42 profilesInChannelCache.Purge() 43 profileByIdsCache.Purge() 44 45 if us.metrics != nil { 46 us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Purge") 47 us.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Purge") 48 } 49 } 50 51 func (us SqlUserStore) InvalidatProfileCacheForUser(userId string) { 52 profileByIdsCache.Remove(userId) 53 54 if us.metrics != nil { 55 us.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Remove") 56 } 57 } 58 59 func NewSqlUserStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.UserStore { 60 us := &SqlUserStore{ 61 SqlStore: sqlStore, 62 metrics: metrics, 63 } 64 65 for _, db := range sqlStore.GetAllConns() { 66 table := db.AddTableWithName(model.User{}, "Users").SetKeys(false, "Id") 67 table.ColMap("Id").SetMaxSize(26) 68 table.ColMap("Username").SetMaxSize(64).SetUnique(true) 69 table.ColMap("Password").SetMaxSize(128) 70 table.ColMap("AuthData").SetMaxSize(128).SetUnique(true) 71 table.ColMap("AuthService").SetMaxSize(32) 72 table.ColMap("Email").SetMaxSize(128).SetUnique(true) 73 table.ColMap("Nickname").SetMaxSize(64) 74 table.ColMap("FirstName").SetMaxSize(64) 75 table.ColMap("LastName").SetMaxSize(64) 76 table.ColMap("Roles").SetMaxSize(256) 77 table.ColMap("Props").SetMaxSize(4000) 78 table.ColMap("NotifyProps").SetMaxSize(2000) 79 table.ColMap("Locale").SetMaxSize(5) 80 table.ColMap("MfaSecret").SetMaxSize(128) 81 table.ColMap("Position").SetMaxSize(128) 82 table.ColMap("Timezone").SetMaxSize(256) 83 } 84 85 return us 86 } 87 88 func (us SqlUserStore) CreateIndexesIfNotExists() { 89 us.CreateIndexIfNotExists("idx_users_email", "Users", "Email") 90 us.CreateIndexIfNotExists("idx_users_update_at", "Users", "UpdateAt") 91 us.CreateIndexIfNotExists("idx_users_create_at", "Users", "CreateAt") 92 us.CreateIndexIfNotExists("idx_users_delete_at", "Users", "DeleteAt") 93 94 if us.DriverName() == model.DATABASE_DRIVER_POSTGRES { 95 us.CreateIndexIfNotExists("idx_users_email_lower", "Users", "lower(Email)") 96 us.CreateIndexIfNotExists("idx_users_username_lower", "Users", "lower(Username)") 97 us.CreateIndexIfNotExists("idx_users_nickname_lower", "Users", "lower(Nickname)") 98 us.CreateIndexIfNotExists("idx_users_firstname_lower", "Users", "lower(FirstName)") 99 us.CreateIndexIfNotExists("idx_users_lastname_lower", "Users", "lower(LastName)") 100 } 101 102 us.CreateFullTextIndexIfNotExists("idx_users_all_txt", "Users", strings.Join(USER_SEARCH_TYPE_ALL, ", ")) 103 us.CreateFullTextIndexIfNotExists("idx_users_all_no_full_name_txt", "Users", strings.Join(USER_SEARCH_TYPE_ALL_NO_FULL_NAME, ", ")) 104 us.CreateFullTextIndexIfNotExists("idx_users_names_txt", "Users", strings.Join(USER_SEARCH_TYPE_NAMES, ", ")) 105 us.CreateFullTextIndexIfNotExists("idx_users_names_no_full_name_txt", "Users", strings.Join(USER_SEARCH_TYPE_NAMES_NO_FULL_NAME, ", ")) 106 } 107 108 func (us SqlUserStore) Save(user *model.User) store.StoreChannel { 109 return store.Do(func(result *store.StoreResult) { 110 if len(user.Id) > 0 { 111 result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.existing.app_error", nil, "user_id="+user.Id, http.StatusBadRequest) 112 return 113 } 114 115 user.PreSave() 116 if result.Err = user.IsValid(); result.Err != nil { 117 return 118 } 119 120 if err := us.GetMaster().Insert(user); err != nil { 121 if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) { 122 result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.email_exists.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest) 123 } else if IsUniqueConstraintError(err, []string{"Username", "users_username_key", "idx_users_username_unique"}) { 124 result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.username_exists.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest) 125 } else { 126 result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusInternalServerError) 127 } 128 } else { 129 result.Data = user 130 } 131 }) 132 } 133 134 func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) store.StoreChannel { 135 return store.Do(func(result *store.StoreResult) { 136 user.PreUpdate() 137 138 if result.Err = user.IsValid(); result.Err != nil { 139 return 140 } 141 142 if oldUserResult, err := us.GetMaster().Get(model.User{}, user.Id); err != nil { 143 result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.finding.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusInternalServerError) 144 } else if oldUserResult == nil { 145 result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.find.app_error", nil, "user_id="+user.Id, http.StatusBadRequest) 146 } else { 147 oldUser := oldUserResult.(*model.User) 148 user.CreateAt = oldUser.CreateAt 149 user.AuthData = oldUser.AuthData 150 user.AuthService = oldUser.AuthService 151 user.Password = oldUser.Password 152 user.LastPasswordUpdate = oldUser.LastPasswordUpdate 153 user.LastPictureUpdate = oldUser.LastPictureUpdate 154 user.EmailVerified = oldUser.EmailVerified 155 user.FailedAttempts = oldUser.FailedAttempts 156 user.MfaSecret = oldUser.MfaSecret 157 user.MfaActive = oldUser.MfaActive 158 159 if !trustedUpdateData { 160 user.Roles = oldUser.Roles 161 user.DeleteAt = oldUser.DeleteAt 162 } 163 164 if user.IsOAuthUser() { 165 if !trustedUpdateData { 166 user.Email = oldUser.Email 167 } 168 } else if user.IsLDAPUser() && !trustedUpdateData { 169 if user.Username != oldUser.Username || 170 user.Email != oldUser.Email { 171 result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.can_not_change_ldap.app_error", nil, "user_id="+user.Id, http.StatusBadRequest) 172 return 173 } 174 } else if user.Email != oldUser.Email { 175 user.EmailVerified = false 176 } 177 178 if user.Username != oldUser.Username { 179 user.UpdateMentionKeysFromUsername(oldUser.Username) 180 } 181 182 if count, err := us.GetMaster().Update(user); err != nil { 183 if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) { 184 result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.email_taken.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest) 185 } else if IsUniqueConstraintError(err, []string{"Username", "users_username_key", "idx_users_username_unique"}) { 186 result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.username_taken.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusBadRequest) 187 } else { 188 result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.updating.app_error", nil, "user_id="+user.Id+", "+err.Error(), http.StatusInternalServerError) 189 } 190 } else if count != 1 { 191 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) 192 } else { 193 user.Sanitize(map[string]bool{}) 194 oldUser.Sanitize(map[string]bool{}) 195 result.Data = [2]*model.User{user, oldUser} 196 } 197 } 198 }) 199 } 200 201 func (us SqlUserStore) UpdateLastPictureUpdate(userId string) store.StoreChannel { 202 return store.Do(func(result *store.StoreResult) { 203 curTime := model.GetMillis() 204 205 if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { 206 result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_last_picture_update.app_error", nil, "user_id="+userId, http.StatusInternalServerError) 207 } else { 208 result.Data = userId 209 } 210 }) 211 } 212 213 func (us SqlUserStore) UpdateUpdateAt(userId string) store.StoreChannel { 214 return store.Do(func(result *store.StoreResult) { 215 curTime := model.GetMillis() 216 217 if _, err := us.GetMaster().Exec("UPDATE Users SET UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { 218 result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_update.app_error", nil, "user_id="+userId, http.StatusInternalServerError) 219 } else { 220 result.Data = userId 221 } 222 }) 223 } 224 225 func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) store.StoreChannel { 226 return store.Do(func(result *store.StoreResult) { 227 updateAt := model.GetMillis() 228 229 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 { 230 result.Err = model.NewAppError("SqlUserStore.UpdatePassword", "store.sql_user.update_password.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError) 231 } else { 232 result.Data = userId 233 } 234 }) 235 } 236 237 func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int) store.StoreChannel { 238 return store.Do(func(result *store.StoreResult) { 239 if _, err := us.GetMaster().Exec("UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId", map[string]interface{}{"FailedAttempts": attempts, "UserId": userId}); err != nil { 240 result.Err = model.NewAppError("SqlUserStore.UpdateFailedPasswordAttempts", "store.sql_user.update_failed_pwd_attempts.app_error", nil, "user_id="+userId, http.StatusInternalServerError) 241 } else { 242 result.Data = userId 243 } 244 }) 245 } 246 247 func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *string, email string, resetMfa bool) store.StoreChannel { 248 return store.Do(func(result *store.StoreResult) { 249 email = strings.ToLower(email) 250 251 updateAt := model.GetMillis() 252 253 query := ` 254 UPDATE 255 Users 256 SET 257 Password = '', 258 LastPasswordUpdate = :LastPasswordUpdate, 259 UpdateAt = :UpdateAt, 260 FailedAttempts = 0, 261 AuthService = :AuthService, 262 AuthData = :AuthData` 263 264 if len(email) != 0 { 265 query += ", Email = :Email" 266 } 267 268 if resetMfa { 269 query += ", MfaActive = false, MfaSecret = ''" 270 } 271 272 query += " WHERE Id = :UserId" 273 274 if _, err := us.GetMaster().Exec(query, map[string]interface{}{"LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId, "AuthService": service, "AuthData": authData, "Email": email}); err != nil { 275 if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique", "AuthData", "users_authdata_key"}) { 276 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) 277 } else { 278 result.Err = model.NewAppError("SqlUserStore.UpdateAuthData", "store.sql_user.update_auth_data.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError) 279 } 280 } else { 281 result.Data = userId 282 } 283 }) 284 } 285 286 func (us SqlUserStore) UpdateMfaSecret(userId, secret string) store.StoreChannel { 287 return store.Do(func(result *store.StoreResult) { 288 updateAt := model.GetMillis() 289 290 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 { 291 result.Err = model.NewAppError("SqlUserStore.UpdateMfaSecret", "store.sql_user.update_mfa_secret.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError) 292 } else { 293 result.Data = userId 294 } 295 }) 296 } 297 298 func (us SqlUserStore) UpdateMfaActive(userId string, active bool) store.StoreChannel { 299 return store.Do(func(result *store.StoreResult) { 300 updateAt := model.GetMillis() 301 302 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 { 303 result.Err = model.NewAppError("SqlUserStore.UpdateMfaActive", "store.sql_user.update_mfa_active.app_error", nil, "id="+userId+", "+err.Error(), http.StatusInternalServerError) 304 } else { 305 result.Data = userId 306 } 307 }) 308 } 309 310 func (us SqlUserStore) Get(id string) store.StoreChannel { 311 return store.Do(func(result *store.StoreResult) { 312 if obj, err := us.GetReplica().Get(model.User{}, id); err != nil { 313 result.Err = model.NewAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, "user_id="+id+", "+err.Error(), http.StatusInternalServerError) 314 } else if obj == nil { 315 result.Err = model.NewAppError("SqlUserStore.Get", store.MISSING_ACCOUNT_ERROR, nil, "user_id="+id, http.StatusNotFound) 316 } else { 317 result.Data = obj.(*model.User) 318 } 319 }) 320 } 321 322 func (us SqlUserStore) GetAll() store.StoreChannel { 323 return store.Do(func(result *store.StoreResult) { 324 var data []*model.User 325 if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users"); err != nil { 326 result.Err = model.NewAppError("SqlUserStore.GetAll", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError) 327 } 328 329 result.Data = data 330 }) 331 } 332 333 func (s SqlUserStore) GetEtagForAllProfiles() store.StoreChannel { 334 return store.Do(func(result *store.StoreResult) { 335 updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1") 336 if err != nil { 337 result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) 338 } else { 339 result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt) 340 } 341 }) 342 } 343 344 func (us SqlUserStore) GetAllProfiles(offset int, limit int) store.StoreChannel { 345 return store.Do(func(result *store.StoreResult) { 346 var users []*model.User 347 348 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 { 349 result.Err = model.NewAppError("SqlUserStore.GetAllProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 350 } else { 351 352 for _, u := range users { 353 u.Sanitize(map[string]bool{}) 354 } 355 356 result.Data = users 357 } 358 }) 359 } 360 361 func (s SqlUserStore) GetEtagForProfiles(teamId string) store.StoreChannel { 362 return store.Do(func(result *store.StoreResult) { 363 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}) 364 if err != nil { 365 result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) 366 } else { 367 result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt) 368 } 369 }) 370 } 371 372 func (us SqlUserStore) GetProfiles(teamId string, offset int, limit int) store.StoreChannel { 373 return store.Do(func(result *store.StoreResult) { 374 var users []*model.User 375 376 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 { 377 result.Err = model.NewAppError("SqlUserStore.GetProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 378 } else { 379 380 for _, u := range users { 381 u.Sanitize(map[string]bool{}) 382 } 383 384 result.Data = users 385 } 386 }) 387 } 388 389 func (us SqlUserStore) InvalidateProfilesInChannelCacheByUser(userId string) { 390 keys := profilesInChannelCache.Keys() 391 392 for _, key := range keys { 393 if cacheItem, ok := profilesInChannelCache.Get(key); ok { 394 userMap := cacheItem.(map[string]*model.User) 395 if _, userInCache := userMap[userId]; userInCache { 396 profilesInChannelCache.Remove(key) 397 if us.metrics != nil { 398 us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User") 399 } 400 } 401 } 402 } 403 } 404 405 func (us SqlUserStore) InvalidateProfilesInChannelCache(channelId string) { 406 profilesInChannelCache.Remove(channelId) 407 if us.metrics != nil { 408 us.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by Channel") 409 } 410 } 411 412 func (us SqlUserStore) GetProfilesInChannel(channelId string, offset int, limit int) store.StoreChannel { 413 return store.Do(func(result *store.StoreResult) { 414 var users []*model.User 415 416 query := ` 417 SELECT 418 Users.* 419 FROM 420 Users, ChannelMembers 421 WHERE 422 ChannelMembers.ChannelId = :ChannelId 423 AND Users.Id = ChannelMembers.UserId 424 ORDER BY 425 Users.Username ASC 426 LIMIT :Limit OFFSET :Offset 427 ` 428 429 if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil { 430 result.Err = model.NewAppError("SqlUserStore.GetProfilesInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 431 } else { 432 433 for _, u := range users { 434 u.Sanitize(map[string]bool{}) 435 } 436 437 result.Data = users 438 } 439 }) 440 } 441 442 func (us SqlUserStore) GetProfilesInChannelByStatus(channelId string, offset int, limit int) store.StoreChannel { 443 return store.Do(func(result *store.StoreResult) { 444 var users []*model.User 445 446 query := ` 447 SELECT 448 Users.* 449 FROM Users 450 INNER JOIN ChannelMembers ON Users.Id = ChannelMembers.UserId 451 LEFT JOIN Status ON Users.Id = Status.UserId 452 WHERE 453 ChannelMembers.ChannelId = :ChannelId 454 ORDER BY 455 CASE Status 456 WHEN 'online' THEN 1 457 WHEN 'away' THEN 2 458 WHEN 'dnd' THEN 3 459 ELSE 4 460 END, 461 Users.Username ASC 462 LIMIT :Limit OFFSET :Offset 463 ` 464 465 if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil { 466 result.Err = model.NewAppError("SqlUserStore.GetProfilesInChannelByStatus", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 467 } else { 468 469 for _, u := range users { 470 u.Sanitize(map[string]bool{}) 471 } 472 473 result.Data = users 474 } 475 }) 476 } 477 478 func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) store.StoreChannel { 479 return store.Do(func(result *store.StoreResult) { 480 if allowFromCache { 481 if cacheItem, ok := profilesInChannelCache.Get(channelId); ok { 482 if us.metrics != nil { 483 us.metrics.IncrementMemCacheHitCounter("Profiles in Channel") 484 } 485 result.Data = cacheItem.(map[string]*model.User) 486 return 487 } else { 488 if us.metrics != nil { 489 us.metrics.IncrementMemCacheMissCounter("Profiles in Channel") 490 } 491 } 492 } else { 493 if us.metrics != nil { 494 us.metrics.IncrementMemCacheMissCounter("Profiles in Channel") 495 } 496 } 497 498 var users []*model.User 499 500 query := "SELECT Users.* FROM Users, ChannelMembers WHERE ChannelMembers.ChannelId = :ChannelId AND Users.Id = ChannelMembers.UserId AND Users.DeleteAt = 0" 501 502 if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"ChannelId": channelId}); err != nil { 503 result.Err = model.NewAppError("SqlUserStore.GetAllProfilesInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 504 } else { 505 506 userMap := make(map[string]*model.User) 507 508 for _, u := range users { 509 u.Sanitize(map[string]bool{}) 510 userMap[u.Id] = u 511 } 512 513 result.Data = userMap 514 515 if allowFromCache { 516 profilesInChannelCache.AddWithExpiresInSecs(channelId, userMap, PROFILES_IN_CHANNEL_CACHE_SEC) 517 } 518 } 519 }) 520 } 521 522 func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) store.StoreChannel { 523 return store.Do(func(result *store.StoreResult) { 524 var users []*model.User 525 526 if _, err := us.GetReplica().Select(&users, ` 527 SELECT 528 u.* 529 FROM Users u 530 INNER JOIN TeamMembers tm 531 ON tm.UserId = u.Id 532 AND tm.TeamId = :TeamId 533 AND tm.DeleteAt = 0 534 LEFT JOIN ChannelMembers cm 535 ON cm.UserId = u.Id 536 AND cm.ChannelId = :ChannelId 537 WHERE cm.UserId IS NULL 538 ORDER BY u.Username ASC 539 LIMIT :Limit OFFSET :Offset 540 `, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil { 541 result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInChannel", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 542 } else { 543 544 for _, u := range users { 545 u.Sanitize(map[string]bool{}) 546 } 547 548 result.Data = users 549 } 550 }) 551 } 552 553 func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreChannel { 554 return store.Do(func(result *store.StoreResult) { 555 var users []*model.User 556 557 query := ` 558 SELECT 559 * 560 FROM 561 Users 562 WHERE 563 (SELECT 564 COUNT(0) 565 FROM 566 TeamMembers 567 WHERE 568 TeamMembers.UserId = Users.Id 569 AND TeamMembers.DeleteAt = 0) = 0 570 ORDER BY 571 Username ASC 572 LIMIT 573 :Limit 574 OFFSET 575 :Offset` 576 577 if _, err := us.GetReplica().Select(&users, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil { 578 result.Err = model.NewAppError("SqlUserStore.GetProfilesWithoutTeam", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 579 } else { 580 581 for _, u := range users { 582 u.Sanitize(map[string]bool{}) 583 } 584 585 result.Data = users 586 } 587 }) 588 } 589 590 func (us SqlUserStore) GetProfilesByUsernames(usernames []string, teamId string) store.StoreChannel { 591 return store.Do(func(result *store.StoreResult) { 592 var users []*model.User 593 props := make(map[string]interface{}) 594 idQuery := "" 595 596 for index, usernames := range usernames { 597 if len(idQuery) > 0 { 598 idQuery += ", " 599 } 600 601 props["username"+strconv.Itoa(index)] = usernames 602 idQuery += ":username" + strconv.Itoa(index) 603 } 604 605 var query string 606 if teamId == "" { 607 query = `SELECT * FROM Users WHERE Username IN (` + idQuery + `)` 608 } else { 609 query = `SELECT Users.* FROM Users INNER JOIN TeamMembers ON 610 Users.Id = TeamMembers.UserId AND Users.Username IN (` + idQuery + `) AND TeamMembers.TeamId = :TeamId ` 611 props["TeamId"] = teamId 612 } 613 614 if _, err := us.GetReplica().Select(&users, query, props); err != nil { 615 result.Err = model.NewAppError("SqlUserStore.GetProfilesByUsernames", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 616 } else { 617 result.Data = users 618 } 619 }) 620 } 621 622 type UserWithLastActivityAt struct { 623 model.User 624 LastActivityAt int64 625 } 626 627 func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limit int) store.StoreChannel { 628 return store.Do(func(result *store.StoreResult) { 629 var users []*UserWithLastActivityAt 630 631 if _, err := us.GetReplica().Select(&users, ` 632 SELECT 633 u.*, 634 s.LastActivityAt 635 FROM Users AS u 636 INNER JOIN TeamMembers AS t ON u.Id = t.UserId 637 INNER JOIN Status AS s ON s.UserId = t.UserId 638 WHERE t.TeamId = :TeamId 639 ORDER BY s.LastActivityAt DESC 640 LIMIT :Limit OFFSET :Offset 641 `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil { 642 result.Err = model.NewAppError("SqlUserStore.GetRecentlyActiveUsers", "store.sql_user.get_recently_active_users.app_error", nil, err.Error(), http.StatusInternalServerError) 643 } else { 644 645 userList := []*model.User{} 646 647 for _, userWithLastActivityAt := range users { 648 u := userWithLastActivityAt.User 649 u.Sanitize(map[string]bool{}) 650 u.LastActivityAt = userWithLastActivityAt.LastActivityAt 651 userList = append(userList, &u) 652 } 653 654 result.Data = userList 655 } 656 }) 657 } 658 659 func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) store.StoreChannel { 660 return store.Do(func(result *store.StoreResult) { 661 var users []*model.User 662 663 if _, err := us.GetReplica().Select(&users, ` 664 SELECT 665 u.* 666 FROM Users AS u 667 INNER JOIN TeamMembers AS t ON u.Id = t.UserId 668 WHERE t.TeamId = :TeamId 669 ORDER BY u.CreateAt DESC 670 LIMIT :Limit OFFSET :Offset 671 `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil { 672 result.Err = model.NewAppError("SqlUserStore.GetNewUsersForTeam", "store.sql_user.get_new_users.app_error", nil, err.Error(), http.StatusInternalServerError) 673 } else { 674 for _, u := range users { 675 u.Sanitize(map[string]bool{}) 676 } 677 678 result.Data = users 679 } 680 }) 681 } 682 683 func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) store.StoreChannel { 684 return store.Do(func(result *store.StoreResult) { 685 users := []*model.User{} 686 props := make(map[string]interface{}) 687 idQuery := "" 688 remainingUserIds := make([]string, 0) 689 690 if allowFromCache { 691 for _, userId := range userIds { 692 if cacheItem, ok := profileByIdsCache.Get(userId); ok { 693 u := &model.User{} 694 *u = *cacheItem.(*model.User) 695 users = append(users, u) 696 } else { 697 remainingUserIds = append(remainingUserIds, userId) 698 } 699 } 700 if us.metrics != nil { 701 us.metrics.AddMemCacheHitCounter("Profile By Ids", float64(len(users))) 702 us.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds))) 703 } 704 } else { 705 remainingUserIds = userIds 706 if us.metrics != nil { 707 us.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds))) 708 } 709 } 710 711 // If everything came from the cache then just return 712 if len(remainingUserIds) == 0 { 713 result.Data = users 714 return 715 } 716 717 for index, userId := range remainingUserIds { 718 if len(idQuery) > 0 { 719 idQuery += ", " 720 } 721 722 props["userId"+strconv.Itoa(index)] = userId 723 idQuery += ":userId" + strconv.Itoa(index) 724 } 725 726 if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Users.Id IN ("+idQuery+")", props); err != nil { 727 result.Err = model.NewAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 728 } else { 729 730 for _, u := range users { 731 u.Sanitize(map[string]bool{}) 732 733 cpy := &model.User{} 734 *cpy = *u 735 profileByIdsCache.AddWithExpiresInSecs(cpy.Id, cpy, PROFILE_BY_IDS_CACHE_SEC) 736 } 737 738 result.Data = users 739 } 740 }) 741 } 742 743 func (us SqlUserStore) GetSystemAdminProfiles() store.StoreChannel { 744 return store.Do(func(result *store.StoreResult) { 745 var users []*model.User 746 747 if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Roles LIKE :Roles", map[string]interface{}{"Roles": "%system_admin%"}); err != nil { 748 result.Err = model.NewAppError("SqlUserStore.GetSystemAdminProfiles", "store.sql_user.get_sysadmin_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 749 } else { 750 751 userMap := make(map[string]*model.User) 752 753 for _, u := range users { 754 u.Sanitize(map[string]bool{}) 755 userMap[u.Id] = u 756 } 757 758 result.Data = userMap 759 } 760 }) 761 } 762 763 func (us SqlUserStore) GetByEmail(email string) store.StoreChannel { 764 return store.Do(func(result *store.StoreResult) { 765 email = strings.ToLower(email) 766 767 user := model.User{} 768 769 if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Email = :Email", map[string]interface{}{"Email": email}); err != nil { 770 result.Err = model.NewAppError("SqlUserStore.GetByEmail", store.MISSING_ACCOUNT_ERROR, nil, "email="+email+", "+err.Error(), http.StatusInternalServerError) 771 } 772 773 result.Data = &user 774 }) 775 } 776 777 func (us SqlUserStore) GetByAuth(authData *string, authService string) store.StoreChannel { 778 return store.Do(func(result *store.StoreResult) { 779 if authData == nil || *authData == "" { 780 result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData='', authService="+authService, http.StatusBadRequest) 781 return 782 } 783 784 user := model.User{} 785 786 if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE AuthData = :AuthData AND AuthService = :AuthService", map[string]interface{}{"AuthData": authData, "AuthService": authService}); err != nil { 787 if err == sql.ErrNoRows { 788 result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData="+*authData+", authService="+authService+", "+err.Error(), http.StatusInternalServerError) 789 } else { 790 result.Err = model.NewAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authData="+*authData+", authService="+authService+", "+err.Error(), http.StatusInternalServerError) 791 } 792 } 793 794 result.Data = &user 795 }) 796 } 797 798 func (us SqlUserStore) GetAllUsingAuthService(authService string) store.StoreChannel { 799 return store.Do(func(result *store.StoreResult) { 800 var data []*model.User 801 802 if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE AuthService = :AuthService", map[string]interface{}{"AuthService": authService}); err != nil { 803 result.Err = model.NewAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authService="+authService+", "+err.Error(), http.StatusInternalServerError) 804 } 805 806 result.Data = data 807 }) 808 } 809 810 func (us SqlUserStore) GetByUsername(username string) store.StoreChannel { 811 return store.Do(func(result *store.StoreResult) { 812 user := model.User{} 813 814 if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Username = :Username", map[string]interface{}{"Username": username}); err != nil { 815 result.Err = model.NewAppError("SqlUserStore.GetByUsername", "store.sql_user.get_by_username.app_error", nil, err.Error(), http.StatusInternalServerError) 816 } 817 818 result.Data = &user 819 }) 820 } 821 822 func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) store.StoreChannel { 823 return store.Do(func(result *store.StoreResult) { 824 params := map[string]interface{}{ 825 "LoginId": loginId, 826 "AllowSignInWithUsername": allowSignInWithUsername, 827 "AllowSignInWithEmail": allowSignInWithEmail, 828 "LdapEnabled": ldapEnabled, 829 } 830 831 users := []*model.User{} 832 if _, err := us.GetReplica().Select( 833 &users, 834 `SELECT 835 * 836 FROM 837 Users 838 WHERE 839 (:AllowSignInWithUsername AND Username = :LoginId) 840 OR (:AllowSignInWithEmail AND Email = :LoginId) 841 OR (:LdapEnabled AND AuthService = '`+model.USER_AUTH_SERVICE_LDAP+`' AND AuthData = :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 }