github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+incompatible/store/sqlstore/user_access_token_store.go (about) 1 // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "net/http" 9 10 "github.com/mattermost/gorp" 11 "github.com/mattermost/mattermost-server/model" 12 "github.com/mattermost/mattermost-server/store" 13 ) 14 15 type SqlUserAccessTokenStore struct { 16 SqlStore 17 } 18 19 func NewSqlUserAccessTokenStore(sqlStore SqlStore) store.UserAccessTokenStore { 20 s := &SqlUserAccessTokenStore{sqlStore} 21 22 for _, db := range sqlStore.GetAllConns() { 23 table := db.AddTableWithName(model.UserAccessToken{}, "UserAccessTokens").SetKeys(false, "Id") 24 table.ColMap("Id").SetMaxSize(26) 25 table.ColMap("Token").SetMaxSize(26).SetUnique(true) 26 table.ColMap("UserId").SetMaxSize(26) 27 table.ColMap("Description").SetMaxSize(512) 28 } 29 30 return s 31 } 32 33 func (s SqlUserAccessTokenStore) CreateIndexesIfNotExists() { 34 s.CreateIndexIfNotExists("idx_user_access_tokens_token", "UserAccessTokens", "Token") 35 s.CreateIndexIfNotExists("idx_user_access_tokens_user_id", "UserAccessTokens", "UserId") 36 } 37 38 func (s SqlUserAccessTokenStore) Save(token *model.UserAccessToken) store.StoreChannel { 39 return store.Do(func(result *store.StoreResult) { 40 token.PreSave() 41 42 if result.Err = token.IsValid(); result.Err != nil { 43 return 44 } 45 46 if err := s.GetMaster().Insert(token); err != nil { 47 result.Err = model.NewAppError("SqlUserAccessTokenStore.Save", "store.sql_user_access_token.save.app_error", nil, "", http.StatusInternalServerError) 48 } else { 49 result.Data = token 50 } 51 }) 52 } 53 54 func (s SqlUserAccessTokenStore) Delete(tokenId string) store.StoreChannel { 55 return store.Do(func(result *store.StoreResult) { 56 transaction, err := s.GetMaster().Begin() 57 if err != nil { 58 result.Err = model.NewAppError("SqlUserAccessTokenStore.Delete", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 59 } else { 60 if extrasResult := s.deleteSessionsAndTokensById(transaction, tokenId); extrasResult.Err != nil { 61 *result = extrasResult 62 } 63 64 if result.Err == nil { 65 if err := transaction.Commit(); err != nil { 66 // don't need to rollback here since the transaction is already closed 67 result.Err = model.NewAppError("SqlUserAccessTokenStore.Delete", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 68 } 69 } else { 70 if err := transaction.Rollback(); err != nil { 71 result.Err = model.NewAppError("SqlUserAccessTokenStore.Delete", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 72 } 73 } 74 } 75 }) 76 } 77 78 func (s SqlUserAccessTokenStore) deleteSessionsAndTokensById(transaction *gorp.Transaction, tokenId string) store.StoreResult { 79 result := store.StoreResult{} 80 81 query := "" 82 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 83 query = "DELETE FROM Sessions s USING UserAccessTokens o WHERE o.Token = s.Token AND o.Id = :Id" 84 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 85 query = "DELETE s.* FROM Sessions s INNER JOIN UserAccessTokens o ON o.Token = s.Token WHERE o.Id = :Id" 86 } 87 88 if _, err := transaction.Exec(query, map[string]interface{}{"Id": tokenId}); err != nil { 89 result.Err = model.NewAppError("SqlUserAccessTokenStore.deleteSessionsById", "store.sql_user_access_token.delete.app_error", nil, "id="+tokenId+", err="+err.Error(), http.StatusInternalServerError) 90 return result 91 } 92 93 return s.deleteTokensById(transaction, tokenId) 94 } 95 96 func (s SqlUserAccessTokenStore) deleteTokensById(transaction *gorp.Transaction, tokenId string) store.StoreResult { 97 result := store.StoreResult{} 98 99 if _, err := transaction.Exec("DELETE FROM UserAccessTokens WHERE Id = :Id", map[string]interface{}{"Id": tokenId}); err != nil { 100 result.Err = model.NewAppError("SqlUserAccessTokenStore.deleteTokensById", "store.sql_user_access_token.delete.app_error", nil, "", http.StatusInternalServerError) 101 } 102 103 return result 104 } 105 106 func (s SqlUserAccessTokenStore) DeleteAllForUser(userId string) store.StoreChannel { 107 return store.Do(func(result *store.StoreResult) { 108 transaction, err := s.GetMaster().Begin() 109 if err != nil { 110 result.Err = model.NewAppError("SqlUserAccessTokenStore.DeleteAllForUser", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 111 } else { 112 if extrasResult := s.deleteSessionsandTokensByUser(transaction, userId); extrasResult.Err != nil { 113 *result = extrasResult 114 } 115 116 if result.Err == nil { 117 if err := transaction.Commit(); err != nil { 118 // don't need to rollback here since the transaction is already closed 119 result.Err = model.NewAppError("SqlUserAccessTokenStore.DeleteAllForUser", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 120 } 121 } else { 122 if err := transaction.Rollback(); err != nil { 123 result.Err = model.NewAppError("SqlUserAccessTokenStore.DeleteAllForUser", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 124 } 125 } 126 } 127 }) 128 } 129 130 func (s SqlUserAccessTokenStore) deleteSessionsandTokensByUser(transaction *gorp.Transaction, userId string) store.StoreResult { 131 result := store.StoreResult{} 132 133 query := "" 134 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 135 query = "DELETE FROM Sessions s USING UserAccessTokens o WHERE o.Token = s.Token AND o.UserId = :UserId" 136 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 137 query = "DELETE s.* FROM Sessions s INNER JOIN UserAccessTokens o ON o.Token = s.Token WHERE o.UserId = :UserId" 138 } 139 140 if _, err := transaction.Exec(query, map[string]interface{}{"UserId": userId}); err != nil { 141 result.Err = model.NewAppError("SqlUserAccessTokenStore.deleteSessionsByUser", "store.sql_user_access_token.delete.app_error", nil, "user_id="+userId+", err="+err.Error(), http.StatusInternalServerError) 142 return result 143 } 144 145 return s.deleteTokensByUser(transaction, userId) 146 } 147 148 func (s SqlUserAccessTokenStore) deleteTokensByUser(transaction *gorp.Transaction, userId string) store.StoreResult { 149 result := store.StoreResult{} 150 151 if _, err := transaction.Exec("DELETE FROM UserAccessTokens WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 152 result.Err = model.NewAppError("SqlUserAccessTokenStore.deleteTokensByUser", "store.sql_user_access_token.delete.app_error", nil, "", http.StatusInternalServerError) 153 } 154 155 return result 156 } 157 158 func (s SqlUserAccessTokenStore) Get(tokenId string) store.StoreChannel { 159 return store.Do(func(result *store.StoreResult) { 160 token := model.UserAccessToken{} 161 162 if err := s.GetReplica().SelectOne(&token, "SELECT * FROM UserAccessTokens WHERE Id = :Id", map[string]interface{}{"Id": tokenId}); err != nil { 163 if err == sql.ErrNoRows { 164 result.Err = model.NewAppError("SqlUserAccessTokenStore.Get", "store.sql_user_access_token.get.app_error", nil, err.Error(), http.StatusNotFound) 165 } else { 166 result.Err = model.NewAppError("SqlUserAccessTokenStore.Get", "store.sql_user_access_token.get.app_error", nil, err.Error(), http.StatusInternalServerError) 167 } 168 } 169 170 result.Data = &token 171 }) 172 } 173 174 func (s SqlUserAccessTokenStore) GetAll(offset, limit int) store.StoreChannel { 175 return store.Do(func(result *store.StoreResult) { 176 tokens := []*model.UserAccessToken{} 177 178 if _, err := s.GetReplica().Select(&tokens, "SELECT * FROM UserAccessTokens LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil { 179 result.Err = model.NewAppError("SqlUserAccessTokenStore.GetAll", "store.sql_user_access_token.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 180 } 181 182 result.Data = tokens 183 }) 184 } 185 186 func (s SqlUserAccessTokenStore) GetByToken(tokenString string) store.StoreChannel { 187 return store.Do(func(result *store.StoreResult) { 188 token := model.UserAccessToken{} 189 190 if err := s.GetReplica().SelectOne(&token, "SELECT * FROM UserAccessTokens WHERE Token = :Token", map[string]interface{}{"Token": tokenString}); err != nil { 191 if err == sql.ErrNoRows { 192 result.Err = model.NewAppError("SqlUserAccessTokenStore.GetByToken", "store.sql_user_access_token.get_by_token.app_error", nil, err.Error(), http.StatusNotFound) 193 } else { 194 result.Err = model.NewAppError("SqlUserAccessTokenStore.GetByToken", "store.sql_user_access_token.get_by_token.app_error", nil, err.Error(), http.StatusInternalServerError) 195 } 196 } 197 198 result.Data = &token 199 }) 200 } 201 202 func (s SqlUserAccessTokenStore) GetByUser(userId string, offset, limit int) store.StoreChannel { 203 return store.Do(func(result *store.StoreResult) { 204 tokens := []*model.UserAccessToken{} 205 206 if _, err := s.GetReplica().Select(&tokens, "SELECT * FROM UserAccessTokens WHERE UserId = :UserId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"UserId": userId, "Offset": offset, "Limit": limit}); err != nil { 207 result.Err = model.NewAppError("SqlUserAccessTokenStore.GetByUser", "store.sql_user_access_token.get_by_user.app_error", nil, err.Error(), http.StatusInternalServerError) 208 } 209 210 result.Data = tokens 211 }) 212 } 213 214 func (s SqlUserAccessTokenStore) Search(term string) store.StoreChannel { 215 return store.Do(func(result *store.StoreResult) { 216 tokens := []*model.UserAccessToken{} 217 params := map[string]interface{}{"Term": term + "%"} 218 query := ` 219 SELECT 220 uat.* 221 FROM UserAccessTokens uat 222 INNER JOIN Users u 223 ON uat.UserId = u.Id 224 WHERE uat.Id LIKE :Term OR uat.UserId LIKE :Term OR u.Username LIKE :Term` 225 226 if _, err := s.GetReplica().Select(&tokens, query, params); err != nil { 227 result.Err = model.NewAppError("SqlUserAccessTokenStore.Search", "store.sql_user_access_token.search.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError) 228 } 229 230 result.Data = tokens 231 }) 232 } 233 234 func (s SqlUserAccessTokenStore) UpdateTokenEnable(tokenId string) store.StoreChannel { 235 return store.Do(func(result *store.StoreResult) { 236 if _, err := s.GetMaster().Exec("UPDATE UserAccessTokens SET IsActive = TRUE WHERE Id = :Id", map[string]interface{}{"Id": tokenId}); err != nil { 237 result.Err = model.NewAppError("SqlUserAccessTokenStore.UpdateTokenEnable", "store.sql_user_access_token.update_token_enable.app_error", nil, "id="+tokenId+", "+err.Error(), http.StatusInternalServerError) 238 } else { 239 result.Data = tokenId 240 } 241 }) 242 } 243 244 func (s SqlUserAccessTokenStore) UpdateTokenDisable(tokenId string) store.StoreChannel { 245 return store.Do(func(result *store.StoreResult) { 246 transaction, err := s.GetMaster().Begin() 247 if err != nil { 248 result.Err = model.NewAppError("SqlUserAccessTokenStore.UpdateTokenDisable", "store.sql_user_access_token.update_token_disble.app_error", nil, err.Error(), http.StatusInternalServerError) 249 } else { 250 if extrasResult := s.deleteSessionsAndDisableToken(transaction, tokenId); extrasResult.Err != nil { 251 *result = extrasResult 252 } 253 254 if result.Err == nil { 255 if err := transaction.Commit(); err != nil { 256 // don't need to rollback here since the transaction is already closed 257 result.Err = model.NewAppError("SqlUserAccessTokenStore.UpdateTokenDisable", "store.sql_user_access_token.update_token_disable.app_error", nil, err.Error(), http.StatusInternalServerError) 258 } 259 } else { 260 if err := transaction.Rollback(); err != nil { 261 result.Err = model.NewAppError("SqlUserAccessTokenStore.UpdateTokenDisable", "store.sql_user_access_token.update_token_disable.app_error", nil, err.Error(), http.StatusInternalServerError) 262 } 263 } 264 } 265 }) 266 } 267 268 func (s SqlUserAccessTokenStore) deleteSessionsAndDisableToken(transaction *gorp.Transaction, tokenId string) store.StoreResult { 269 result := store.StoreResult{} 270 271 query := "" 272 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 273 query = "DELETE FROM Sessions s USING UserAccessTokens o WHERE o.Token = s.Token AND o.Id = :Id" 274 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 275 query = "DELETE s.* FROM Sessions s INNER JOIN UserAccessTokens o ON o.Token = s.Token WHERE o.Id = :Id" 276 } 277 278 if _, err := transaction.Exec(query, map[string]interface{}{"Id": tokenId}); err != nil { 279 result.Err = model.NewAppError("SqlUserAccessTokenStore.deleteSessionsAndDisableToken", "store.sql_user_access_token.update_token_disable.app_error", nil, "id="+tokenId+", err="+err.Error(), http.StatusInternalServerError) 280 return result 281 } 282 283 return s.updateTokenDisable(transaction, tokenId) 284 } 285 286 func (s SqlUserAccessTokenStore) updateTokenDisable(transaction *gorp.Transaction, tokenId string) store.StoreResult { 287 result := store.StoreResult{} 288 289 if _, err := transaction.Exec("UPDATE UserAccessTokens SET IsActive = FALSE WHERE Id = :Id", map[string]interface{}{"Id": tokenId}); err != nil { 290 result.Err = model.NewAppError("SqlUserAccessTokenStore.updateTokenDisable", "store.sql_user_access_token.update_token_disable.app_error", nil, "", http.StatusInternalServerError) 291 } 292 293 return result 294 }