Files
mattermost/store/sql_upgrade.go
Harrison Healey 8a0e649f98 PLT-3105 Files table migration (#4068)
* Implemented initial changes for files table

* Removed *_benchmark_test.go files

* Re-implemented GetPublicFile and added support for old path

* Localization for files table

* Moved file system code into utils package

* Finished server-side changes and added initial upgrade script

* Added getPostFiles api

* Re-add Extension and HasPreviewImage fields to FileInfo

* Removed unused translation

* Fixed merge conflicts left over after permissions changes

* Forced FileInfo.extension to be lower case

* Changed FileUploadResponse to contain the FileInfos instead of FileIds

* Fixed permissions on getFile* calls

* Fixed notifications for file uploads

* Added initial version of client code for files changes

* Permanently added FileIds field to Post object and removed Post.HasFiles

* Updated PostStore.Update to be usable in more circumstances

* Re-added Filenames field and switched file migration to be entirely lazy-loaded

* Increased max listener count for FileStore

* Removed unused fileInfoCache

* Moved file system code back into api

* Removed duplicate test case

* Fixed unit test running on ports other than 8065

* Renamed HasPermissionToPostContext to HasPermissionToChannelByPostContext

* Refactored handleImages to make it more easily understandable

* Renamed getPostFiles to getFileInfosForPost

* Re-added pre-FileIds posts to analytics

* Changed files to be saved as their ids as opposed to id/filename.ext

* Renamed FileInfo.UserId to FileInfo.CreatorId

* Fixed detection of language in CodePreview

* Fixed switching between threads in the RHS not loading new files

* Add serverside protection against a rare bug where the client sends the same file twice for a single post

* Refactored the important parts of uploadFile api call into a function that can be called without a web context
2016-09-30 11:06:30 -04:00

212 lines
7.2 KiB
Go

// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"os"
"strings"
"time"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
const (
VERSION_3_5_0 = "3.5.0"
VERSION_3_4_0 = "3.4.0"
VERSION_3_3_0 = "3.3.0"
VERSION_3_2_0 = "3.2.0"
VERSION_3_1_0 = "3.1.0"
VERSION_3_0_0 = "3.0.0"
)
const (
EXIT_VERSION_SAVE_MISSING = 1001
EXIT_TOO_OLD = 1002
EXIT_VERSION_SAVE = 1003
EXIT_THEME_MIGRATION = 1004
)
func UpgradeDatabase(sqlStore *SqlStore) {
UpgradeDatabaseToVersion31(sqlStore)
UpgradeDatabaseToVersion32(sqlStore)
UpgradeDatabaseToVersion33(sqlStore)
UpgradeDatabaseToVersion34(sqlStore)
UpgradeDatabaseToVersion35(sqlStore)
// If the SchemaVersion is empty this this is the first time it has ran
// so lets set it to the current version.
if sqlStore.SchemaVersion == "" {
if result := <-sqlStore.system.Save(&model.System{Name: "Version", Value: model.CurrentVersion}); result.Err != nil {
l4g.Critical(result.Err.Error())
time.Sleep(time.Second)
os.Exit(EXIT_VERSION_SAVE_MISSING)
}
sqlStore.SchemaVersion = model.CurrentVersion
l4g.Info(utils.T("store.sql.schema_set.info"), model.CurrentVersion)
}
// If we're not on the current version then it's too old to be upgraded
if sqlStore.SchemaVersion != model.CurrentVersion {
l4g.Critical(utils.T("store.sql.schema_version.critical"), sqlStore.SchemaVersion)
time.Sleep(time.Second)
os.Exit(EXIT_TOO_OLD)
}
}
func saveSchemaVersion(sqlStore *SqlStore, version string) {
if result := <-sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion}); result.Err != nil {
l4g.Critical(result.Err.Error())
time.Sleep(time.Second)
os.Exit(EXIT_VERSION_SAVE)
}
sqlStore.SchemaVersion = version
l4g.Warn(utils.T("store.sql.upgraded.warn"), version)
}
func shouldPerformUpgrade(sqlStore *SqlStore, currentSchemaVersion string, expectedSchemaVersion string) bool {
if sqlStore.SchemaVersion == currentSchemaVersion {
l4g.Warn(utils.T("store.sql.schema_out_of_date.warn"), currentSchemaVersion)
l4g.Warn(utils.T("store.sql.schema_upgrade_attempt.warn"), expectedSchemaVersion)
return true
}
return false
}
func UpgradeDatabaseToVersion31(sqlStore *SqlStore) {
if shouldPerformUpgrade(sqlStore, VERSION_3_0_0, VERSION_3_1_0) {
sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
saveSchemaVersion(sqlStore, VERSION_3_1_0)
}
}
func UpgradeDatabaseToVersion32(sqlStore *SqlStore) {
if shouldPerformUpgrade(sqlStore, VERSION_3_1_0, VERSION_3_2_0) {
sqlStore.CreateColumnIfNotExists("TeamMembers", "DeleteAt", "bigint(20)", "bigint", "0")
saveSchemaVersion(sqlStore, VERSION_3_2_0)
}
}
func themeMigrationFailed(err error) {
l4g.Critical(utils.T("store.sql_user.migrate_theme.critical"), err)
time.Sleep(time.Second)
os.Exit(EXIT_THEME_MIGRATION)
}
func UpgradeDatabaseToVersion33(sqlStore *SqlStore) {
if shouldPerformUpgrade(sqlStore, VERSION_3_2_0, VERSION_3_3_0) {
if sqlStore.DoesColumnExist("Users", "ThemeProps") {
params := map[string]interface{}{
"Category": model.PREFERENCE_CATEGORY_THEME,
"Name": "",
}
transaction, err := sqlStore.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)
}
}
// 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 := sqlStore.GetMaster().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)
}
sqlStore.Preference().Save(&data)
}
}
sqlStore.CreateColumnIfNotExists("OAuthApps", "IsTrusted", "tinyint(1)", "boolean", "0")
sqlStore.CreateColumnIfNotExists("OAuthApps", "IconURL", "varchar(512)", "varchar(512)", "")
sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ClientId", "varchar(26)", "varchar(26)", "")
sqlStore.CreateColumnIfNotExists("OAuthAccessData", "UserId", "varchar(26)", "varchar(26)", "")
sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ExpiresAt", "bigint", "bigint", "0")
if sqlStore.DoesColumnExist("OAuthAccessData", "AuthCode") {
sqlStore.RemoveIndexIfExists("idx_oauthaccessdata_auth_code", "OAuthAccessData")
sqlStore.RemoveColumnIfExists("OAuthAccessData", "AuthCode")
}
sqlStore.RemoveColumnIfExists("Users", "LastActivityAt")
sqlStore.RemoveColumnIfExists("Users", "LastPingAt")
sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "TriggerWhen", "tinyint", "integer", "0")
saveSchemaVersion(sqlStore, VERSION_3_3_0)
}
}
func UpgradeDatabaseToVersion34(sqlStore *SqlStore) {
if shouldPerformUpgrade(sqlStore, VERSION_3_3_0, VERSION_3_4_0) {
sqlStore.CreateColumnIfNotExists("Status", "Manual", "BOOLEAN", "BOOLEAN", "0")
sqlStore.CreateColumnIfNotExists("Status", "ActiveChannel", "varchar(26)", "varchar(26)", "")
saveSchemaVersion(sqlStore, VERSION_3_4_0)
}
}
func UpgradeDatabaseToVersion35(sqlStore *SqlStore) {
//if shouldPerformUpgrade(sqlStore, VERSION_3_4_0, VERSION_3_5_0) {
sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user' WHERE Roles = ''")
sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user system_admin' WHERE Roles = 'system_admin'")
sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user' WHERE Roles = ''")
sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user team_admin' WHERE Roles = 'admin'")
sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user' WHERE Roles = ''")
sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user channel_admin' WHERE Roles = 'admin'")
// The rest of the migration from Filenames -> FileIds is done lazily in api.GetFileInfosForPost
sqlStore.CreateColumnIfNotExists("Posts", "FileIds", "varchar(150)", "varchar(150)", "[]")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// UNCOMMENT WHEN WE DO RELEASE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//sqlStore.Session().RemoveAllSessions()
//saveSchemaVersion(sqlStore, VERSION_3_5_0)
//}
}