github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+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 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 } 829 830 users := []*model.User{} 831 if _, err := us.GetReplica().Select( 832 &users, 833 `SELECT 834 * 835 FROM 836 Users 837 WHERE 838 (:AllowSignInWithUsername AND Username = :LoginId) 839 OR (:AllowSignInWithEmail AND Email = :LoginId)`, 840 params); err != nil { 841 result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, err.Error(), http.StatusInternalServerError) 842 } else if len(users) == 1 { 843 result.Data = users[0] 844 } else if len(users) > 1 { 845 result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.multiple_users", nil, "", http.StatusInternalServerError) 846 } else { 847 result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, "", http.StatusInternalServerError) 848 } 849 }) 850 } 851 852 func (us SqlUserStore) VerifyEmail(userId string) store.StoreChannel { 853 return store.Do(func(result *store.StoreResult) { 854 if _, err := us.GetMaster().Exec("UPDATE Users SET EmailVerified = true WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 855 result.Err = model.NewAppError("SqlUserStore.VerifyEmail", "store.sql_user.verify_email.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError) 856 } 857 858 result.Data = userId 859 }) 860 } 861 862 func (us SqlUserStore) GetTotalUsersCount() store.StoreChannel { 863 return store.Do(func(result *store.StoreResult) { 864 if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users"); err != nil { 865 result.Err = model.NewAppError("SqlUserStore.GetTotalUsersCount", "store.sql_user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError) 866 } else { 867 result.Data = count 868 } 869 }) 870 } 871 872 func (us SqlUserStore) PermanentDelete(userId string) store.StoreChannel { 873 return store.Do(func(result *store.StoreResult) { 874 if _, err := us.GetMaster().Exec("DELETE FROM Users WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 875 result.Err = model.NewAppError("SqlUserStore.PermanentDelete", "store.sql_user.permanent_delete.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError) 876 } 877 }) 878 } 879 880 func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) store.StoreChannel { 881 return store.Do(func(result *store.StoreResult) { 882 query := "" 883 if len(teamId) > 0 { 884 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" 885 } else { 886 query = "SELECT COUNT(DISTINCT Email) FROM Users WHERE DeleteAt = 0" 887 } 888 889 v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId}) 890 if err != nil { 891 result.Err = model.NewAppError("SqlUserStore.AnalyticsUniqueUserCount", "store.sql_user.analytics_unique_user_count.app_error", nil, err.Error(), http.StatusInternalServerError) 892 } else { 893 result.Data = v 894 } 895 }) 896 } 897 898 func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64) store.StoreChannel { 899 return store.Do(func(result *store.StoreResult) { 900 time := model.GetMillis() - timePeriod 901 902 query := "SELECT COUNT(*) FROM Status WHERE LastActivityAt > :Time" 903 904 v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"Time": time}) 905 if err != nil { 906 result.Err = model.NewAppError("SqlUserStore.AnalyticsDailyActiveUsers", "store.sql_user.analytics_daily_active_users.app_error", nil, err.Error(), http.StatusInternalServerError) 907 } else { 908 result.Data = v 909 } 910 }) 911 } 912 913 func (us SqlUserStore) GetUnreadCount(userId string) store.StoreChannel { 914 return store.Do(func(result *store.StoreResult) { 915 if count, err := us.GetReplica().SelectInt(` 916 SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) 917 FROM Channels c 918 INNER JOIN ChannelMembers cm 919 ON cm.ChannelId = c.Id 920 AND cm.UserId = :UserId 921 AND c.DeleteAt = 0`, map[string]interface{}{"UserId": userId}); err != nil { 922 result.Err = model.NewAppError("SqlUserStore.GetMentionCount", "store.sql_user.get_unread_count.app_error", nil, err.Error(), http.StatusInternalServerError) 923 } else { 924 result.Data = count 925 } 926 }) 927 } 928 929 func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) store.StoreChannel { 930 return store.Do(func(result *store.StoreResult) { 931 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 { 932 result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError) 933 } else { 934 result.Data = count 935 } 936 }) 937 } 938 939 func (us SqlUserStore) Search(teamId string, term string, options map[string]bool) store.StoreChannel { 940 return store.Do(func(result *store.StoreResult) { 941 searchQuery := "" 942 943 if teamId == "" { 944 945 // Id != '' is added because both SEARCH_CLAUSE and INACTIVE_CLAUSE start with an AND 946 searchQuery = ` 947 SELECT 948 * 949 FROM 950 Users 951 WHERE 952 Id != '' 953 SEARCH_CLAUSE 954 INACTIVE_CLAUSE 955 ORDER BY Username ASC 956 LIMIT 100` 957 } else { 958 searchQuery = ` 959 SELECT 960 Users.* 961 FROM 962 Users, TeamMembers 963 WHERE 964 TeamMembers.TeamId = :TeamId 965 AND Users.Id = TeamMembers.UserId 966 AND TeamMembers.DeleteAt = 0 967 SEARCH_CLAUSE 968 INACTIVE_CLAUSE 969 ORDER BY Users.Username ASC 970 LIMIT 100` 971 } 972 973 *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId}) 974 975 }) 976 } 977 978 func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) store.StoreChannel { 979 return store.Do(func(result *store.StoreResult) { 980 searchQuery := ` 981 SELECT 982 * 983 FROM 984 Users 985 WHERE 986 (SELECT 987 COUNT(0) 988 FROM 989 TeamMembers 990 WHERE 991 TeamMembers.UserId = Users.Id 992 AND TeamMembers.DeleteAt = 0) = 0 993 SEARCH_CLAUSE 994 INACTIVE_CLAUSE 995 ORDER BY Username ASC 996 LIMIT 100` 997 998 *result = us.performSearch(searchQuery, term, options, map[string]interface{}{}) 999 1000 }) 1001 } 1002 1003 func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options map[string]bool) store.StoreChannel { 1004 return store.Do(func(result *store.StoreResult) { 1005 searchQuery := ` 1006 SELECT 1007 Users.* 1008 FROM Users 1009 LEFT JOIN TeamMembers tm 1010 ON tm.UserId = Users.Id 1011 AND tm.TeamId = :NotInTeamId 1012 WHERE 1013 (tm.UserId IS NULL OR tm.DeleteAt != 0) 1014 SEARCH_CLAUSE 1015 INACTIVE_CLAUSE 1016 ORDER BY Users.Username ASC 1017 LIMIT 100` 1018 1019 *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"NotInTeamId": notInTeamId}) 1020 1021 }) 1022 } 1023 1024 func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) store.StoreChannel { 1025 return store.Do(func(result *store.StoreResult) { 1026 searchQuery := "" 1027 if teamId == "" { 1028 searchQuery = ` 1029 SELECT 1030 Users.* 1031 FROM Users 1032 LEFT JOIN ChannelMembers cm 1033 ON cm.UserId = Users.Id 1034 AND cm.ChannelId = :ChannelId 1035 WHERE 1036 cm.UserId IS NULL 1037 SEARCH_CLAUSE 1038 INACTIVE_CLAUSE 1039 ORDER BY Users.Username ASC 1040 LIMIT 100` 1041 } else { 1042 searchQuery = ` 1043 SELECT 1044 Users.* 1045 FROM Users 1046 INNER JOIN TeamMembers tm 1047 ON tm.UserId = Users.Id 1048 AND tm.TeamId = :TeamId 1049 AND tm.DeleteAt = 0 1050 LEFT JOIN ChannelMembers cm 1051 ON cm.UserId = Users.Id 1052 AND cm.ChannelId = :ChannelId 1053 WHERE 1054 cm.UserId IS NULL 1055 SEARCH_CLAUSE 1056 INACTIVE_CLAUSE 1057 ORDER BY Users.Username ASC 1058 LIMIT 100` 1059 } 1060 1061 *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId}) 1062 1063 }) 1064 } 1065 1066 func (us SqlUserStore) SearchInChannel(channelId string, term string, options map[string]bool) store.StoreChannel { 1067 return store.Do(func(result *store.StoreResult) { 1068 searchQuery := ` 1069 SELECT 1070 Users.* 1071 FROM 1072 Users, ChannelMembers 1073 WHERE 1074 ChannelMembers.ChannelId = :ChannelId 1075 AND ChannelMembers.UserId = Users.Id 1076 SEARCH_CLAUSE 1077 INACTIVE_CLAUSE 1078 ORDER BY Users.Username ASC 1079 LIMIT 100` 1080 1081 *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"ChannelId": channelId}) 1082 1083 }) 1084 } 1085 1086 var escapeLikeSearchChar = []string{ 1087 "%", 1088 "_", 1089 } 1090 1091 var ignoreLikeSearchChar = []string{ 1092 "*", 1093 } 1094 1095 var spaceFulltextSearchChar = []string{ 1096 "<", 1097 ">", 1098 "+", 1099 "-", 1100 "(", 1101 ")", 1102 "~", 1103 ":", 1104 "*", 1105 "\"", 1106 "!", 1107 "@", 1108 } 1109 1110 func generateSearchQuery(searchQuery string, terms []string, fields []string, parameters map[string]interface{}, isPostgreSQL bool) string { 1111 searchTerms := []string{} 1112 for i, term := range terms { 1113 searchFields := []string{} 1114 for _, field := range fields { 1115 if isPostgreSQL { 1116 searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*' ", field, fmt.Sprintf(":Term%d", i))) 1117 } else { 1118 searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*' ", field, fmt.Sprintf(":Term%d", i))) 1119 } 1120 } 1121 searchTerms = append(searchTerms, fmt.Sprintf("(%s)", strings.Join(searchFields, " OR "))) 1122 parameters[fmt.Sprintf("Term%d", i)] = fmt.Sprintf("%s%%", term) 1123 } 1124 1125 searchClause := strings.Join(searchTerms, " AND ") 1126 return strings.Replace(searchQuery, "SEARCH_CLAUSE", fmt.Sprintf(" AND %s ", searchClause), 1) 1127 } 1128 1129 func (us SqlUserStore) performSearch(searchQuery string, term string, options map[string]bool, parameters map[string]interface{}) store.StoreResult { 1130 result := store.StoreResult{} 1131 1132 // These chars must be removed from the like query. 1133 for _, c := range ignoreLikeSearchChar { 1134 term = strings.Replace(term, c, "", -1) 1135 } 1136 1137 // These chars must be escaped in the like query. 1138 for _, c := range escapeLikeSearchChar { 1139 term = strings.Replace(term, c, "*"+c, -1) 1140 } 1141 1142 searchType := USER_SEARCH_TYPE_ALL 1143 if ok := options[store.USER_SEARCH_OPTION_NAMES_ONLY]; ok { 1144 searchType = USER_SEARCH_TYPE_NAMES 1145 } else if ok = options[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME]; ok { 1146 searchType = USER_SEARCH_TYPE_NAMES_NO_FULL_NAME 1147 } else if ok = options[store.USER_SEARCH_OPTION_ALL_NO_FULL_NAME]; ok { 1148 searchType = USER_SEARCH_TYPE_ALL_NO_FULL_NAME 1149 } 1150 1151 if ok := options[store.USER_SEARCH_OPTION_ALLOW_INACTIVE]; ok { 1152 searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "", 1) 1153 } else { 1154 searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "AND Users.DeleteAt = 0", 1) 1155 } 1156 1157 if strings.TrimSpace(term) == "" { 1158 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) 1159 } else { 1160 isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES 1161 searchQuery = generateSearchQuery(searchQuery, strings.Fields(term), searchType, parameters, isPostgreSQL) 1162 } 1163 1164 var users []*model.User 1165 1166 if _, err := us.GetReplica().Select(&users, searchQuery, parameters); err != nil { 1167 result.Err = model.NewAppError("SqlUserStore.Search", "store.sql_user.search.app_error", nil, 1168 fmt.Sprintf("term=%v, search_type=%v, %v", term, searchType, err.Error()), http.StatusInternalServerError) 1169 } else { 1170 for _, u := range users { 1171 u.Sanitize(map[string]bool{}) 1172 } 1173 1174 result.Data = users 1175 } 1176 1177 return result 1178 } 1179 1180 func (us SqlUserStore) AnalyticsGetInactiveUsersCount() store.StoreChannel { 1181 return store.Do(func(result *store.StoreResult) { 1182 if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0"); err != nil { 1183 result.Err = model.NewAppError("SqlUserStore.AnalyticsGetInactiveUsersCount", "store.sql_user.analytics_get_inactive_users_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1184 } else { 1185 result.Data = count 1186 } 1187 }) 1188 } 1189 1190 func (us SqlUserStore) AnalyticsGetSystemAdminCount() store.StoreChannel { 1191 return store.Do(func(result *store.StoreResult) { 1192 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 { 1193 result.Err = model.NewAppError("SqlUserStore.AnalyticsGetSystemAdminCount", "store.sql_user.analytics_get_system_admin_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1194 } else { 1195 result.Data = count 1196 } 1197 }) 1198 } 1199 1200 func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int) store.StoreChannel { 1201 return store.Do(func(result *store.StoreResult) { 1202 var users []*model.User 1203 1204 if _, err := us.GetReplica().Select(&users, ` 1205 SELECT 1206 u.* 1207 FROM Users u 1208 LEFT JOIN TeamMembers tm 1209 ON tm.UserId = u.Id 1210 AND tm.TeamId = :TeamId 1211 AND tm.DeleteAt = 0 1212 WHERE tm.UserId IS NULL 1213 ORDER BY u.Username ASC 1214 LIMIT :Limit OFFSET :Offset 1215 `, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil { 1216 result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInTeam", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) 1217 } else { 1218 1219 for _, u := range users { 1220 u.Sanitize(map[string]bool{}) 1221 } 1222 1223 result.Data = users 1224 } 1225 }) 1226 } 1227 1228 func (us SqlUserStore) GetEtagForProfilesNotInTeam(teamId string) store.StoreChannel { 1229 return store.Do(func(result *store.StoreResult) { 1230 updateAt, err := us.GetReplica().SelectInt(` 1231 SELECT 1232 u.UpdateAt 1233 FROM Users u 1234 LEFT JOIN TeamMembers tm 1235 ON tm.UserId = u.Id 1236 AND tm.TeamId = :TeamId 1237 AND tm.DeleteAt = 0 1238 WHERE tm.UserId IS NULL 1239 ORDER BY u.UpdateAt DESC 1240 LIMIT 1 1241 `, map[string]interface{}{"TeamId": teamId}) 1242 1243 if err != nil { 1244 result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) 1245 } else { 1246 result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt) 1247 } 1248 }) 1249 }