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