2017-04-12 08:27:57 -04:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2015-06-14 23:53:32 -08:00
// See License.txt for license information.
2017-09-25 09:11:25 -05:00
package sqlstore
2015-06-14 23:53:32 -08:00
import (
2016-03-11 10:48:43 -05:00
"database/sql"
2015-06-14 23:53:32 -08:00
"fmt"
2017-01-30 08:30:02 -05:00
"net/http"
2016-04-21 22:37:01 -07:00
"strconv"
2016-01-20 13:36:16 -06:00
"strings"
2016-04-21 22:37:01 -07:00
2018-06-25 14:34:59 +01:00
"github.com/mattermost/gorp"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
2017-09-25 09:11:25 -05:00
"github.com/mattermost/mattermost-server/store"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/utils"
2015-06-14 23:53:32 -08:00
)
2016-01-05 14:53:41 -06:00
const (
2017-10-31 11:52:10 -04:00
PROFILES_IN_CHANNEL_CACHE_SIZE = model . CHANNEL_CACHE_SIZE
PROFILES_IN_CHANNEL_CACHE_SEC = 900 // 15 mins
PROFILE_BY_IDS_CACHE_SIZE = model . SESSION_CACHE_SIZE
PROFILE_BY_IDS_CACHE_SEC = 900 // 15 mins
)
var (
USER_SEARCH_TYPE_NAMES_NO_FULL_NAME = [ ] string { "Username" , "Nickname" }
USER_SEARCH_TYPE_NAMES = [ ] string { "Username" , "FirstName" , "LastName" , "Nickname" }
USER_SEARCH_TYPE_ALL_NO_FULL_NAME = [ ] string { "Username" , "Nickname" , "Email" }
USER_SEARCH_TYPE_ALL = [ ] string { "Username" , "FirstName" , "LastName" , "Nickname" , "Email" }
2016-01-05 14:53:41 -06:00
)
2015-06-14 23:53:32 -08:00
type SqlUserStore struct {
2017-06-27 08:02:08 -07:00
SqlStore
2017-09-14 12:01:44 -05:00
metrics einterfaces . MetricsInterface
2015-06-14 23:53:32 -08:00
}
2016-10-19 14:49:25 -04:00
var profilesInChannelCache * utils . Cache = utils . NewLru ( PROFILES_IN_CHANNEL_CACHE_SIZE )
2016-12-13 19:23:36 -08:00
var profileByIdsCache * utils . Cache = utils . NewLru ( PROFILE_BY_IDS_CACHE_SIZE )
2016-10-19 14:49:25 -04:00
2018-03-05 10:35:26 -05:00
func ( us SqlUserStore ) ClearCaches ( ) {
2016-12-08 07:18:15 -08:00
profilesInChannelCache . Purge ( )
2016-12-13 19:23:36 -08:00
profileByIdsCache . Purge ( )
2018-03-05 10:35:26 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheInvalidationCounter ( "Profiles in Channel - Purge" )
us . metrics . IncrementMemCacheInvalidationCounter ( "Profile By Ids - Purge" )
}
2016-12-13 19:23:36 -08:00
}
func ( us SqlUserStore ) InvalidatProfileCacheForUser ( userId string ) {
profileByIdsCache . Remove ( userId )
2018-03-05 10:35:26 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheInvalidationCounter ( "Profile By Ids - Remove" )
}
2016-12-08 07:18:15 -08:00
}
2017-09-25 09:11:25 -05:00
func NewSqlUserStore ( sqlStore SqlStore , metrics einterfaces . MetricsInterface ) store . UserStore {
2017-09-14 12:01:44 -05:00
us := & SqlUserStore {
SqlStore : sqlStore ,
metrics : metrics ,
}
2015-06-14 23:53:32 -08:00
for _ , db := range sqlStore . GetAllConns ( ) {
table := db . AddTableWithName ( model . User { } , "Users" ) . SetKeys ( false , "Id" )
table . ColMap ( "Id" ) . SetMaxSize ( 26 )
2016-04-21 22:37:01 -07:00
table . ColMap ( "Username" ) . SetMaxSize ( 64 ) . SetUnique ( true )
2015-06-14 23:53:32 -08:00
table . ColMap ( "Password" ) . SetMaxSize ( 128 )
2016-05-11 11:04:30 -07:00
table . ColMap ( "AuthData" ) . SetMaxSize ( 128 ) . SetUnique ( true )
2015-07-22 15:05:20 -04:00
table . ColMap ( "AuthService" ) . SetMaxSize ( 32 )
2016-04-21 22:37:01 -07:00
table . ColMap ( "Email" ) . SetMaxSize ( 128 ) . SetUnique ( true )
2015-07-09 13:59:19 -04:00
table . ColMap ( "Nickname" ) . SetMaxSize ( 64 )
2015-07-09 17:06:04 -04:00
table . ColMap ( "FirstName" ) . SetMaxSize ( 64 )
table . ColMap ( "LastName" ) . SetMaxSize ( 64 )
2017-08-01 11:06:53 -04:00
table . ColMap ( "Roles" ) . SetMaxSize ( 256 )
2015-06-14 23:53:32 -08:00
table . ColMap ( "Props" ) . SetMaxSize ( 4000 )
table . ColMap ( "NotifyProps" ) . SetMaxSize ( 2000 )
2016-01-19 22:00:01 -06:00
table . ColMap ( "Locale" ) . SetMaxSize ( 5 )
2016-03-30 12:49:29 -04:00
table . ColMap ( "MfaSecret" ) . SetMaxSize ( 128 )
2018-01-26 08:37:12 -05:00
table . ColMap ( "Position" ) . SetMaxSize ( 128 )
2018-03-22 06:53:43 -07:00
table . ColMap ( "Timezone" ) . SetMaxSize ( 256 )
2015-06-14 23:53:32 -08:00
}
return us
}
func ( us SqlUserStore ) CreateIndexesIfNotExists ( ) {
2015-07-12 14:56:44 -08:00
us . CreateIndexIfNotExists ( "idx_users_email" , "Users" , "Email" )
2016-10-24 17:05:27 -03:00
us . CreateIndexIfNotExists ( "idx_users_update_at" , "Users" , "UpdateAt" )
us . CreateIndexIfNotExists ( "idx_users_create_at" , "Users" , "CreateAt" )
us . CreateIndexIfNotExists ( "idx_users_delete_at" , "Users" , "DeleteAt" )
2016-10-19 14:49:25 -04:00
2017-10-09 10:16:14 -07:00
if us . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
2017-09-27 18:44:22 +01:00
us . CreateIndexIfNotExists ( "idx_users_email_lower" , "Users" , "lower(Email)" )
us . CreateIndexIfNotExists ( "idx_users_username_lower" , "Users" , "lower(Username)" )
us . CreateIndexIfNotExists ( "idx_users_nickname_lower" , "Users" , "lower(Nickname)" )
us . CreateIndexIfNotExists ( "idx_users_firstname_lower" , "Users" , "lower(FirstName)" )
us . CreateIndexIfNotExists ( "idx_users_lastname_lower" , "Users" , "lower(LastName)" )
}
2017-10-31 11:52:10 -04:00
us . CreateFullTextIndexIfNotExists ( "idx_users_all_txt" , "Users" , strings . Join ( USER_SEARCH_TYPE_ALL , ", " ) )
us . CreateFullTextIndexIfNotExists ( "idx_users_all_no_full_name_txt" , "Users" , strings . Join ( USER_SEARCH_TYPE_ALL_NO_FULL_NAME , ", " ) )
us . CreateFullTextIndexIfNotExists ( "idx_users_names_txt" , "Users" , strings . Join ( USER_SEARCH_TYPE_NAMES , ", " ) )
us . CreateFullTextIndexIfNotExists ( "idx_users_names_no_full_name_txt" , "Users" , strings . Join ( USER_SEARCH_TYPE_NAMES_NO_FULL_NAME , ", " ) )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) Save ( user * model . User ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
if len ( user . Id ) > 0 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Save" , "store.sql_user.save.existing.app_error" , nil , "user_id=" + user . Id , http . StatusBadRequest )
2015-06-14 23:53:32 -08:00
return
}
user . PreSave ( )
if result . Err = user . IsValid ( ) ; result . Err != nil {
return
}
if err := us . GetMaster ( ) . Insert ( user ) ; err != nil {
2017-09-06 14:00:56 -04:00
if IsUniqueConstraintError ( err , [ ] string { "Email" , "users_email_key" , "idx_users_email_unique" } ) {
2017-01-30 08:30:02 -05:00
result . Err = model . NewAppError ( "SqlUserStore.Save" , "store.sql_user.save.email_exists.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2017-09-06 14:00:56 -04:00
} else if IsUniqueConstraintError ( err , [ ] string { "Username" , "users_username_key" , "idx_users_username_unique" } ) {
2017-01-30 08:30:02 -05:00
result . Err = model . NewAppError ( "SqlUserStore.Save" , "store.sql_user.save.username_exists.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2015-06-14 23:53:32 -08:00
} else {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Save" , "store.sql_user.save.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
}
} else {
result . Data = user
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) Update ( user * model . User , trustedUpdateData bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
user . PreUpdate ( )
if result . Err = user . IsValid ( ) ; result . Err != nil {
return
}
if oldUserResult , err := us . GetMaster ( ) . Get ( model . User { } , user . Id ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Update" , "store.sql_user.update.finding.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
} else if oldUserResult == nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Update" , "store.sql_user.update.find.app_error" , nil , "user_id=" + user . Id , http . StatusBadRequest )
2015-06-14 23:53:32 -08:00
} else {
oldUser := oldUserResult . ( * model . User )
user . CreateAt = oldUser . CreateAt
user . AuthData = oldUser . AuthData
2015-10-22 10:53:39 -04:00
user . AuthService = oldUser . AuthService
2015-06-14 23:53:32 -08:00
user . Password = oldUser . Password
user . LastPasswordUpdate = oldUser . LastPasswordUpdate
2015-07-16 08:55:37 -07:00
user . LastPictureUpdate = oldUser . LastPictureUpdate
2015-06-14 23:53:32 -08:00
user . EmailVerified = oldUser . EmailVerified
2015-07-29 01:26:10 -08:00
user . FailedAttempts = oldUser . FailedAttempts
2016-03-30 12:49:29 -04:00
user . MfaSecret = oldUser . MfaSecret
user . MfaActive = oldUser . MfaActive
2015-06-14 23:53:32 -08:00
2016-05-03 15:27:00 -04:00
if ! trustedUpdateData {
2015-06-14 23:53:32 -08:00
user . Roles = oldUser . Roles
user . DeleteAt = oldUser . DeleteAt
}
2016-04-21 22:37:01 -07:00
if user . IsOAuthUser ( ) {
2017-02-27 00:18:01 +05:30
if ! trustedUpdateData {
user . Email = oldUser . Email
}
2016-05-03 15:27:00 -04:00
} else if user . IsLDAPUser ( ) && ! trustedUpdateData {
2016-05-02 08:07:58 -04:00
if user . Username != oldUser . Username ||
user . Email != oldUser . Email {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Update" , "store.sql_user.update.can_not_change_ldap.app_error" , nil , "user_id=" + user . Id , http . StatusBadRequest )
2016-05-02 08:07:58 -04:00
return
}
} else if user . Email != oldUser . Email {
2015-06-14 23:53:32 -08:00
user . EmailVerified = false
}
2015-08-20 14:29:40 -07:00
if user . Username != oldUser . Username {
2016-04-25 08:20:45 -04:00
user . UpdateMentionKeysFromUsername ( oldUser . Username )
2015-08-20 14:29:40 -07:00
}
2015-06-14 23:53:32 -08:00
if count , err := us . GetMaster ( ) . Update ( user ) ; err != nil {
2017-09-06 14:00:56 -04:00
if IsUniqueConstraintError ( err , [ ] string { "Email" , "users_email_key" , "idx_users_email_unique" } ) {
2017-04-28 10:11:26 -04:00
result . Err = model . NewAppError ( "SqlUserStore.Update" , "store.sql_user.update.email_taken.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2017-09-06 14:00:56 -04:00
} else if IsUniqueConstraintError ( err , [ ] string { "Username" , "users_username_key" , "idx_users_username_unique" } ) {
2017-04-28 10:11:26 -04:00
result . Err = model . NewAppError ( "SqlUserStore.Update" , "store.sql_user.update.username_taken.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2015-07-29 09:42:13 -07:00
} else {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Update" , "store.sql_user.update.updating.app_error" , nil , "user_id=" + user . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-07-29 09:42:13 -07:00
}
2015-06-14 23:53:32 -08:00
} else if count != 1 {
2017-09-18 17:40:56 +01:00
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 )
2015-06-14 23:53:32 -08:00
} else {
2017-04-19 15:38:35 -04:00
user . Sanitize ( map [ string ] bool { } )
oldUser . Sanitize ( map [ string ] bool { } )
2015-06-14 23:53:32 -08:00
result . Data = [ 2 ] * model . User { user , oldUser }
}
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdateLastPictureUpdate ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-07-16 08:55:37 -07:00
curTime := model . GetMillis ( )
2015-07-27 17:04:44 -04:00
if _ , err := us . GetMaster ( ) . Exec ( "UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId" , map [ string ] interface { } { "Time" : curTime , "UserId" : userId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdateUpdateAt" , "store.sql_user.update_last_picture_update.app_error" , nil , "user_id=" + userId , http . StatusInternalServerError )
2015-07-09 16:37:03 -07:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2015-07-09 16:37:03 -07:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdateUpdateAt ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-05-12 18:36:30 -07:00
curTime := model . GetMillis ( )
if _ , err := us . GetMaster ( ) . Exec ( "UPDATE Users SET UpdateAt = :Time WHERE Id = :UserId" , map [ string ] interface { } { "Time" : curTime , "UserId" : userId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdateUpdateAt" , "store.sql_user.update_update.app_error" , nil , "user_id=" + userId , http . StatusInternalServerError )
2016-05-12 18:36:30 -07:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2016-05-12 18:36:30 -07:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdatePassword ( userId , hashedPassword string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
updateAt := model . GetMillis ( )
2016-05-11 11:04:30 -07:00
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdatePassword" , "store.sql_user.update_password.app_error" , nil , "id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdateFailedPasswordAttempts ( userId string , attempts int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-07-29 01:26:10 -08:00
if _ , err := us . GetMaster ( ) . Exec ( "UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId" , map [ string ] interface { } { "FailedAttempts" : attempts , "UserId" : userId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdateFailedPasswordAttempts" , "store.sql_user.update_failed_pwd_attempts.app_error" , nil , "user_id=" + userId , http . StatusInternalServerError )
2015-07-29 01:26:10 -08:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2015-07-29 01:26:10 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdateAuthData ( userId string , service string , authData * string , email string , resetMfa bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-04-13 14:31:27 -04:00
email = strings . ToLower ( email )
2015-12-17 12:44:46 -05:00
updateAt := model . GetMillis ( )
2016-02-03 10:32:37 -05:00
query := `
UPDATE
Users
SET
Password = ' ' ,
LastPasswordUpdate = : LastPasswordUpdate ,
UpdateAt = : UpdateAt ,
FailedAttempts = 0 ,
AuthService = : AuthService ,
AuthData = : AuthData `
if len ( email ) != 0 {
query += ", Email = :Email"
}
2016-12-12 08:16:10 -05:00
if resetMfa {
query += ", MfaActive = false, MfaSecret = ''"
}
2016-02-03 10:32:37 -05:00
query += " WHERE Id = :UserId"
if _ , err := us . GetMaster ( ) . Exec ( query , map [ string ] interface { } { "LastPasswordUpdate" : updateAt , "UpdateAt" : updateAt , "UserId" : userId , "AuthService" : service , "AuthData" : authData , "Email" : email } ) ; err != nil {
2017-09-06 14:00:56 -04:00
if IsUniqueConstraintError ( err , [ ] string { "Email" , "users_email_key" , "idx_users_email_unique" , "AuthData" , "users_authdata_key" } ) {
2017-09-18 17:40:56 +01:00
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 )
2016-06-15 08:02:07 -04:00
} else {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdateAuthData" , "store.sql_user.update_auth_data.app_error" , nil , "id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-06-15 08:02:07 -04:00
}
2015-12-17 12:44:46 -05:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2015-12-17 12:44:46 -05:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdateMfaSecret ( userId , secret string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-03-30 12:49:29 -04:00
updateAt := model . GetMillis ( )
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdateMfaSecret" , "store.sql_user.update_mfa_secret.app_error" , nil , "id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-03-30 12:49:29 -04:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2016-03-30 12:49:29 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) UpdateMfaActive ( userId string , active bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-03-30 12:49:29 -04:00
updateAt := model . GetMillis ( )
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.UpdateMfaActive" , "store.sql_user.update_mfa_active.app_error" , nil , "id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-03-30 12:49:29 -04:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2016-03-30 12:49:29 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) Get ( id string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
if obj , err := us . GetReplica ( ) . Get ( model . User { } , id ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.Get" , "store.sql_user.get.app_error" , nil , "user_id=" + id + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
} else if obj == nil {
2017-09-25 09:11:25 -05:00
result . Err = model . NewAppError ( "SqlUserStore.Get" , store . MISSING_ACCOUNT_ERROR , nil , "user_id=" + id , http . StatusNotFound )
2015-06-14 23:53:32 -08:00
} else {
result . Data = obj . ( * model . User )
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetAll ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-04-21 22:37:01 -07:00
var data [ ] * model . User
if _ , err := us . GetReplica ( ) . Select ( & data , "SELECT * FROM Users" ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetAll" , "store.sql_user.get.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
}
result . Data = data
2017-10-06 08:12:10 -07:00
} )
2016-04-21 22:37:01 -07:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlUserStore ) GetEtagForAllProfiles ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-05-04 06:31:42 -07:00
updateAt , err := s . GetReplica ( ) . SelectInt ( "SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1" )
2016-04-21 22:37:01 -07:00
if err != nil {
2017-10-09 10:16:14 -07:00
result . Data = fmt . Sprintf ( "%v.%v" , model . CurrentVersion , model . GetMillis ( ) )
2016-04-21 22:37:01 -07:00
} else {
2017-10-09 10:16:14 -07:00
result . Data = fmt . Sprintf ( "%v.%v" , model . CurrentVersion , updateAt )
2016-04-21 22:37:01 -07:00
}
2017-10-06 08:12:10 -07:00
} )
2016-04-21 22:37:01 -07:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetAllProfiles ( offset int , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-05-04 06:31:42 -07:00
var users [ ] * model . User
2016-10-19 14:49:25 -04:00
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetAllProfiles" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-05-04 06:31:42 -07:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2016-05-04 06:31:42 -07:00
}
2017-02-03 15:17:34 -05:00
result . Data = users
2016-05-04 06:31:42 -07:00
}
2017-10-06 08:12:10 -07:00
} )
2016-05-04 06:31:42 -07:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlUserStore ) GetEtagForProfiles ( teamId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-04-21 22:37:01 -07:00
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 } )
2015-06-14 23:53:32 -08:00
if err != nil {
2017-10-09 10:16:14 -07:00
result . Data = fmt . Sprintf ( "%v.%v" , model . CurrentVersion , model . GetMillis ( ) )
2015-06-14 23:53:32 -08:00
} else {
2017-10-09 10:16:14 -07:00
result . Data = fmt . Sprintf ( "%v.%v" , model . CurrentVersion , updateAt )
2015-06-14 23:53:32 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfiles ( teamId string , offset int , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
var users [ ] * model . User
2016-10-19 14:49:25 -04:00
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfiles" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2015-06-14 23:53:32 -08:00
}
2017-02-03 15:17:34 -05:00
result . Data = users
2015-06-14 23:53:32 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2016-11-10 06:25:23 -08:00
func ( us SqlUserStore ) InvalidateProfilesInChannelCacheByUser ( userId string ) {
keys := profilesInChannelCache . Keys ( )
for _ , key := range keys {
if cacheItem , ok := profilesInChannelCache . Get ( key ) ; ok {
userMap := cacheItem . ( map [ string ] * model . User )
if _ , userInCache := userMap [ userId ] ; userInCache {
profilesInChannelCache . Remove ( key )
2018-03-05 10:35:26 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheInvalidationCounter ( "Profiles in Channel - Remove by User" )
}
2016-11-10 06:25:23 -08:00
}
}
}
}
2016-10-19 14:49:25 -04:00
func ( us SqlUserStore ) InvalidateProfilesInChannelCache ( channelId string ) {
profilesInChannelCache . Remove ( channelId )
2018-03-05 10:35:26 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheInvalidationCounter ( "Profiles in Channel - Remove by Channel" )
}
2016-10-19 14:49:25 -04:00
}
2016-04-21 22:37:01 -07:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfilesInChannel ( channelId string , offset int , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-02-03 15:17:34 -05:00
var users [ ] * model . User
2018-03-09 05:48:30 -07:00
query := `
SELECT
Users . *
FROM
Users , ChannelMembers
WHERE
ChannelMembers . ChannelId = : ChannelId
AND Users . Id = ChannelMembers . UserId
ORDER BY
Users . Username ASC
LIMIT : Limit OFFSET : Offset
`
2017-02-03 15:17:34 -05:00
if _ , err := us . GetReplica ( ) . Select ( & users , query , map [ string ] interface { } { "ChannelId" : channelId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfilesInChannel" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-02-03 15:17:34 -05:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2017-02-03 15:17:34 -05:00
}
result . Data = users
}
2017-10-06 08:12:10 -07:00
} )
2017-02-03 15:17:34 -05:00
}
2018-03-09 05:48:30 -07:00
func ( us SqlUserStore ) GetProfilesInChannelByStatus ( channelId string , offset int , limit int ) store . StoreChannel {
return store . Do ( func ( result * store . StoreResult ) {
var users [ ] * model . User
query := `
SELECT
Users . *
FROM Users
INNER JOIN ChannelMembers ON Users . Id = ChannelMembers . UserId
LEFT JOIN Status ON Users . Id = Status . UserId
WHERE
ChannelMembers . ChannelId = : ChannelId
ORDER BY
CASE Status
WHEN ' online ' THEN 1
WHEN ' away ' THEN 2
WHEN ' dnd ' THEN 3
ELSE 4
END ,
Users . Username ASC
LIMIT : Limit OFFSET : Offset
`
if _ , err := us . GetReplica ( ) . Select ( & users , query , map [ string ] interface { } { "ChannelId" : channelId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
result . Err = model . NewAppError ( "SqlUserStore.GetProfilesInChannelByStatus" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
} else {
for _ , u := range users {
u . Sanitize ( map [ string ] bool { } )
}
result . Data = users
}
} )
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetAllProfilesInChannel ( channelId string , allowFromCache bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-02-03 15:17:34 -05:00
if allowFromCache {
2016-10-19 14:49:25 -04:00
if cacheItem , ok := profilesInChannelCache . Get ( channelId ) ; ok {
2017-09-14 12:01:44 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheHitCounter ( "Profiles in Channel" )
2016-12-19 10:16:22 -05:00
}
2016-10-19 14:49:25 -04:00
result . Data = cacheItem . ( map [ string ] * model . User )
return
2016-12-19 10:16:22 -05:00
} else {
2017-09-14 12:01:44 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheMissCounter ( "Profiles in Channel" )
2016-12-19 10:16:22 -05:00
}
}
} else {
2017-09-14 12:01:44 -05:00
if us . metrics != nil {
us . metrics . IncrementMemCacheMissCounter ( "Profiles in Channel" )
2016-10-19 14:49:25 -04:00
}
}
var users [ ] * model . User
query := "SELECT Users.* FROM Users, ChannelMembers WHERE ChannelMembers.ChannelId = :ChannelId AND Users.Id = ChannelMembers.UserId AND Users.DeleteAt = 0"
2017-02-03 15:17:34 -05:00
if _ , err := us . GetReplica ( ) . Select ( & users , query , map [ string ] interface { } { "ChannelId" : channelId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetAllProfilesInChannel" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-10-19 14:49:25 -04:00
} else {
userMap := make ( map [ string ] * model . User )
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2016-10-19 14:49:25 -04:00
userMap [ u . Id ] = u
}
result . Data = userMap
2017-02-03 15:17:34 -05:00
if allowFromCache {
2016-10-19 14:49:25 -04:00
profilesInChannelCache . AddWithExpiresInSecs ( channelId , userMap , PROFILES_IN_CHANNEL_CACHE_SEC )
}
}
2017-10-06 08:12:10 -07:00
} )
2016-10-19 14:49:25 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfilesNotInChannel ( teamId string , channelId string , offset int , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-04-21 22:37:01 -07:00
var users [ ] * model . User
if _ , err := us . GetReplica ( ) . Select ( & users , `
2016-10-19 14:49:25 -04:00
SELECT
u . *
FROM Users u
INNER JOIN TeamMembers tm
ON tm . UserId = u . Id
AND tm . TeamId = : TeamId
2016-10-24 12:00:42 -04:00
AND tm . DeleteAt = 0
2016-10-19 14:49:25 -04:00
LEFT JOIN ChannelMembers cm
ON cm . UserId = u . Id
AND cm . ChannelId = : ChannelId
WHERE cm . UserId IS NULL
ORDER BY u . Username ASC
LIMIT : Limit OFFSET : Offset
` , map [ string ] interface { } { "TeamId" : teamId , "ChannelId" : channelId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfilesNotInChannel" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2017-03-29 21:11:40 -04:00
}
result . Data = users
}
2017-10-06 08:12:10 -07:00
} )
2017-03-29 21:11:40 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfilesWithoutTeam ( offset int , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-03-29 21:11:40 -04:00
var users [ ] * model . User
query := `
SELECT
*
FROM
Users
WHERE
( SELECT
COUNT ( 0 )
FROM
TeamMembers
WHERE
TeamMembers . UserId = Users . Id
AND TeamMembers . DeleteAt = 0 ) = 0
ORDER BY
Username ASC
LIMIT
: Limit
OFFSET
: Offset `
if _ , err := us . GetReplica ( ) . Select ( & users , query , map [ string ] interface { } { "Offset" : offset , "Limit" : limit } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfilesWithoutTeam" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-03-29 21:11:40 -04:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2016-04-21 22:37:01 -07:00
}
2017-02-03 15:17:34 -05:00
result . Data = users
2016-04-21 22:37:01 -07:00
}
2017-10-06 08:12:10 -07:00
} )
2016-04-21 22:37:01 -07:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfilesByUsernames ( usernames [ ] string , teamId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-10-19 14:49:25 -04:00
var users [ ] * model . User
props := make ( map [ string ] interface { } )
idQuery := ""
for index , usernames := range usernames {
if len ( idQuery ) > 0 {
idQuery += ", "
}
props [ "username" + strconv . Itoa ( index ) ] = usernames
idQuery += ":username" + strconv . Itoa ( index )
}
2017-04-25 11:00:41 -04:00
var query string
if teamId == "" {
query = ` SELECT * FROM Users WHERE Username IN ( ` + idQuery + ` ) `
} else {
query = ` SELECT Users . * FROM Users INNER JOIN TeamMembers ON
Users . Id = TeamMembers . UserId AND Users . Username IN ( ` + idQuery + ` ) AND TeamMembers . TeamId = : TeamId `
props [ "TeamId" ] = teamId
}
2016-10-19 14:49:25 -04:00
2017-04-25 11:00:41 -04:00
if _ , err := us . GetReplica ( ) . Select ( & users , query , props ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfilesByUsernames" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-10-19 14:49:25 -04:00
} else {
2017-04-25 11:00:41 -04:00
result . Data = users
2016-10-19 14:49:25 -04:00
}
2017-10-06 08:12:10 -07:00
} )
2016-10-19 14:49:25 -04:00
}
type UserWithLastActivityAt struct {
model . User
LastActivityAt int64
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetRecentlyActiveUsersForTeam ( teamId string , offset , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-10-19 14:49:25 -04:00
var users [ ] * UserWithLastActivityAt
if _ , err := us . GetReplica ( ) . Select ( & users , `
SELECT
u . * ,
s . LastActivityAt
FROM Users AS u
INNER JOIN TeamMembers AS t ON u . Id = t . UserId
INNER JOIN Status AS s ON s . UserId = t . UserId
WHERE t . TeamId = : TeamId
ORDER BY s . LastActivityAt DESC
2017-06-30 12:07:23 -04:00
LIMIT : Limit OFFSET : Offset
` , map [ string ] interface { } { "TeamId" : teamId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
result . Err = model . NewAppError ( "SqlUserStore.GetRecentlyActiveUsers" , "store.sql_user.get_recently_active_users.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-10-19 14:49:25 -04:00
} else {
2017-06-30 12:07:23 -04:00
userList := [ ] * model . User { }
2016-10-19 14:49:25 -04:00
for _ , userWithLastActivityAt := range users {
u := userWithLastActivityAt . User
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2016-10-19 14:49:25 -04:00
u . LastActivityAt = userWithLastActivityAt . LastActivityAt
2017-06-30 12:07:23 -04:00
userList = append ( userList , & u )
2016-10-19 14:49:25 -04:00
}
2017-06-30 12:07:23 -04:00
result . Data = userList
}
2017-10-06 08:12:10 -07:00
} )
2017-06-30 12:07:23 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetNewUsersForTeam ( teamId string , offset , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-06-30 12:07:23 -04:00
var users [ ] * model . User
if _ , err := us . GetReplica ( ) . Select ( & users , `
SELECT
u . *
FROM Users AS u
INNER JOIN TeamMembers AS t ON u . Id = t . UserId
WHERE t . TeamId = : TeamId
ORDER BY u . CreateAt DESC
LIMIT : Limit OFFSET : Offset
` , map [ string ] interface { } { "TeamId" : teamId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
result . Err = model . NewAppError ( "SqlUserStore.GetNewUsersForTeam" , "store.sql_user.get_new_users.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
} else {
for _ , u := range users {
u . Sanitize ( map [ string ] bool { } )
}
result . Data = users
2016-10-19 14:49:25 -04:00
}
2017-10-06 08:12:10 -07:00
} )
2016-10-19 14:49:25 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfileByIds ( userIds [ ] string , allowFromCache bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-02-03 09:30:57 -05:00
users := [ ] * model . User { }
2016-04-21 22:37:01 -07:00
props := make ( map [ string ] interface { } )
idQuery := ""
2016-12-13 19:23:36 -08:00
remainingUserIds := make ( [ ] string , 0 )
if allowFromCache {
for _ , userId := range userIds {
if cacheItem , ok := profileByIdsCache . Get ( userId ) ; ok {
2017-05-01 17:40:04 -04:00
u := & model . User { }
* u = * cacheItem . ( * model . User )
2017-02-03 09:30:57 -05:00
users = append ( users , u )
2016-12-13 19:23:36 -08:00
} else {
remainingUserIds = append ( remainingUserIds , userId )
}
}
2017-09-14 12:01:44 -05:00
if us . metrics != nil {
us . metrics . AddMemCacheHitCounter ( "Profile By Ids" , float64 ( len ( users ) ) )
us . metrics . AddMemCacheMissCounter ( "Profile By Ids" , float64 ( len ( remainingUserIds ) ) )
2017-01-03 09:57:38 -05:00
}
2016-12-13 19:23:36 -08:00
} else {
remainingUserIds = userIds
2017-09-14 12:01:44 -05:00
if us . metrics != nil {
us . metrics . AddMemCacheMissCounter ( "Profile By Ids" , float64 ( len ( remainingUserIds ) ) )
2017-01-03 09:57:38 -05:00
}
2016-12-13 19:23:36 -08:00
}
2016-04-21 22:37:01 -07:00
2016-12-13 19:23:36 -08:00
// If everything came from the cache then just return
if len ( remainingUserIds ) == 0 {
2017-02-03 09:30:57 -05:00
result . Data = users
2016-12-13 19:23:36 -08:00
return
}
for index , userId := range remainingUserIds {
2016-04-21 22:37:01 -07:00
if len ( idQuery ) > 0 {
idQuery += ", "
}
props [ "userId" + strconv . Itoa ( index ) ] = userId
idQuery += ":userId" + strconv . Itoa ( index )
}
if _ , err := us . GetReplica ( ) . Select ( & users , "SELECT * FROM Users WHERE Users.Id IN (" + idQuery + ")" , props ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfileByIds" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2017-05-01 17:40:04 -04:00
cpy := & model . User { }
* cpy = * u
profileByIdsCache . AddWithExpiresInSecs ( cpy . Id , cpy , PROFILE_BY_IDS_CACHE_SEC )
2016-04-21 22:37:01 -07:00
}
2017-02-03 09:30:57 -05:00
result . Data = users
2016-04-21 22:37:01 -07:00
}
2017-10-06 08:12:10 -07:00
} )
2016-04-21 22:37:01 -07:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetSystemAdminProfiles ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-10-05 17:33:45 -07:00
var users [ ] * model . User
2016-09-13 12:42:48 -04:00
if _ , err := us . GetReplica ( ) . Select ( & users , "SELECT * FROM Users WHERE Roles LIKE :Roles" , map [ string ] interface { } { "Roles" : "%system_admin%" } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetSystemAdminProfiles" , "store.sql_user.get_sysadmin_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2015-10-05 17:33:45 -07:00
} else {
userMap := make ( map [ string ] * model . User )
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2015-10-05 17:33:45 -07:00
userMap [ u . Id ] = u
}
result . Data = userMap
}
2017-10-06 08:12:10 -07:00
} )
2015-10-05 17:33:45 -07:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetByEmail ( email string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-04-13 14:31:27 -04:00
email = strings . ToLower ( email )
2015-06-14 23:53:32 -08:00
user := model . User { }
2016-04-21 22:37:01 -07:00
if err := us . GetReplica ( ) . SelectOne ( & user , "SELECT * FROM Users WHERE Email = :Email" , map [ string ] interface { } { "Email" : email } ) ; err != nil {
2017-09-25 09:11:25 -05:00
result . Err = model . NewAppError ( "SqlUserStore.GetByEmail" , store . MISSING_ACCOUNT_ERROR , nil , "email=" + email + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
}
result . Data = & user
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetByAuth ( authData * string , authService string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-05-11 11:04:30 -07:00
if authData == nil || * authData == "" {
2017-09-25 09:11:25 -05:00
result . Err = model . NewAppError ( "SqlUserStore.GetByAuth" , store . MISSING_AUTH_ACCOUNT_ERROR , nil , "authData='', authService=" + authService , http . StatusBadRequest )
2016-05-11 11:04:30 -07:00
return
}
2015-07-15 12:48:50 -04:00
user := model . User { }
2016-04-21 22:37:01 -07:00
if err := us . GetReplica ( ) . SelectOne ( & user , "SELECT * FROM Users WHERE AuthData = :AuthData AND AuthService = :AuthService" , map [ string ] interface { } { "AuthData" : authData , "AuthService" : authService } ) ; err != nil {
2016-03-11 10:48:43 -05:00
if err == sql . ErrNoRows {
2017-09-25 09:11:25 -05:00
result . Err = model . NewAppError ( "SqlUserStore.GetByAuth" , store . MISSING_AUTH_ACCOUNT_ERROR , nil , "authData=" + * authData + ", authService=" + authService + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-03-11 10:48:43 -05:00
} else {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetByAuth" , "store.sql_user.get_by_auth.other.app_error" , nil , "authData=" + * authData + ", authService=" + authService + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-03-11 10:48:43 -05:00
}
2015-07-15 12:48:50 -04:00
}
result . Data = & user
2017-10-06 08:12:10 -07:00
} )
2015-07-15 12:48:50 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetAllUsingAuthService ( authService string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-06-03 09:33:59 -04:00
var data [ ] * model . User
if _ , err := us . GetReplica ( ) . Select ( & data , "SELECT * FROM Users WHERE AuthService = :AuthService" , map [ string ] interface { } { "AuthService" : authService } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetByAuth" , "store.sql_user.get_by_auth.other.app_error" , nil , "authService=" + authService + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-06-03 09:33:59 -04:00
}
result . Data = data
2017-10-06 08:12:10 -07:00
} )
2016-06-03 09:33:59 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetByUsername ( username string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
user := model . User { }
2016-04-21 22:37:01 -07:00
if err := us . GetReplica ( ) . SelectOne ( & user , "SELECT * FROM Users WHERE Username = :Username" , map [ string ] interface { } { "Username" : username } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetByUsername" , "store.sql_user.get_by_username.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
}
result . Data = & user
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2018-05-10 09:46:09 -07:00
func ( us SqlUserStore ) GetForLogin ( loginId string , allowSignInWithUsername , allowSignInWithEmail bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-05-03 14:10:36 -04:00
params := map [ string ] interface { } {
"LoginId" : loginId ,
"AllowSignInWithUsername" : allowSignInWithUsername ,
"AllowSignInWithEmail" : allowSignInWithEmail ,
}
users := [ ] * model . User { }
if _ , err := us . GetReplica ( ) . Select (
& users ,
` SELECT
*
FROM
Users
WHERE
( : AllowSignInWithUsername AND Username = : LoginId )
2018-05-10 09:46:09 -07:00
OR ( : AllowSignInWithEmail AND Email = : LoginId ) ` ,
2016-05-03 14:10:36 -04:00
params ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetForLogin" , "store.sql_user.get_for_login.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-05-03 14:10:36 -04:00
} else if len ( users ) == 1 {
result . Data = users [ 0 ]
} else if len ( users ) > 1 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetForLogin" , "store.sql_user.get_for_login.multiple_users" , nil , "" , http . StatusInternalServerError )
2016-05-03 14:10:36 -04:00
} else {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetForLogin" , "store.sql_user.get_for_login.app_error" , nil , "" , http . StatusInternalServerError )
2016-05-03 14:10:36 -04:00
}
2017-10-06 08:12:10 -07:00
} )
2016-05-03 14:10:36 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) VerifyEmail ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-05-03 03:08:48 +09:00
if _ , err := us . GetMaster ( ) . Exec ( "UPDATE Users SET EmailVerified = true WHERE Id = :UserId" , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.VerifyEmail" , "store.sql_user.verify_email.app_error" , nil , "userId=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
}
result . Data = userId
2017-10-06 08:12:10 -07:00
} )
2015-08-26 12:49:07 -04:00
}
2015-09-23 15:52:59 -07:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetTotalUsersCount ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-09-23 15:52:59 -07:00
if count , err := us . GetReplica ( ) . SelectInt ( "SELECT COUNT(Id) FROM Users" ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetTotalUsersCount" , "store.sql_user.get_total_users_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2015-10-09 12:24:39 -07:00
} else {
result . Data = count
}
2017-10-06 08:12:10 -07:00
} )
2015-10-09 12:24:39 -07:00
}
2015-11-15 18:18:02 -08:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) PermanentDelete ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-11-15 18:18:02 -08:00
if _ , err := us . GetMaster ( ) . Exec ( "DELETE FROM Users WHERE Id = :UserId" , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.PermanentDelete" , "store.sql_user.permanent_delete.app_error" , nil , "userId=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-11-15 18:18:02 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-11-15 18:18:02 -08:00
}
2016-01-21 12:14:17 -05:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) AnalyticsUniqueUserCount ( teamId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-11-08 09:59:40 -05:00
query := ""
2016-01-21 12:14:17 -05:00
if len ( teamId ) > 0 {
2016-11-08 09:59:40 -05:00
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"
} else {
query = "SELECT COUNT(DISTINCT Email) FROM Users WHERE DeleteAt = 0"
2016-01-21 12:14:17 -05:00
}
v , err := us . GetReplica ( ) . SelectInt ( query , map [ string ] interface { } { "TeamId" : teamId } )
if err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.AnalyticsUniqueUserCount" , "store.sql_user.analytics_unique_user_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-01-21 12:14:17 -05:00
} else {
result . Data = v
}
2017-10-06 08:12:10 -07:00
} )
2016-01-21 12:14:17 -05:00
}
2016-03-11 00:14:55 -03:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) AnalyticsActiveCount ( timePeriod int64 ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-01-20 15:24:53 -05:00
time := model . GetMillis ( ) - timePeriod
query := "SELECT COUNT(*) FROM Status WHERE LastActivityAt > :Time"
v , err := us . GetReplica ( ) . SelectInt ( query , map [ string ] interface { } { "Time" : time } )
if err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.AnalyticsDailyActiveUsers" , "store.sql_user.analytics_daily_active_users.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-01-20 15:24:53 -05:00
} else {
result . Data = v
}
2017-10-06 08:12:10 -07:00
} )
2017-01-20 15:24:53 -05:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetUnreadCount ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-03-07 16:05:01 -05:00
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 cm . ChannelId = c . Id
AND cm . UserId = : UserId
AND c . DeleteAt = 0 ` , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetMentionCount" , "store.sql_user.get_unread_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-03-11 00:14:55 -03:00
} else {
result . Data = count
}
2017-10-06 08:12:10 -07:00
} )
2016-03-11 00:14:55 -03:00
}
2016-08-31 12:52:14 -04:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetUnreadCountForChannel ( userId string , channelId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-08-31 12:52:14 -04:00
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetMentionCountForChannel" , "store.sql_user.get_unread_count_for_channel.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-08-31 12:52:14 -04:00
} else {
result . Data = count
}
2017-10-06 08:12:10 -07:00
} )
2016-08-31 12:52:14 -04:00
}
2016-10-19 14:49:25 -04:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) Search ( teamId string , term string , options map [ string ] bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-10-19 14:49:25 -04:00
searchQuery := ""
2016-11-02 14:38:34 -04:00
2016-10-19 14:49:25 -04:00
if teamId == "" {
2016-11-02 14:38:34 -04:00
// Id != '' is added because both SEARCH_CLAUSE and INACTIVE_CLAUSE start with an AND
2016-10-19 14:49:25 -04:00
searchQuery = `
SELECT
*
FROM
Users
WHERE
2016-11-02 14:38:34 -04:00
Id != ' '
2016-10-19 14:49:25 -04:00
SEARCH_CLAUSE
2016-11-02 14:38:34 -04:00
INACTIVE_CLAUSE
2016-10-19 14:49:25 -04:00
ORDER BY Username ASC
2016-11-24 09:35:09 -05:00
LIMIT 100 `
2016-10-19 14:49:25 -04:00
} else {
searchQuery = `
SELECT
Users . *
FROM
Users , TeamMembers
WHERE
TeamMembers . TeamId = : TeamId
AND Users . Id = TeamMembers . UserId
AND TeamMembers . DeleteAt = 0
SEARCH_CLAUSE
2016-11-02 14:38:34 -04:00
INACTIVE_CLAUSE
2016-10-19 14:49:25 -04:00
ORDER BY Users . Username ASC
LIMIT 100 `
}
2017-10-06 08:12:10 -07:00
* result = us . performSearch ( searchQuery , term , options , map [ string ] interface { } { "TeamId" : teamId } )
2017-03-23 06:34:22 -04:00
2017-10-06 08:12:10 -07:00
} )
2017-03-23 06:34:22 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) SearchWithoutTeam ( term string , options map [ string ] bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-03-23 06:34:22 -04:00
searchQuery := `
SELECT
*
FROM
Users
WHERE
( SELECT
COUNT ( 0 )
FROM
TeamMembers
WHERE
TeamMembers . UserId = Users . Id
AND TeamMembers . DeleteAt = 0 ) = 0
SEARCH_CLAUSE
INACTIVE_CLAUSE
ORDER BY Username ASC
LIMIT 100 `
2017-10-06 08:12:10 -07:00
* result = us . performSearch ( searchQuery , term , options , map [ string ] interface { } { } )
2017-04-03 18:11:12 +01:00
2017-10-06 08:12:10 -07:00
} )
2017-04-03 18:11:12 +01:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) SearchNotInTeam ( notInTeamId string , term string , options map [ string ] bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-04-03 18:11:12 +01:00
searchQuery := `
SELECT
Users . *
FROM Users
LEFT JOIN TeamMembers tm
ON tm . UserId = Users . Id
AND tm . TeamId = : NotInTeamId
WHERE
2017-04-07 19:49:02 +01:00
( tm . UserId IS NULL OR tm . DeleteAt != 0 )
2017-04-03 18:11:12 +01:00
SEARCH_CLAUSE
INACTIVE_CLAUSE
ORDER BY Users . Username ASC
LIMIT 100 `
2017-10-06 08:12:10 -07:00
* result = us . performSearch ( searchQuery , term , options , map [ string ] interface { } { "NotInTeamId" : notInTeamId } )
2016-10-19 14:49:25 -04:00
2017-10-06 08:12:10 -07:00
} )
2016-10-19 14:49:25 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) SearchNotInChannel ( teamId string , channelId string , term string , options map [ string ] bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-10-19 14:49:25 -04:00
searchQuery := ""
if teamId == "" {
searchQuery = `
SELECT
2016-11-02 14:38:34 -04:00
Users . *
FROM Users
2016-10-19 14:49:25 -04:00
LEFT JOIN ChannelMembers cm
2016-11-02 14:38:34 -04:00
ON cm . UserId = Users . Id
2016-10-19 14:49:25 -04:00
AND cm . ChannelId = : ChannelId
2016-11-02 14:38:34 -04:00
WHERE
cm . UserId IS NULL
SEARCH_CLAUSE
INACTIVE_CLAUSE
ORDER BY Users . Username ASC
2016-10-19 14:49:25 -04:00
LIMIT 100 `
} else {
searchQuery = `
SELECT
2016-11-02 14:38:34 -04:00
Users . *
FROM Users
2016-10-19 14:49:25 -04:00
INNER JOIN TeamMembers tm
2016-11-02 14:38:34 -04:00
ON tm . UserId = Users . Id
2016-10-19 14:49:25 -04:00
AND tm . TeamId = : TeamId
2016-10-24 12:00:42 -04:00
AND tm . DeleteAt = 0
2016-10-19 14:49:25 -04:00
LEFT JOIN ChannelMembers cm
2016-11-02 14:38:34 -04:00
ON cm . UserId = Users . Id
2016-10-19 14:49:25 -04:00
AND cm . ChannelId = : ChannelId
2016-11-02 14:38:34 -04:00
WHERE
cm . UserId IS NULL
SEARCH_CLAUSE
INACTIVE_CLAUSE
ORDER BY Users . Username ASC
2016-10-19 14:49:25 -04:00
LIMIT 100 `
}
2017-10-06 08:12:10 -07:00
* result = us . performSearch ( searchQuery , term , options , map [ string ] interface { } { "TeamId" : teamId , "ChannelId" : channelId } )
2016-10-19 14:49:25 -04:00
2017-10-06 08:12:10 -07:00
} )
2016-10-19 14:49:25 -04:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) SearchInChannel ( channelId string , term string , options map [ string ] bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-10-19 14:49:25 -04:00
searchQuery := `
SELECT
Users . *
FROM
Users , ChannelMembers
WHERE
ChannelMembers . ChannelId = : ChannelId
AND ChannelMembers . UserId = Users . Id
SEARCH_CLAUSE
2016-11-02 14:38:34 -04:00
INACTIVE_CLAUSE
2016-10-19 14:49:25 -04:00
ORDER BY Users . Username ASC
LIMIT 100 `
2017-10-06 08:12:10 -07:00
* result = us . performSearch ( searchQuery , term , options , map [ string ] interface { } { "ChannelId" : channelId } )
2016-10-19 14:49:25 -04:00
2017-10-06 08:12:10 -07:00
} )
2016-10-19 14:49:25 -04:00
}
2018-01-05 15:59:10 +00:00
var escapeLikeSearchChar = [ ] string {
2017-09-27 18:44:22 +01:00
"%" ,
"_" ,
2017-01-03 17:11:44 -05:00
}
2018-01-05 15:59:10 +00:00
var ignoreLikeSearchChar = [ ] string {
2017-09-27 18:44:22 +01:00
"*" ,
2016-11-21 12:17:53 -05:00
}
2018-01-05 15:59:10 +00:00
var spaceFulltextSearchChar = [ ] string {
"<" ,
">" ,
"+" ,
"-" ,
"(" ,
")" ,
"~" ,
":" ,
"*" ,
"\"" ,
"!" ,
"@" ,
}
2017-10-31 11:52:10 -04:00
func generateSearchQuery ( searchQuery string , terms [ ] string , fields [ ] string , parameters map [ string ] interface { } , isPostgreSQL bool ) string {
searchTerms := [ ] string { }
for i , term := range terms {
searchFields := [ ] string { }
for _ , field := range fields {
2017-10-11 17:20:27 +08:00
if isPostgreSQL {
2017-10-31 11:52:10 -04:00
searchFields = append ( searchFields , fmt . Sprintf ( "lower(%s) LIKE lower(%s) escape '*' " , field , fmt . Sprintf ( ":Term%d" , i ) ) )
2017-10-11 17:20:27 +08:00
} else {
2017-10-31 11:52:10 -04:00
searchFields = append ( searchFields , fmt . Sprintf ( "%s LIKE %s escape '*' " , field , fmt . Sprintf ( ":Term%d" , i ) ) )
2017-10-11 17:20:27 +08:00
}
}
2017-10-31 11:52:10 -04:00
searchTerms = append ( searchTerms , fmt . Sprintf ( "(%s)" , strings . Join ( searchFields , " OR " ) ) )
2017-10-11 17:20:27 +08:00
parameters [ fmt . Sprintf ( "Term%d" , i ) ] = fmt . Sprintf ( "%s%%" , term )
}
2017-10-31 11:52:10 -04:00
searchClause := strings . Join ( searchTerms , " AND " )
2017-10-11 17:20:27 +08:00
return strings . Replace ( searchQuery , "SEARCH_CLAUSE" , fmt . Sprintf ( " AND %s " , searchClause ) , 1 )
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) performSearch ( searchQuery string , term string , options map [ string ] bool , parameters map [ string ] interface { } ) store . StoreResult {
result := store . StoreResult { }
2016-10-19 14:49:25 -04:00
2017-09-27 18:44:22 +01:00
// These chars must be removed from the like query.
2018-01-05 15:59:10 +00:00
for _ , c := range ignoreLikeSearchChar {
2017-09-27 18:44:22 +01:00
term = strings . Replace ( term , c , "" , - 1 )
2017-01-03 17:11:44 -05:00
}
2017-09-27 18:44:22 +01:00
// These chars must be escaped in the like query.
2018-01-05 15:59:10 +00:00
for _ , c := range escapeLikeSearchChar {
2017-09-27 18:44:22 +01:00
term = strings . Replace ( term , c , "*" + c , - 1 )
2016-10-31 09:10:20 -04:00
}
2016-11-02 14:38:34 -04:00
searchType := USER_SEARCH_TYPE_ALL
2017-09-25 09:11:25 -05:00
if ok := options [ store . USER_SEARCH_OPTION_NAMES_ONLY ] ; ok {
2016-11-03 11:24:45 -04:00
searchType = USER_SEARCH_TYPE_NAMES
2017-09-25 09:11:25 -05:00
} else if ok = options [ store . USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME ] ; ok {
2016-12-02 12:24:22 -05:00
searchType = USER_SEARCH_TYPE_NAMES_NO_FULL_NAME
2017-09-25 09:11:25 -05:00
} else if ok = options [ store . USER_SEARCH_OPTION_ALL_NO_FULL_NAME ] ; ok {
2016-12-02 12:24:22 -05:00
searchType = USER_SEARCH_TYPE_ALL_NO_FULL_NAME
2016-11-02 14:38:34 -04:00
}
2017-09-25 09:11:25 -05:00
if ok := options [ store . USER_SEARCH_OPTION_ALLOW_INACTIVE ] ; ok {
2016-11-02 14:38:34 -04:00
searchQuery = strings . Replace ( searchQuery , "INACTIVE_CLAUSE" , "" , 1 )
} else {
searchQuery = strings . Replace ( searchQuery , "INACTIVE_CLAUSE" , "AND Users.DeleteAt = 0" , 1 )
}
2017-12-20 19:29:43 +00:00
if strings . TrimSpace ( term ) == "" {
2016-10-19 14:49:25 -04:00
searchQuery = strings . Replace ( searchQuery , "SEARCH_CLAUSE" , "" , 1 )
2017-09-27 18:44:22 +01:00
} else {
2017-10-11 17:20:27 +08:00
isPostgreSQL := us . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES
2017-10-31 11:52:10 -04:00
searchQuery = generateSearchQuery ( searchQuery , strings . Fields ( term ) , searchType , parameters , isPostgreSQL )
2016-10-19 14:49:25 -04:00
}
var users [ ] * model . User
if _ , err := us . GetReplica ( ) . Select ( & users , searchQuery , parameters ) ; err != nil {
2017-10-31 11:52:10 -04:00
result . Err = model . NewAppError ( "SqlUserStore.Search" , "store.sql_user.search.app_error" , nil ,
fmt . Sprintf ( "term=%v, search_type=%v, %v" , term , searchType , err . Error ( ) ) , http . StatusInternalServerError )
2016-10-19 14:49:25 -04:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2016-10-19 14:49:25 -04:00
}
result . Data = users
}
return result
}
2017-02-24 17:33:59 +00:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) AnalyticsGetInactiveUsersCount ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-02-24 17:33:59 +00:00
if count , err := us . GetReplica ( ) . SelectInt ( "SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0" ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.AnalyticsGetInactiveUsersCount" , "store.sql_user.analytics_get_inactive_users_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-02-24 17:33:59 +00:00
} else {
result . Data = count
}
2017-10-06 08:12:10 -07:00
} )
2017-02-24 17:33:59 +00:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) AnalyticsGetSystemAdminCount ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-02-24 17:33:59 +00:00
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 {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.AnalyticsGetSystemAdminCount" , "store.sql_user.analytics_get_system_admin_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-02-24 17:33:59 +00:00
} else {
result . Data = count
}
2017-10-06 08:12:10 -07:00
} )
2017-02-24 17:33:59 +00:00
}
2017-03-30 02:10:51 +01:00
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetProfilesNotInTeam ( teamId string , offset int , limit int ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-03-30 02:10:51 +01:00
var users [ ] * model . User
if _ , err := us . GetReplica ( ) . Select ( & users , `
SELECT
u . *
FROM Users u
LEFT JOIN TeamMembers tm
ON tm . UserId = u . Id
AND tm . TeamId = : TeamId
AND tm . DeleteAt = 0
WHERE tm . UserId IS NULL
ORDER BY u . Username ASC
LIMIT : Limit OFFSET : Offset
` , map [ string ] interface { } { "TeamId" : teamId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
2017-09-18 17:40:56 +01:00
result . Err = model . NewAppError ( "SqlUserStore.GetProfilesNotInTeam" , "store.sql_user.get_profiles.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-03-30 02:10:51 +01:00
} else {
for _ , u := range users {
2017-04-19 15:38:35 -04:00
u . Sanitize ( map [ string ] bool { } )
2017-03-30 02:10:51 +01:00
}
result . Data = users
}
2017-10-06 08:12:10 -07:00
} )
2017-03-30 02:10:51 +01:00
}
2017-09-25 09:11:25 -05:00
func ( us SqlUserStore ) GetEtagForProfilesNotInTeam ( teamId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-03-30 02:10:51 +01:00
updateAt , err := us . GetReplica ( ) . SelectInt ( `
SELECT
u . UpdateAt
FROM Users u
LEFT JOIN TeamMembers tm
ON tm . UserId = u . Id
AND tm . TeamId = : TeamId
AND tm . DeleteAt = 0
WHERE tm . UserId IS NULL
ORDER BY u . UpdateAt DESC
LIMIT 1
` , map [ string ] interface { } { "TeamId" : teamId } )
if err != nil {
2017-10-09 10:16:14 -07:00
result . Data = fmt . Sprintf ( "%v.%v" , model . CurrentVersion , model . GetMillis ( ) )
2017-03-30 02:10:51 +01:00
} else {
2017-10-09 10:16:14 -07:00
result . Data = fmt . Sprintf ( "%v.%v" , model . CurrentVersion , updateAt )
2017-03-30 02:10:51 +01:00
}
2017-10-06 08:12:10 -07:00
} )
2017-03-30 02:10:51 +01:00
}
2018-06-25 14:34:59 +01:00
func ( us SqlUserStore ) ClearAllCustomRoleAssignments ( ) store . StoreChannel {
return store . Do ( func ( result * store . StoreResult ) {
builtInRoles := model . MakeDefaultRoles ( )
lastUserId := strings . Repeat ( "0" , 26 )
for true {
var transaction * gorp . Transaction
var err error
if transaction , err = us . GetMaster ( ) . Begin ( ) ; err != nil {
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
var users [ ] * model . User
if _ , err := transaction . Select ( & users , "SELECT * from Users WHERE Id > :Id ORDER BY Id LIMIT 1000" , map [ string ] interface { } { "Id" : lastUserId } ) ; err != nil {
if err2 := transaction . Rollback ( ) ; err2 != nil {
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error" , nil , err2 . Error ( ) , http . StatusInternalServerError )
return
}
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.select.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
if len ( users ) == 0 {
break
}
for _ , user := range users {
lastUserId = user . Id
var newRoles [ ] string
for _ , role := range strings . Fields ( user . Roles ) {
for name := range builtInRoles {
if name == role {
newRoles = append ( newRoles , role )
break
}
}
}
newRolesString := strings . Join ( newRoles , " " )
if newRolesString != user . Roles {
if _ , err := transaction . Exec ( "UPDATE Users SET Roles = :Roles WHERE Id = :Id" , map [ string ] interface { } { "Roles" : newRolesString , "Id" : user . Id } ) ; err != nil {
if err2 := transaction . Rollback ( ) ; err2 != nil {
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error" , nil , err2 . Error ( ) , http . StatusInternalServerError )
return
}
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.update.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
}
}
if err := transaction . Commit ( ) ; err != nil {
if err2 := transaction . Rollback ( ) ; err2 != nil {
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.rollback_transaction.app_error" , nil , err2 . Error ( ) , http . StatusInternalServerError )
return
}
result . Err = model . NewAppError ( "SqlUserStore.ClearAllCustomRoleAssignments" , "store.sql_user.clear_all_custom_role_assignments.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
}
} )
}