diff options
Diffstat (limited to 'store')
-rw-r--r-- | store/sql_channel_store.go | 74 | ||||
-rw-r--r-- | store/sql_post_store.go | 24 | ||||
-rw-r--r-- | store/sql_preference_store.go | 27 | ||||
-rw-r--r-- | store/sql_preference_store_test.go | 27 | ||||
-rw-r--r-- | store/sql_team_store.go | 2 | ||||
-rw-r--r-- | store/sql_user_store.go | 116 | ||||
-rw-r--r-- | store/store.go | 5 |
7 files changed, 174 insertions, 101 deletions
diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index e5e0aa8ba..463bc0678 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -856,6 +856,58 @@ func (s SqlChannelStore) CheckOpenChannelPermissions(teamId string, channelId st return storeChannel } +func (s SqlChannelStore) SetLastViewedAt(channelId string, userId string, newLastViewedAt int64) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var query string + + if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { + query = `UPDATE + ChannelMembers + SET + MentionCount = 0, + MsgCount = Channels.TotalMsgCount - (SELECT COUNT(*) + FROM Posts + WHERE ChannelId = :ChannelId + AND CreateAt > :NewLastViewedAt), + LastViewedAt = :NewLastViewedAt + FROM + Channels + WHERE + Channels.Id = ChannelMembers.ChannelId + AND UserId = :UserId + AND ChannelId = :ChannelId` + } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { + query = `UPDATE + ChannelMembers, Channels + SET + ChannelMembers.MentionCount = 0, + ChannelMembers.MsgCount = Channels.TotalMsgCount - (SELECT COUNT(*) + FROM Posts + WHERE ChannelId = :ChannelId + AND CreateAt > :NewLastViewedAt), + ChannelMembers.LastViewedAt = :NewLastViewedAt + WHERE + Channels.Id = ChannelMembers.ChannelId + AND UserId = :UserId + AND ChannelId = :ChannelId` + } + + _, err := s.GetMaster().Exec(query, map[string]interface{}{"ChannelId": channelId, "UserId": userId, "NewLastViewedAt": newLastViewedAt}) + if err != nil { + result.Err = model.NewLocAppError("SqlChannelStore.SetLastViewedAt", "store.sql_channel.set_last_viewed_at.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlChannelStore) UpdateLastViewedAt(channelId string, userId string) StoreChannel { storeChannel := make(StoreChannel) @@ -930,28 +982,6 @@ func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string) return storeChannel } -func (s SqlChannelStore) GetForExport(teamId string) StoreChannel { - storeChannel := make(StoreChannel) - - go func() { - result := StoreResult{} - - var data []*model.Channel - _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND DeleteAt = 0 AND Type = 'O'", map[string]interface{}{"TeamId": teamId}) - - if err != nil { - result.Err = model.NewLocAppError("SqlChannelStore.GetAllChannels", "store.sql_channel.get_for_export.app_error", nil, "teamId="+teamId+", err="+err.Error()) - } else { - result.Data = data - } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel -} - func (s SqlChannelStore) GetAll(teamId string) StoreChannel { storeChannel := make(StoreChannel) diff --git a/store/sql_post_store.go b/store/sql_post_store.go index e6291687e..57bb2a512 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -784,30 +784,6 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP return storeChannel } -func (s SqlPostStore) GetForExport(channelId string) StoreChannel { - storeChannel := make(StoreChannel) - - go func() { - result := StoreResult{} - - var posts []*model.Post - _, err := s.GetReplica().Select( - &posts, - "SELECT * FROM Posts WHERE ChannelId = :ChannelId AND DeleteAt = 0", - map[string]interface{}{"ChannelId": channelId}) - if err != nil { - result.Err = model.NewLocAppError("SqlPostStore.GetForExport", "store.sql_post.get_for_export.app_error", nil, "channelId="+channelId+err.Error()) - } else { - result.Data = posts - } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel -} - func (s SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) StoreChannel { storeChannel := make(StoreChannel) diff --git a/store/sql_preference_store.go b/store/sql_preference_store.go index 83bf92ead..a701c3cb8 100644 --- a/store/sql_preference_store.go +++ b/store/sql_preference_store.go @@ -26,7 +26,7 @@ func NewSqlPreferenceStore(sqlStore *SqlStore) PreferenceStore { table.ColMap("UserId").SetMaxSize(26) table.ColMap("Category").SetMaxSize(32) table.ColMap("Name").SetMaxSize(32) - table.ColMap("Value").SetMaxSize(128) + table.ColMap("Value").SetMaxSize(2000) } return s @@ -100,6 +100,8 @@ func (s SqlPreferenceStore) Save(preferences *model.Preferences) StoreChannel { func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *model.Preference) StoreResult { result := StoreResult{} + preference.PreUpdate() + if result.Err = preference.IsValid(); result.Err != nil { return result } @@ -304,3 +306,26 @@ func (s SqlPreferenceStore) IsFeatureEnabled(feature, userId string) StoreChanne return storeChannel } + +func (s SqlPreferenceStore) Delete(userId, category, name string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + if _, err := s.GetMaster().Exec( + `DELETE 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.NewLocAppError("SqlPreferenceStore.Delete", "store.sql_preference.delete.app_error", nil, err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_preference_store_test.go b/store/sql_preference_store_test.go index ec9d1df6c..8c6a2b6af 100644 --- a/store/sql_preference_store_test.go +++ b/store/sql_preference_store_test.go @@ -193,7 +193,7 @@ func TestPreferenceGetAll(t *testing.T) { } } -func TestPreferenceDelete(t *testing.T) { +func TestPreferenceDeleteByUser(t *testing.T) { Setup() userId := model.NewId() @@ -367,3 +367,28 @@ func TestDeleteUnusedFeatures(t *testing.T) { t.Fatalf("Found %d features with value 'true', expected to find at least %d features", val, 2) } } + +func TestPreferenceDelete(t *testing.T) { + Setup() + + preference := model.Preference{ + UserId: model.NewId(), + Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW, + Name: model.NewId(), + Value: "value1a", + } + + Must(store.Preference().Save(&model.Preferences{preference})) + + if prefs := Must(store.Preference().GetAll(preference.UserId)).(model.Preferences); len([]model.Preference(prefs)) != 1 { + t.Fatal("should've returned 1 preference") + } + + if result := <-store.Preference().Delete(preference.UserId, preference.Category, preference.Name); result.Err != nil { + t.Fatal(result.Err) + } + + if prefs := Must(store.Preference().GetAll(preference.UserId)).(model.Preferences); len([]model.Preference(prefs)) != 0 { + t.Fatal("should've returned no preferences") + } +} diff --git a/store/sql_team_store.go b/store/sql_team_store.go index ddcaa7896..002d2a3ea 100644 --- a/store/sql_team_store.go +++ b/store/sql_team_store.go @@ -265,7 +265,7 @@ func (s SqlTeamStore) GetTeamsByUserId(userId string) StoreChannel { result := StoreResult{} var data []*model.Team - if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, TeamMembers WHERE TeamMembers.TeamId = Teams.Id AND TeamMembers.UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { + if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, TeamMembers WHERE TeamMembers.TeamId = Teams.Id AND TeamMembers.UserId = :UserId AND TeamMembers.DeleteAt = 0 AND Teams.DeleteAt = 0", map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewLocAppError("SqlTeamStore.GetTeamsByUserId", "store.sql_team.get_all.app_error", nil, err.Error()) } diff --git a/store/sql_user_store.go b/store/sql_user_store.go index df132ab42..325008670 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -4,11 +4,14 @@ package store import ( + "crypto/md5" "database/sql" "fmt" "strconv" "strings" + "time" + l4g "github.com/alecthomas/log4go" "github.com/mattermost/platform/model" "github.com/mattermost/platform/utils" ) @@ -39,7 +42,6 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore { table.ColMap("Roles").SetMaxSize(64) table.ColMap("Props").SetMaxSize(4000) table.ColMap("NotifyProps").SetMaxSize(2000) - table.ColMap("ThemeProps").SetMaxSize(2000) table.ColMap("Locale").SetMaxSize(5) table.ColMap("MfaSecret").SetMaxSize(128) } @@ -52,27 +54,68 @@ func (us SqlUserStore) UpgradeSchemaIfNeeded() { us.CreateColumnIfNotExists("Users", "Locale", "varchar(5)", "character varying(5)", model.DEFAULT_LOCALE) // ADDED for 3.2 REMOVE for 3.6 - var data []*model.User - if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE ThemeProps LIKE '%solarized%'"); err == nil { - for _, user := range data { - shouldUpdate := false - if user.ThemeProps["codeTheme"] == "solarized_dark" { - user.ThemeProps["codeTheme"] = "solarized-dark" - shouldUpdate = true - } else if user.ThemeProps["codeTheme"] == "solarized_light" { - user.ThemeProps["codeTheme"] = "solarized-light" - shouldUpdate = true + if us.DoesColumnExist("Users", "ThemeProps") { + params := map[string]interface{}{ + "Category": model.PREFERENCE_CATEGORY_THEME, + "Name": "", + } + + transaction, err := us.GetMaster().Begin() + if err != nil { + themeMigrationFailed(err) + } + + // increase size of Value column of Preferences table to match the size of the ThemeProps column + if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { + if _, err := transaction.Exec("ALTER TABLE Preferences ALTER COLUMN Value TYPE varchar(2000)"); err != nil { + themeMigrationFailed(err) + } + } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { + if _, err := transaction.Exec("ALTER TABLE Preferences MODIFY Value text"); err != nil { + themeMigrationFailed(err) } + } - if shouldUpdate { - if result := <-us.Update(user, true); result.Err != nil { - return - } + // copy data across + if _, err := transaction.Exec( + `INSERT INTO + Preferences(UserId, Category, Name, Value) + SELECT + Id, '`+model.PREFERENCE_CATEGORY_THEME+`', '', ThemeProps + FROM + Users + WHERE + Users.ThemeProps != 'null'`, params); err != nil { + themeMigrationFailed(err) + } + + // delete old data + if _, err := transaction.Exec("ALTER TABLE Users DROP COLUMN ThemeProps"); err != nil { + themeMigrationFailed(err) + } + + if err := transaction.Commit(); err != nil { + themeMigrationFailed(err) + } + + // rename solarized_* code themes to solarized-* to match client changes in 3.0 + var data model.Preferences + if _, err := us.GetReplica().Select(&data, "SELECT * FROM Preferences WHERE Category = '"+model.PREFERENCE_CATEGORY_THEME+"' AND Value LIKE '%solarized_%'"); err == nil { + for i := range data { + data[i].Value = strings.Replace(data[i].Value, "solarized_", "solarized-", -1) } + + us.Preference().Save(&data) } } } +func themeMigrationFailed(err error) { + l4g.Critical(utils.T("store.sql_user.migrate_theme.critical"), err) + time.Sleep(time.Second) + panic(fmt.Sprintf(utils.T("store.sql_user.migrate_theme.critical"), err.Error())) +} + func (us SqlUserStore) CreateIndexesIfNotExists() { us.CreateIndexIfNotExists("idx_users_email", "Users", "Email") } @@ -480,9 +523,10 @@ func (s SqlUserStore) GetEtagForDirectProfiles(userId string) StoreChannel { go func() { result := StoreResult{} - updateAt, err := s.GetReplica().SelectInt(` + var ids []string + _, err := s.GetReplica().Select(ids, ` SELECT - UpdateAt + Id FROM Users WHERE @@ -508,12 +552,14 @@ func (s SqlUserStore) GetEtagForDirectProfiles(userId string) StoreChannel { WHERE UserId = :UserId AND Category = 'direct_channel_show') - ORDER BY UpdateAt DESC LIMIT 1 + ORDER BY UpdateAt DESC `, map[string]interface{}{"UserId": userId}) - if err != nil { - result.Data = fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.GetMillis(), utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) + + if err != nil || len(ids) == 0 { + result.Data = fmt.Sprintf("%v.%v.0.%v.%v", model.CurrentVersion, model.GetMillis(), utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } else { - result.Data = fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, updateAt, utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) + allIds := strings.Join(ids, "") + result.Data = fmt.Sprintf("%v.%v.%v.%v.%v", model.CurrentVersion, md5.Sum([]byte(allIds)), len(ids), utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } storeChannel <- result @@ -923,34 +969,6 @@ func (us SqlUserStore) VerifyEmail(userId string) StoreChannel { return storeChannel } -func (us SqlUserStore) GetForExport(teamId string) StoreChannel { - - storeChannel := make(StoreChannel) - - go func() { - result := StoreResult{} - - var users []*model.User - - if _, err := us.GetReplica().Select(&users, "SELECT Users.* FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId", map[string]interface{}{"TeamId": teamId}); err != nil { - result.Err = model.NewLocAppError("SqlUserStore.GetForExport", "store.sql_user.get_for_export.app_error", nil, err.Error()) - } else { - for _, u := range users { - u.Password = "" - u.AuthData = new(string) - *u.AuthData = "" - } - - result.Data = users - } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel -} - func (us SqlUserStore) GetTotalUsersCount() StoreChannel { storeChannel := make(StoreChannel) diff --git a/store/store.go b/store/store.go index f576cc2ab..4b5c0e8cd 100644 --- a/store/store.go +++ b/store/store.go @@ -83,7 +83,6 @@ type ChannelStore interface { GetChannels(teamId string, userId string) StoreChannel GetMoreChannels(teamId string, userId string) StoreChannel GetChannelCounts(teamId string, userId string) StoreChannel - GetForExport(teamId string) StoreChannel GetAll(teamId string) StoreChannel SaveMember(member *model.ChannelMember) StoreChannel @@ -99,6 +98,7 @@ type ChannelStore interface { CheckOpenChannelPermissions(teamId string, channelId string) StoreChannel CheckPermissionsToByName(teamId string, channelName string, userId string) StoreChannel UpdateLastViewedAt(channelId string, userId string) StoreChannel + SetLastViewedAt(channelId string, userId string, newLastViewedAt int64) StoreChannel IncrementMentionCount(channelId string, userId string) StoreChannel AnalyticsTypeCount(teamId string, channelType string) StoreChannel ExtraUpdateByUser(userId string, time int64) StoreChannel @@ -116,7 +116,6 @@ type PostStore interface { GetPostsSince(channelId string, time int64) StoreChannel GetEtag(channelId string) StoreChannel Search(teamId string, userId string, params *model.SearchParams) StoreChannel - GetForExport(channelId string) StoreChannel AnalyticsUserCountsWithPostsByDay(teamId string) StoreChannel AnalyticsPostCountsByDay(teamId string) StoreChannel AnalyticsPostCount(teamId string, mustHaveFile bool, mustHaveHashtag bool) StoreChannel @@ -150,7 +149,6 @@ type UserStore interface { GetEtagForProfiles(teamId string) StoreChannel GetEtagForDirectProfiles(userId string) StoreChannel UpdateFailedPasswordAttempts(userId string, attempts int) StoreChannel - GetForExport(teamId string) StoreChannel GetTotalUsersCount() StoreChannel GetTotalActiveUsersCount() StoreChannel GetSystemAdminProfiles() StoreChannel @@ -242,6 +240,7 @@ type PreferenceStore interface { Get(userId string, category string, name string) StoreChannel GetCategory(userId string, category string) StoreChannel GetAll(userId string) StoreChannel + Delete(userId, category, name string) StoreChannel PermanentDeleteByUser(userId string) StoreChannel IsFeatureEnabled(feature, userId string) StoreChannel } |