2015-12-10 14:33:21 -08:00
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
2015-10-01 10:56:07 -04:00
// See License.txt for license information.
package store
import (
2016-01-11 09:12:51 -06:00
l4g "github.com/alecthomas/log4go"
2015-10-09 13:47:11 -04:00
"github.com/go-gorp/gorp"
2015-10-01 10:56:07 -04:00
"github.com/mattermost/platform/model"
2015-10-08 10:52:20 -04:00
"github.com/mattermost/platform/utils"
2015-10-01 10:56:07 -04:00
)
type SqlPreferenceStore struct {
* SqlStore
}
2015-11-13 22:56:41 +01:00
const (
FEATURE_TOGGLE_PREFIX = "feature_enabled_"
)
2015-10-01 10:56:07 -04:00
func NewSqlPreferenceStore ( sqlStore * SqlStore ) PreferenceStore {
s := & SqlPreferenceStore { sqlStore }
for _ , db := range sqlStore . GetAllConns ( ) {
2015-10-13 11:52:17 -04:00
table := db . AddTableWithName ( model . Preference { } , "Preferences" ) . SetKeys ( false , "UserId" , "Category" , "Name" )
2015-10-01 10:56:07 -04:00
table . ColMap ( "UserId" ) . SetMaxSize ( 26 )
table . ColMap ( "Category" ) . SetMaxSize ( 32 )
table . ColMap ( "Name" ) . SetMaxSize ( 32 )
table . ColMap ( "Value" ) . SetMaxSize ( 128 )
}
return s
}
func ( s SqlPreferenceStore ) UpgradeSchemaIfNeeded ( ) {
}
func ( s SqlPreferenceStore ) CreateIndexesIfNotExists ( ) {
s . CreateIndexIfNotExists ( "idx_preferences_user_id" , "Preferences" , "UserId" )
s . CreateIndexIfNotExists ( "idx_preferences_category" , "Preferences" , "Category" )
s . CreateIndexIfNotExists ( "idx_preferences_name" , "Preferences" , "Name" )
}
2015-11-13 22:56:41 +01:00
func ( s SqlPreferenceStore ) DeleteUnusedFeatures ( ) {
l4g . Debug ( "Deleting any unused pre-release features" )
sql := ` DELETE
FROM Preferences
WHERE
Category = : Category
AND Value = : Value
AND Name LIKE ' ` + FEATURE_TOGGLE_PREFIX + ` % ' `
queryParams := map [ string ] string {
2015-11-27 02:20:06 +01:00
"Category" : model . PREFERENCE_CATEGORY_ADVANCED_SETTINGS ,
2015-11-13 22:56:41 +01:00
"Value" : "false" ,
}
s . GetMaster ( ) . Exec ( sql , queryParams )
}
2015-10-09 13:47:11 -04:00
func ( s SqlPreferenceStore ) Save ( preferences * model . Preferences ) StoreChannel {
2015-10-01 10:56:07 -04:00
storeChannel := make ( StoreChannel )
go func ( ) {
result := StoreResult { }
2015-10-09 13:47:11 -04:00
// wrap in a transaction so that if one fails, everything fails
2015-10-15 15:39:50 -04:00
transaction , err := s . GetMaster ( ) . Begin ( )
2015-10-09 13:47:11 -04:00
if err != nil {
result . Err = model . NewAppError ( "SqlPreferenceStore.Save" , "Unable to open transaction to save preferences" , err . Error ( ) )
} else {
for _ , preference := range * preferences {
2015-10-13 11:52:17 -04:00
if upsertResult := s . save ( transaction , & preference ) ; upsertResult . Err != nil {
2015-10-09 13:47:11 -04:00
result = upsertResult
break
2015-10-07 10:19:02 -04:00
}
2015-10-09 13:47:11 -04:00
}
2015-10-07 10:19:02 -04:00
2015-10-09 13:47:11 -04:00
if result . Err == nil {
if err := transaction . Commit ( ) ; err != nil {
// don't need to rollback here since the transaction is already closed
result . Err = model . NewAppError ( "SqlPreferenceStore.Save" , "Unable to commit transaction to save preferences" , err . Error ( ) )
2015-10-07 10:19:02 -04:00
} else {
2015-10-09 13:47:11 -04:00
result . Data = len ( * preferences )
}
} else {
if err := transaction . Rollback ( ) ; err != nil {
result . Err = model . NewAppError ( "SqlPreferenceStore.Save" , "Unable to rollback transaction to save preferences" , err . Error ( ) )
2015-10-07 10:19:02 -04:00
}
}
2015-10-01 10:56:07 -04:00
}
storeChannel <- result
close ( storeChannel )
} ( )
return storeChannel
}
2015-10-09 13:47:11 -04:00
func ( s SqlPreferenceStore ) save ( transaction * gorp . Transaction , preference * model . Preference ) StoreResult {
2015-10-08 10:52:20 -04:00
result := StoreResult { }
2015-10-09 13:47:11 -04:00
if result . Err = preference . IsValid ( ) ; result . Err != nil {
return result
}
2015-10-08 10:52:20 -04:00
params := map [ string ] interface { } {
"UserId" : preference . UserId ,
"Category" : preference . Category ,
"Name" : preference . Name ,
"Value" : preference . Value ,
}
if utils . Cfg . SqlSettings . DriverName == model . DATABASE_DRIVER_MYSQL {
2015-10-09 13:47:11 -04:00
if _ , err := transaction . Exec (
2015-10-08 10:52:20 -04:00
` INSERT INTO
Preferences
2015-10-13 11:52:17 -04:00
( UserId , Category , Name , Value )
2015-10-08 10:52:20 -04:00
VALUES
2015-10-13 11:52:17 -04:00
( : UserId , : Category , : Name , : Value )
2015-10-08 10:52:20 -04:00
ON DUPLICATE KEY UPDATE
Value = : Value ` , params ) ; err != nil {
2015-10-09 13:47:11 -04:00
result . Err = model . NewAppError ( "SqlPreferenceStore.save" , "We encountered an error while updating preferences" , err . Error ( ) )
2015-10-08 10:52:20 -04:00
}
} else if utils . Cfg . SqlSettings . DriverName == model . DATABASE_DRIVER_POSTGRES {
2015-10-09 13:47:11 -04:00
// postgres has no way to upsert values until version 9.5 and trying inserting and then updating causes transactions to abort
count , err := transaction . SelectInt (
2015-10-08 10:52:20 -04:00
` SELECT
count ( 0 )
FROM
Preferences
WHERE
UserId = : UserId
AND Category = : Category
2015-10-13 11:52:17 -04:00
AND Name = : Name ` , params )
2015-10-08 10:52:20 -04:00
if err != nil {
2015-10-09 13:47:11 -04:00
result . Err = model . NewAppError ( "SqlPreferenceStore.save" , "We encountered an error while updating preferences" , err . Error ( ) )
2015-10-08 10:52:20 -04:00
return result
2015-10-07 10:19:02 -04:00
}
2015-10-08 10:52:20 -04:00
if count == 1 {
2015-10-09 13:47:11 -04:00
s . update ( transaction , preference )
2015-10-08 10:52:20 -04:00
} else {
2015-10-09 13:47:11 -04:00
s . insert ( transaction , preference )
2015-10-08 10:52:20 -04:00
}
} else {
2015-10-09 13:47:11 -04:00
result . Err = model . NewAppError ( "SqlPreferenceStore.save" , "We encountered an error while updating preferences" ,
2015-10-08 10:52:20 -04:00
"Failed to update preference because of missing driver" )
2015-10-07 10:19:02 -04:00
}
2015-10-08 10:52:20 -04:00
return result
2015-10-07 10:19:02 -04:00
}
2015-10-09 13:47:11 -04:00
func ( s SqlPreferenceStore ) insert ( transaction * gorp . Transaction , preference * model . Preference ) StoreResult {
result := StoreResult { }
if err := transaction . Insert ( preference ) ; err != nil {
if IsUniqueConstraintError ( err . Error ( ) , "UserId" , "preferences_pkey" ) {
2015-10-13 11:52:17 -04:00
result . Err = model . NewAppError ( "SqlPreferenceStore.insert" , "A preference with that user id, category, and name already exists" ,
"user_id=" + preference . UserId + ", category=" + preference . Category + ", name=" + preference . Name + ", " + err . Error ( ) )
2015-10-09 13:47:11 -04:00
} else {
result . Err = model . NewAppError ( "SqlPreferenceStore.insert" , "We couldn't save the preference" ,
2015-10-13 11:52:17 -04:00
"user_id=" + preference . UserId + ", category=" + preference . Category + ", name=" + preference . Name + ", " + err . Error ( ) )
2015-10-09 13:47:11 -04:00
}
}
return result
}
func ( s SqlPreferenceStore ) update ( transaction * gorp . Transaction , preference * model . Preference ) StoreResult {
result := StoreResult { }
if _ , err := transaction . Update ( preference ) ; err != nil {
result . Err = model . NewAppError ( "SqlPreferenceStore.update" , "We couldn't update the preference" ,
2015-10-13 11:52:17 -04:00
"user_id=" + preference . UserId + ", category=" + preference . Category + ", name=" + preference . Name + ", " + err . Error ( ) )
2015-10-09 13:47:11 -04:00
}
return result
}
2015-10-13 11:52:17 -04:00
func ( s SqlPreferenceStore ) Get ( userId string , category string , name string ) StoreChannel {
2015-10-01 10:56:07 -04:00
storeChannel := make ( StoreChannel )
go func ( ) {
result := StoreResult { }
2015-10-13 15:18:01 -04:00
var preference model . Preference
2015-10-01 10:56:07 -04:00
2015-10-13 15:18:01 -04:00
if err := s . GetReplica ( ) . SelectOne ( & preference ,
2015-10-01 10:56:07 -04:00
` SELECT
*
FROM
Preferences
WHERE
UserId = : UserId
AND Category = : Category
AND Name = : Name ` , map [ string ] interface { } { "UserId" : userId , "Category" : category , "Name" : name } ) ; err != nil {
2015-10-30 12:41:51 -05:00
result . Err = model . NewAppError ( "SqlPreferenceStore.Get" , "We encountered an error while finding preferences" , err . Error ( ) )
2015-10-13 11:52:17 -04:00
} else {
2015-10-13 15:18:01 -04:00
result . Data = preference
2015-10-13 11:52:17 -04:00
}
storeChannel <- result
close ( storeChannel )
} ( )
return storeChannel
}
func ( s SqlPreferenceStore ) GetCategory ( userId string , category string ) StoreChannel {
storeChannel := make ( StoreChannel )
go func ( ) {
result := StoreResult { }
var preferences model . Preferences
if _ , err := s . GetReplica ( ) . Select ( & preferences ,
` SELECT
*
FROM
Preferences
WHERE
UserId = : UserId
AND Category = : Category ` , map [ string ] interface { } { "UserId" : userId , "Category" : category } ) ; err != nil {
2015-10-30 12:41:51 -05:00
result . Err = model . NewAppError ( "SqlPreferenceStore.GetCategory" , "We encountered an error while finding preferences" , err . Error ( ) )
2015-10-01 10:56:07 -04:00
} else {
result . Data = preferences
}
storeChannel <- result
close ( storeChannel )
} ( )
return storeChannel
}
2015-10-15 15:09:40 -04:00
func ( s SqlPreferenceStore ) GetAll ( userId string ) StoreChannel {
storeChannel := make ( StoreChannel )
go func ( ) {
result := StoreResult { }
var preferences model . Preferences
if _ , err := s . GetReplica ( ) . Select ( & preferences ,
` SELECT
*
FROM
Preferences
WHERE
UserId = : UserId ` , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
2015-10-30 12:41:51 -05:00
result . Err = model . NewAppError ( "SqlPreferenceStore.GetAll" , "We encountered an error while finding preferences" , err . Error ( ) )
2015-10-15 15:09:40 -04:00
} else {
result . Data = preferences
}
storeChannel <- result
close ( storeChannel )
} ( )
return storeChannel
}
2015-11-15 18:18:02 -08:00
2015-11-16 17:12:49 -08:00
func ( s SqlPreferenceStore ) PermanentDeleteByUser ( userId string ) StoreChannel {
2015-11-15 18:18:02 -08:00
storeChannel := make ( StoreChannel )
go func ( ) {
result := StoreResult { }
if _ , err := s . GetMaster ( ) . Exec (
` DELETE FROM Preferences WHERE UserId = :UserId ` , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
result . Err = model . NewAppError ( "SqlPreferenceStore.Delete" , "We encountered an error while deleteing preferences" , err . Error ( ) )
}
storeChannel <- result
close ( storeChannel )
} ( )
return storeChannel
}
2015-11-13 22:56:41 +01:00
2015-11-27 23:16:56 +01:00
func ( s SqlPreferenceStore ) IsFeatureEnabled ( feature , userId string ) StoreChannel {
2015-11-13 22:56:41 +01:00
storeChannel := make ( StoreChannel )
go func ( ) {
result := StoreResult { }
if value , err := s . GetReplica ( ) . SelectStr ( ` SELECT
value
FROM
Preferences
WHERE
UserId = : UserId
AND Category = : Category
2015-11-27 02:20:06 +01:00
AND Name = : Name ` , map [ string ] interface { } { "UserId" : userId , "Category" : model . PREFERENCE_CATEGORY_ADVANCED_SETTINGS , "Name" : FEATURE_TOGGLE_PREFIX + feature } ) ; err != nil {
2015-11-27 23:16:56 +01:00
result . Err = model . NewAppError ( "SqlPreferenceStore.IsFeatureEnabled" , "We encountered an error while finding a pre release feature preference" , err . Error ( ) )
2015-11-13 22:56:41 +01:00
} else {
result . Data = value == "true"
}
storeChannel <- result
close ( storeChannel )
} ( )
return storeChannel
}