2017-04-12 08:27:57 -04:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2015-09-16 15:49:12 -04:00
// See License.txt for license information.
2017-09-25 09:11:25 -05:00
package sqlstore
2015-09-16 15:49:12 -04:00
import (
2017-04-12 16:29:42 -04:00
"net/http"
2016-09-19 19:30:41 +07:00
"strings"
2017-05-29 15:46:35 -04:00
"github.com/mattermost/gorp"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/model"
2017-09-25 09:11:25 -05:00
"github.com/mattermost/mattermost-server/store"
2015-09-16 15:49:12 -04:00
)
type SqlOAuthStore struct {
2017-06-27 08:02:08 -07:00
SqlStore
2015-09-16 15:49:12 -04:00
}
2017-09-25 09:11:25 -05:00
func NewSqlOAuthStore ( sqlStore SqlStore ) store . OAuthStore {
2015-09-16 15:49:12 -04:00
as := & SqlOAuthStore { sqlStore }
for _ , db := range sqlStore . GetAllConns ( ) {
table := db . AddTableWithName ( model . OAuthApp { } , "OAuthApps" ) . SetKeys ( false , "Id" )
table . ColMap ( "Id" ) . SetMaxSize ( 26 )
table . ColMap ( "CreatorId" ) . SetMaxSize ( 26 )
table . ColMap ( "ClientSecret" ) . SetMaxSize ( 128 )
table . ColMap ( "Name" ) . SetMaxSize ( 64 )
table . ColMap ( "Description" ) . SetMaxSize ( 512 )
table . ColMap ( "CallbackUrls" ) . SetMaxSize ( 1024 )
table . ColMap ( "Homepage" ) . SetMaxSize ( 256 )
2016-08-03 12:19:27 -05:00
table . ColMap ( "IconURL" ) . SetMaxSize ( 512 )
2015-09-16 15:49:12 -04:00
tableAuth := db . AddTableWithName ( model . AuthData { } , "OAuthAuthData" ) . SetKeys ( false , "Code" )
tableAuth . ColMap ( "UserId" ) . SetMaxSize ( 26 )
tableAuth . ColMap ( "ClientId" ) . SetMaxSize ( 26 )
tableAuth . ColMap ( "Code" ) . SetMaxSize ( 128 )
tableAuth . ColMap ( "RedirectUri" ) . SetMaxSize ( 256 )
2018-02-07 16:21:22 -05:00
tableAuth . ColMap ( "State" ) . SetMaxSize ( 1024 )
2015-09-16 15:49:12 -04:00
tableAuth . ColMap ( "Scope" ) . SetMaxSize ( 128 )
tableAccess := db . AddTableWithName ( model . AccessData { } , "OAuthAccessData" ) . SetKeys ( false , "Token" )
2016-08-03 12:19:27 -05:00
tableAccess . ColMap ( "ClientId" ) . SetMaxSize ( 26 )
tableAccess . ColMap ( "UserId" ) . SetMaxSize ( 26 )
2015-09-16 15:49:12 -04:00
tableAccess . ColMap ( "Token" ) . SetMaxSize ( 26 )
tableAccess . ColMap ( "RefreshToken" ) . SetMaxSize ( 26 )
tableAccess . ColMap ( "RedirectUri" ) . SetMaxSize ( 256 )
2017-04-12 16:29:42 -04:00
tableAccess . ColMap ( "Scope" ) . SetMaxSize ( 128 )
2016-08-03 12:19:27 -05:00
tableAccess . SetUniqueTogether ( "ClientId" , "UserId" )
2015-09-16 15:49:12 -04:00
}
return as
}
func ( as SqlOAuthStore ) CreateIndexesIfNotExists ( ) {
as . CreateIndexIfNotExists ( "idx_oauthapps_creator_id" , "OAuthApps" , "CreatorId" )
2016-08-03 12:19:27 -05:00
as . CreateIndexIfNotExists ( "idx_oauthaccessdata_client_id" , "OAuthAccessData" , "ClientId" )
as . CreateIndexIfNotExists ( "idx_oauthaccessdata_user_id" , "OAuthAccessData" , "UserId" )
as . CreateIndexIfNotExists ( "idx_oauthaccessdata_refresh_token" , "OAuthAccessData" , "RefreshToken" )
2015-09-16 15:49:12 -04:00
as . CreateIndexIfNotExists ( "idx_oauthauthdata_client_id" , "OAuthAuthData" , "Code" )
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) SaveApp ( app * model . OAuthApp ) ( * model . OAuthApp , * model . AppError ) {
if len ( app . Id ) > 0 {
return nil , model . NewAppError ( "SqlOAuthStore.SaveApp" , "store.sql_oauth.save_app.existing.app_error" , nil , "app_id=" + app . Id , http . StatusBadRequest )
}
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
app . PreSave ( )
if err := app . IsValid ( ) ; err != nil {
return nil , err
}
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if err := as . GetMaster ( ) . Insert ( app ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.SaveApp" , "store.sql_oauth.save_app.save.app_error" , nil , "app_id=" + app . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
}
return app , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) UpdateApp ( app * model . OAuthApp ) ( * model . OAuthApp , * model . AppError ) {
app . PreUpdate ( )
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if err := app . IsValid ( ) ; err != nil {
return nil , err
}
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
oldAppResult , err := as . GetMaster ( ) . Get ( model . OAuthApp { } , app . Id )
if err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.UpdateApp" , "store.sql_oauth.update_app.finding.app_error" , nil , "app_id=" + app . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
}
if oldAppResult == nil {
return nil , model . NewAppError ( "SqlOAuthStore.UpdateApp" , "store.sql_oauth.update_app.find.app_error" , nil , "app_id=" + app . Id , http . StatusBadRequest )
}
oldApp := oldAppResult . ( * model . OAuthApp )
app . CreateAt = oldApp . CreateAt
app . CreatorId = oldApp . CreatorId
count , err := as . GetMaster ( ) . Update ( app )
if err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.UpdateApp" , "store.sql_oauth.update_app.updating.app_error" , nil , "app_id=" + app . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
}
if count != 1 {
return nil , model . NewAppError ( "SqlOAuthStore.UpdateApp" , "store.sql_oauth.update_app.update.app_error" , nil , "app_id=" + app . Id , http . StatusBadRequest )
}
return app , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetApp ( id string ) ( * model . OAuthApp , * model . AppError ) {
obj , err := as . GetReplica ( ) . Get ( model . OAuthApp { } , id )
if err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetApp" , "store.sql_oauth.get_app.finding.app_error" , nil , "app_id=" + id + ", " + err . Error ( ) , http . StatusInternalServerError )
}
if obj == nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetApp" , "store.sql_oauth.get_app.find.app_error" , nil , "app_id=" + id , http . StatusNotFound )
}
return obj . ( * model . OAuthApp ) , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetAppByUser ( userId string , offset , limit int ) ( [ ] * model . OAuthApp , * model . AppError ) {
var apps [ ] * model . OAuthApp
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if _ , err := as . GetReplica ( ) . Select ( & apps , "SELECT * FROM OAuthApps WHERE CreatorId = :UserId LIMIT :Limit OFFSET :Offset" , map [ string ] interface { } { "UserId" : userId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAppByUser" , "store.sql_oauth.get_app_by_user.find.app_error" , nil , "user_id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
return apps , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetApps ( offset , limit int ) ( [ ] * model . OAuthApp , * model . AppError ) {
var apps [ ] * model . OAuthApp
2016-08-03 12:19:27 -05:00
2019-06-21 18:21:18 +02:00
if _ , err := as . GetReplica ( ) . Select ( & apps , "SELECT * FROM OAuthApps LIMIT :Limit OFFSET :Offset" , map [ string ] interface { } { "Offset" : offset , "Limit" : limit } ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAppByUser" , "store.sql_oauth.get_apps.find.app_error" , nil , "err=" + err . Error ( ) , http . StatusInternalServerError )
}
2016-08-03 12:19:27 -05:00
2019-06-21 18:21:18 +02:00
return apps , nil
2016-08-03 12:19:27 -05:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetAuthorizedApps ( userId string , offset , limit int ) ( [ ] * model . OAuthApp , * model . AppError ) {
var apps [ ] * model . OAuthApp
2016-08-23 19:06:17 -03:00
2019-06-21 18:21:18 +02:00
if _ , err := as . GetReplica ( ) . Select ( & apps ,
` SELECT o . * FROM OAuthApps AS o INNER JOIN
2017-04-12 16:29:42 -04:00
Preferences AS p ON p . Name = o . Id AND p . UserId = : UserId LIMIT : Limit OFFSET : Offset ` , map [ string ] interface { } { "UserId" : userId , "Offset" : offset , "Limit" : limit } ) ; err != nil {
2019-06-21 18:21:18 +02:00
return nil , model . NewAppError ( "SqlOAuthStore.GetAuthorizedApps" , "store.sql_oauth.get_apps.find.app_error" , nil , "err=" + err . Error ( ) , http . StatusInternalServerError )
}
2016-08-23 19:06:17 -03:00
2019-06-21 18:21:18 +02:00
return apps , nil
2016-08-23 19:06:17 -03:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) DeleteApp ( id string ) * model . AppError {
// wrap in a transaction so that if one fails, everything fails
transaction , err := as . GetMaster ( ) . Begin ( )
if err != nil {
return model . NewAppError ( "SqlOAuthStore.DeleteApp" , "store.sql_oauth.delete.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
if err := as . deleteApp ( transaction , id ) ; err != nil {
return err
}
if err := transaction . Commit ( ) ; err != nil {
// don't need to rollback here since the transaction is already closed
return model . NewAppError ( "SqlOAuthStore.DeleteApp" , "store.sql_oauth.delete.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return nil
2016-08-03 12:19:27 -05:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) SaveAccessData ( accessData * model . AccessData ) ( * model . AccessData , * model . AppError ) {
if err := accessData . IsValid ( ) ; err != nil {
return nil , err
}
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if err := as . GetMaster ( ) . Insert ( accessData ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.SaveAccessData" , "store.sql_oauth.save_access_data.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return accessData , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetAccessData ( token string ) ( * model . AccessData , * model . AppError ) {
accessData := model . AccessData { }
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if err := as . GetReplica ( ) . SelectOne ( & accessData , "SELECT * FROM OAuthAccessData WHERE Token = :Token" , map [ string ] interface { } { "Token" : token } ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAccessData" , "store.sql_oauth.get_access_data.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return & accessData , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetAccessDataByUserForApp ( userId , clientId string ) ( [ ] * model . AccessData , * model . AppError ) {
var accessData [ ] * model . AccessData
2016-08-23 19:06:17 -03:00
2019-06-21 18:21:18 +02:00
if _ , err := as . GetReplica ( ) . Select ( & accessData ,
"SELECT * FROM OAuthAccessData WHERE UserId = :UserId AND ClientId = :ClientId" ,
map [ string ] interface { } { "UserId" : userId , "ClientId" : clientId } ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAccessDataByUserForApp" , "store.sql_oauth.get_access_data_by_user_for_app.app_error" , nil , "user_id=" + userId + " client_id=" + clientId , http . StatusInternalServerError )
}
return accessData , nil
2016-08-23 19:06:17 -03:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetAccessDataByRefreshToken ( token string ) ( * model . AccessData , * model . AppError ) {
accessData := model . AccessData { }
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if err := as . GetReplica ( ) . SelectOne ( & accessData , "SELECT * FROM OAuthAccessData WHERE RefreshToken = :Token" , map [ string ] interface { } { "Token" : token } ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAccessData" , "store.sql_oauth.get_access_data.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return & accessData , nil
2016-08-03 12:19:27 -05:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetPreviousAccessData ( userId , clientId string ) ( * model . AccessData , * model . AppError ) {
accessData := model . AccessData { }
if err := as . GetReplica ( ) . SelectOne ( & accessData , "SELECT * FROM OAuthAccessData WHERE ClientId = :ClientId AND UserId = :UserId" ,
map [ string ] interface { } { "ClientId" : clientId , "UserId" : userId } ) ; err != nil {
if strings . Contains ( err . Error ( ) , "no rows" ) {
return nil , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
return nil , model . NewAppError ( "SqlOAuthStore.GetPreviousAccessData" , "store.sql_oauth.get_previous_access_data.app_error" , nil , err . Error ( ) , http . StatusNotFound )
}
return & accessData , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) UpdateAccessData ( accessData * model . AccessData ) ( * model . AccessData , * model . AppError ) {
if err := accessData . IsValid ( ) ; err != nil {
return nil , err
}
2017-04-03 14:37:58 -03:00
2019-06-21 18:21:18 +02:00
if _ , err := as . GetMaster ( ) . Exec ( "UPDATE OAuthAccessData SET Token = :Token, ExpiresAt = :ExpiresAt, RefreshToken = :RefreshToken WHERE ClientId = :ClientId AND UserID = :UserId" ,
map [ string ] interface { } { "Token" : accessData . Token , "ExpiresAt" : accessData . ExpiresAt , "RefreshToken" : accessData . RefreshToken , "ClientId" : accessData . ClientId , "UserId" : accessData . UserId } ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.Update" , "store.sql_oauth.update_access_data.app_error" , nil ,
"clientId=" + accessData . ClientId + ",userId=" + accessData . UserId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
return accessData , nil
2016-08-03 12:19:27 -05:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) RemoveAccessData ( token string ) * model . AppError {
if _ , err := as . GetMaster ( ) . Exec ( "DELETE FROM OAuthAccessData WHERE Token = :Token" , map [ string ] interface { } { "Token" : token } ) ; err != nil {
return model . NewAppError ( "SqlOAuthStore.RemoveAccessData" , "store.sql_oauth.remove_access_data.app_error" , nil , "err=" + err . Error ( ) , http . StatusInternalServerError )
2019-07-01 23:28:46 +02:00
}
return nil
}
func ( as SqlOAuthStore ) RemoveAllAccessData ( ) * model . AppError {
if _ , err := as . GetMaster ( ) . Exec ( "DELETE FROM OAuthAccessData" , map [ string ] interface { } { } ) ; err != nil {
return model . NewAppError ( "SqlOAuthStore.RemoveAccessData" , "store.sql_oauth.remove_access_data.app_error" , nil , "err=" + err . Error ( ) , http . StatusInternalServerError )
2019-06-21 18:21:18 +02:00
}
return nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) SaveAuthData ( authData * model . AuthData ) ( * model . AuthData , * model . AppError ) {
authData . PreSave ( )
if err := authData . IsValid ( ) ; err != nil {
return nil , err
}
2015-09-16 15:49:12 -04:00
2019-06-21 18:21:18 +02:00
if err := as . GetMaster ( ) . Insert ( authData ) ; err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.SaveAuthData" , "store.sql_oauth.save_auth_data.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return authData , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) GetAuthData ( code string ) ( * model . AuthData , * model . AppError ) {
obj , err := as . GetReplica ( ) . Get ( model . AuthData { } , code )
if err != nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAuthData" , "store.sql_oauth.get_auth_data.finding.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
if obj == nil {
return nil , model . NewAppError ( "SqlOAuthStore.GetAuthData" , "store.sql_oauth.get_auth_data.find.app_error" , nil , "" , http . StatusNotFound )
}
return obj . ( * model . AuthData ) , nil
2015-09-16 15:49:12 -04:00
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) RemoveAuthData ( code string ) * model . AppError {
_ , err := as . GetMaster ( ) . Exec ( "DELETE FROM OAuthAuthData WHERE Code = :Code" , map [ string ] interface { } { "Code" : code } )
if err != nil {
return model . NewAppError ( "SqlOAuthStore.RemoveAuthData" , "store.sql_oauth.remove_auth_data.app_error" , nil , "err=" + err . Error ( ) , http . StatusInternalServerError )
}
return nil
2015-09-16 15:49:12 -04:00
}
2015-11-15 18:18:02 -08:00
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) PermanentDeleteAuthDataByUser ( userId string ) * model . AppError {
_ , err := as . GetMaster ( ) . Exec ( "DELETE FROM OAuthAccessData WHERE UserId = :UserId" , map [ string ] interface { } { "UserId" : userId } )
if err != nil {
return model . NewAppError ( "SqlOAuthStore.RemoveAuthDataByUserId" , "store.sql_oauth.permanent_delete_auth_data_by_user.app_error" , nil , "err=" + err . Error ( ) , http . StatusInternalServerError )
}
return nil
2015-11-15 18:18:02 -08:00
}
2016-08-03 12:19:27 -05:00
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) deleteApp ( transaction * gorp . Transaction , clientId string ) * model . AppError {
2016-08-03 12:19:27 -05:00
if _ , err := transaction . Exec ( "DELETE FROM OAuthApps WHERE Id = :Id" , map [ string ] interface { } { "Id" : clientId } ) ; err != nil {
2019-06-21 18:21:18 +02:00
return model . NewAppError ( "SqlOAuthStore.DeleteApp" , "store.sql_oauth.delete_app.app_error" , nil , "id=" + clientId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2016-08-03 12:19:27 -05:00
}
2017-07-12 16:58:51 -04:00
return as . deleteOAuthAppSessions ( transaction , clientId )
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) deleteOAuthAppSessions ( transaction * gorp . Transaction , clientId string ) * model . AppError {
2017-07-12 16:58:51 -04:00
2017-07-13 15:12:28 -04:00
query := ""
2017-10-09 10:16:14 -07:00
if as . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
2017-07-13 15:12:28 -04:00
query = "DELETE FROM Sessions s USING OAuthAccessData o WHERE o.Token = s.Token AND o.ClientId = :Id"
2017-10-09 10:16:14 -07:00
} else if as . DriverName ( ) == model . DATABASE_DRIVER_MYSQL {
2017-07-13 15:12:28 -04:00
query = "DELETE s.* FROM Sessions s INNER JOIN OAuthAccessData o ON o.Token = s.Token WHERE o.ClientId = :Id"
}
if _ , err := transaction . Exec ( query , map [ string ] interface { } { "Id" : clientId } ) ; err != nil {
2019-06-21 18:21:18 +02:00
return model . NewAppError ( "SqlOAuthStore.DeleteApp" , "store.sql_oauth.delete_app.app_error" , nil , "id=" + clientId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2017-07-12 16:58:51 -04:00
}
2016-08-03 12:19:27 -05:00
return as . deleteOAuthTokens ( transaction , clientId )
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) deleteOAuthTokens ( transaction * gorp . Transaction , clientId string ) * model . AppError {
2016-08-03 12:19:27 -05:00
if _ , err := transaction . Exec ( "DELETE FROM OAuthAccessData WHERE ClientId = :Id" , map [ string ] interface { } { "Id" : clientId } ) ; err != nil {
2019-06-21 18:21:18 +02:00
return model . NewAppError ( "SqlOAuthStore.DeleteApp" , "store.sql_oauth.delete_app.app_error" , nil , "id=" + clientId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2016-08-03 12:19:27 -05:00
}
return as . deleteAppExtras ( transaction , clientId )
}
2019-06-21 18:21:18 +02:00
func ( as SqlOAuthStore ) deleteAppExtras ( transaction * gorp . Transaction , clientId string ) * model . AppError {
2016-08-03 12:19:27 -05:00
if _ , err := transaction . Exec (
` DELETE FROM
Preferences
WHERE
Category = : Category
AND Name = : Name ` , map [ string ] interface { } { "Category" : model . PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP , "Name" : clientId } ) ; err != nil {
2019-06-21 18:21:18 +02:00
return model . NewAppError ( "SqlOAuthStore.DeleteApp" , "store.sql_preference.delete.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-08-03 12:19:27 -05:00
}
2019-06-21 18:21:18 +02:00
return nil
2016-08-03 12:19:27 -05:00
}