Added Preferences table to store user preferences

Этот коммит содержится в:
hmhealey
2015-10-01 10:56:07 -04:00
родитель 3229457de0
Коммит da66599fa3
5 изменённых файлов: 325 добавлений и 13 удалений

Просмотреть файл

@@ -10,7 +10,9 @@ import (
const ( const (
PREFERENCE_CATEGORY_DIRECT_CHANNELS = "direct_channels" PREFERENCE_CATEGORY_DIRECT_CHANNELS = "direct_channels"
PREFERENCE_CATEGORY_TEST = "test" // do not use, just for testing uniqueness while there's only one real category
PREFERENCE_NAME_SHOWHIDE = "show_hide" PREFERENCE_NAME_SHOWHIDE = "show_hide"
PREFERENCE_NAME_TEST = "test" // do not use, just for testing uniqueness while there's only one real name
) )
type Preference struct { type Preference struct {
@@ -66,9 +68,9 @@ func (o *Preference) IsValid() *AppError {
} }
func IsPreferenceCategoryValid(category string) bool { func IsPreferenceCategoryValid(category string) bool {
return category == PREFERENCE_CATEGORY_DIRECT_CHANNELS return category == PREFERENCE_CATEGORY_DIRECT_CHANNELS || category == PREFERENCE_CATEGORY_TEST
} }
func IsPreferenceNameValid(name string) bool { func IsPreferenceNameValid(name string) bool {
return name == PREFERENCE_NAME_SHOWHIDE return name == PREFERENCE_NAME_SHOWHIDE || name == PREFERENCE_NAME_TEST
} }

125
store/sql_preference_store.go Обычный файл
Просмотреть файл

@@ -0,0 +1,125 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"github.com/mattermost/platform/model"
)
type SqlPreferenceStore struct {
*SqlStore
}
func NewSqlPreferenceStore(sqlStore *SqlStore) PreferenceStore {
s := &SqlPreferenceStore{sqlStore}
for _, db := range sqlStore.GetAllConns() {
table := db.AddTableWithName(model.Preference{}, "Preferences").SetKeys(false, "UserId", "Category", "Name", "AltId")
table.ColMap("UserId").SetMaxSize(26)
table.ColMap("Category").SetMaxSize(32)
table.ColMap("Name").SetMaxSize(32)
table.ColMap("AltId").SetMaxSize(26)
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")
}
func (s SqlPreferenceStore) Save(preference *model.Preference) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
if result.Err = preference.IsValid(); result.Err != nil {
storeChannel <- result
close(storeChannel)
return
}
if err := s.GetMaster().Insert(preference); err != nil {
if IsUniqueConstraintError(err.Error(), "UserId", "preferences_pkey") {
result.Err = model.NewAppError("SqlPreferenceStore.Save", "A preference with that user id, category, name, and alt id already exists",
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error())
} else {
result.Err = model.NewAppError("SqlPreferenceStore.Save", "We couldn't save the preference",
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error())
}
} else {
result.Data = preference
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlPreferenceStore) Update(preference *model.Preference) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
if result.Err = preference.IsValid(); result.Err != nil {
storeChannel <- result
close(storeChannel)
return
}
if count, err := s.GetMaster().Update(preference); err != nil {
result.Err = model.NewAppError("SqlPreferenceStore.Update", "We couldn't update the preference",
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error())
} else if count != 1 {
result.Err = model.NewAppError("SqlPreferenceStore.Update", "We couldn't update the preference",
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId)
} else {
result.Data = preference
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlPreferenceStore) GetByName(userId string, category string, name string) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
var preferences []*model.Preference
if _, err := s.GetReplica().Select(&preferences,
`SELECT
*
FROM
Preferences
WHERE
UserId = :UserId
AND Category = :Category
AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil {
result.Err = model.NewAppError("SqlPreferenceStore.GetByName", "We encounted an error while finding preferences", err.Error())
} else {
result.Data = preferences
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}

170
store/sql_preference_store_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,170 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"github.com/mattermost/platform/model"
"testing"
)
func TestPreferenceStoreSave(t *testing.T) {
Setup()
p1 := model.Preference{
UserId: model.NewId(),
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNELS,
Name: model.PREFERENCE_NAME_SHOWHIDE,
AltId: model.NewId(),
}
if err := (<-store.Preference().Save(&p1)).Err; err != nil {
t.Fatal("couldn't save preference", err)
}
if err := (<-store.Preference().Save(&p1)).Err; err == nil {
t.Fatal("shouldn't be able to save duplicate preference")
}
p2 := model.Preference{
UserId: model.NewId(),
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNELS,
Name: model.PREFERENCE_NAME_SHOWHIDE,
AltId: p1.AltId,
}
if err := (<-store.Preference().Save(&p2)).Err; err != nil {
t.Fatal("couldn't save preference with duplicate category, name, alternate id", err)
}
p3 := model.Preference{
UserId: p1.UserId,
Category: model.PREFERENCE_CATEGORY_TEST,
Name: model.PREFERENCE_NAME_SHOWHIDE,
AltId: p1.AltId,
}
if err := (<-store.Preference().Save(&p3)).Err; err != nil {
t.Fatal("couldn't save preference with duplicate user id, name, alternate id", err)
}
p4 := model.Preference{
UserId: p1.UserId,
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNELS,
Name: model.PREFERENCE_NAME_TEST,
AltId: p1.AltId,
}
if err := (<-store.Preference().Save(&p4)).Err; err != nil {
t.Fatal("couldn't save preference with duplicate user id, category, alternate id", err)
}
p5 := model.Preference{
UserId: p1.UserId,
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNELS,
Name: model.PREFERENCE_NAME_SHOWHIDE,
AltId: model.NewId(),
}
if err := (<-store.Preference().Save(&p5)).Err; err != nil {
t.Fatal("couldn't save preference with duplicate user id, category, name", err)
}
}
func TestPreferenceStoreUpdate(t *testing.T) {
Setup()
id := model.NewId()
p1 := model.Preference{
UserId: id,
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNELS,
Name: model.PREFERENCE_NAME_SHOWHIDE,
}
Must(store.Preference().Save(&p1))
p1.Value = "1234garbage"
if err := (<-store.Preference().Update(&p1)).Err; err != nil {
t.Fatal(err)
}
p1.UserId = model.NewId()
if err := (<-store.Preference().Update(&p1)).Err; err == nil {
t.Fatal("update should have failed because of changed user id")
}
p1.UserId = id
p1.Category = model.PREFERENCE_CATEGORY_TEST
if err := (<-store.Preference().Update(&p1)).Err; err == nil {
t.Fatal("update should have failed because of changed category")
}
p1.Category = model.PREFERENCE_CATEGORY_DIRECT_CHANNELS
p1.Name = model.PREFERENCE_NAME_TEST
if err := (<-store.Preference().Update(&p1)).Err; err == nil {
t.Fatal("update should have failed because of changed name")
}
p1.Name = model.PREFERENCE_NAME_SHOWHIDE
p1.AltId = model.NewId()
if err := (<-store.Preference().Update(&p1)).Err; err == nil {
t.Fatal("update should have failed because of changed alternate id")
}
}
func TestPreferenceGetByName(t *testing.T) {
Setup()
p1 := model.Preference{
UserId: model.NewId(),
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNELS,
Name: model.PREFERENCE_NAME_SHOWHIDE,
AltId: model.NewId(),
}
// same user/category/name, different alt id
p2 := model.Preference{
UserId: p1.UserId,
Category: p1.Category,
Name: p1.Name,
AltId: model.NewId(),
}
// same user/category/alt id, different name
p3 := model.Preference{
UserId: p1.UserId,
Category: p1.Category,
Name: model.PREFERENCE_NAME_TEST,
AltId: p1.AltId,
}
// same user/name/alt id, different category
p4 := model.Preference{
UserId: p1.UserId,
Category: model.PREFERENCE_CATEGORY_TEST,
Name: p1.Name,
AltId: p1.AltId,
}
// same name/category/alt id, different user
p5 := model.Preference{
UserId: model.NewId(),
Category: p1.Category,
Name: p1.Name,
AltId: p1.AltId,
}
Must(store.Preference().Save(&p1))
Must(store.Preference().Save(&p2))
Must(store.Preference().Save(&p3))
Must(store.Preference().Save(&p4))
Must(store.Preference().Save(&p5))
if result := <-store.Preference().GetByName(p1.UserId, p1.Category, p1.Name); result.Err != nil {
t.Fatal(result.Err)
} else if data := result.Data.([]*model.Preference); len(data) != 2 {
t.Fatal("got the wrong number of preferences")
} else if !((*data[0] == p1 && *data[1] == p2) || (*data[0] == p2 && *data[1] == p1)) {
t.Fatal("got incorrect preferences")
}
}

Просмотреть файл

@@ -30,17 +30,18 @@ import (
) )
type SqlStore struct { type SqlStore struct {
master *gorp.DbMap master *gorp.DbMap
replicas []*gorp.DbMap replicas []*gorp.DbMap
team TeamStore team TeamStore
channel ChannelStore channel ChannelStore
post PostStore post PostStore
user UserStore user UserStore
audit AuditStore audit AuditStore
session SessionStore session SessionStore
oauth OAuthStore oauth OAuthStore
system SystemStore system SystemStore
webhook WebhookStore webhook WebhookStore
preference PreferenceStore
} }
func NewSqlStore() Store { func NewSqlStore() Store {
@@ -93,6 +94,7 @@ func NewSqlStore() Store {
sqlStore.oauth = NewSqlOAuthStore(sqlStore) sqlStore.oauth = NewSqlOAuthStore(sqlStore)
sqlStore.system = NewSqlSystemStore(sqlStore) sqlStore.system = NewSqlSystemStore(sqlStore)
sqlStore.webhook = NewSqlWebhookStore(sqlStore) sqlStore.webhook = NewSqlWebhookStore(sqlStore)
sqlStore.preference = NewSqlPreferenceStore(sqlStore)
sqlStore.master.CreateTablesIfNotExists() sqlStore.master.CreateTablesIfNotExists()
@@ -105,6 +107,7 @@ func NewSqlStore() Store {
sqlStore.oauth.(*SqlOAuthStore).UpgradeSchemaIfNeeded() sqlStore.oauth.(*SqlOAuthStore).UpgradeSchemaIfNeeded()
sqlStore.system.(*SqlSystemStore).UpgradeSchemaIfNeeded() sqlStore.system.(*SqlSystemStore).UpgradeSchemaIfNeeded()
sqlStore.webhook.(*SqlWebhookStore).UpgradeSchemaIfNeeded() sqlStore.webhook.(*SqlWebhookStore).UpgradeSchemaIfNeeded()
sqlStore.preference.(*SqlPreferenceStore).UpgradeSchemaIfNeeded()
sqlStore.team.(*SqlTeamStore).CreateIndexesIfNotExists() sqlStore.team.(*SqlTeamStore).CreateIndexesIfNotExists()
sqlStore.channel.(*SqlChannelStore).CreateIndexesIfNotExists() sqlStore.channel.(*SqlChannelStore).CreateIndexesIfNotExists()
@@ -115,6 +118,7 @@ func NewSqlStore() Store {
sqlStore.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists() sqlStore.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists()
sqlStore.system.(*SqlSystemStore).CreateIndexesIfNotExists() sqlStore.system.(*SqlSystemStore).CreateIndexesIfNotExists()
sqlStore.webhook.(*SqlWebhookStore).CreateIndexesIfNotExists() sqlStore.webhook.(*SqlWebhookStore).CreateIndexesIfNotExists()
sqlStore.preference.(*SqlPreferenceStore).CreateIndexesIfNotExists()
if model.IsPreviousVersion(schemaVersion) { if model.IsPreviousVersion(schemaVersion) {
sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion}) sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion})
@@ -472,6 +476,10 @@ func (ss SqlStore) Webhook() WebhookStore {
return ss.webhook return ss.webhook
} }
func (ss SqlStore) Preference() PreferenceStore {
return ss.preference
}
type mattermConverter struct{} type mattermConverter struct{}
func (me mattermConverter) ToDb(val interface{}) (interface{}, error) { func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {

Просмотреть файл

@@ -37,6 +37,7 @@ type Store interface {
OAuth() OAuthStore OAuth() OAuthStore
System() SystemStore System() SystemStore
Webhook() WebhookStore Webhook() WebhookStore
Preference() PreferenceStore
Close() Close()
} }
@@ -149,3 +150,9 @@ type WebhookStore interface {
GetIncomingByUser(userId string) StoreChannel GetIncomingByUser(userId string) StoreChannel
DeleteIncoming(webhookId string, time int64) StoreChannel DeleteIncoming(webhookId string, time int64) StoreChannel
} }
type PreferenceStore interface {
Save(preference *model.Preference) StoreChannel
Update(preference *model.Preference) StoreChannel
GetByName(userId string, category string, name string) StoreChannel
}