github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/sqlstore/upgrade.go (about)

     1  // Copyright (c) 2016-present Xenia, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"database/sql"
     8  	"encoding/json"
     9  	"fmt"
    10  	"os"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/blang/semver"
    15  	"github.com/pkg/errors"
    16  
    17  	"github.com/xzl8028/xenia-server/mlog"
    18  	"github.com/xzl8028/xenia-server/model"
    19  	"github.com/xzl8028/xenia-server/services/timezones"
    20  )
    21  
    22  const (
    23  	VERSION_5_14_0           = "5.14.0"
    24  	VERSION_5_13_0           = "5.13.0"
    25  	VERSION_5_12_0           = "5.12.0"
    26  	VERSION_5_11_0           = "5.11.0"
    27  	VERSION_5_10_0           = "5.10.0"
    28  	VERSION_5_9_0            = "5.9.0"
    29  	VERSION_5_8_0            = "5.8.0"
    30  	VERSION_5_7_0            = "5.7.0"
    31  	VERSION_5_6_0            = "5.6.0"
    32  	VERSION_5_5_0            = "5.5.0"
    33  	VERSION_5_4_0            = "5.4.0"
    34  	VERSION_5_3_0            = "5.3.0"
    35  	VERSION_5_2_0            = "5.2.0"
    36  	VERSION_5_1_0            = "5.1.0"
    37  	VERSION_5_0_0            = "5.0.0"
    38  	VERSION_4_10_0           = "4.10.0"
    39  	VERSION_4_9_0            = "4.9.0"
    40  	VERSION_4_8_1            = "4.8.1"
    41  	VERSION_4_8_0            = "4.8.0"
    42  	VERSION_4_7_2            = "4.7.2"
    43  	VERSION_4_7_1            = "4.7.1"
    44  	VERSION_4_7_0            = "4.7.0"
    45  	VERSION_4_6_0            = "4.6.0"
    46  	VERSION_4_5_0            = "4.5.0"
    47  	VERSION_4_4_0            = "4.4.0"
    48  	VERSION_4_3_0            = "4.3.0"
    49  	VERSION_4_2_0            = "4.2.0"
    50  	VERSION_4_1_0            = "4.1.0"
    51  	VERSION_4_0_0            = "4.0.0"
    52  	VERSION_3_10_0           = "3.10.0"
    53  	VERSION_3_9_0            = "3.9.0"
    54  	VERSION_3_8_0            = "3.8.0"
    55  	VERSION_3_7_0            = "3.7.0"
    56  	VERSION_3_6_0            = "3.6.0"
    57  	VERSION_3_5_0            = "3.5.0"
    58  	VERSION_3_4_0            = "3.4.0"
    59  	VERSION_3_3_0            = "3.3.0"
    60  	VERSION_3_2_0            = "3.2.0"
    61  	VERSION_3_1_0            = "3.1.0"
    62  	VERSION_3_0_0            = "3.0.0"
    63  	OLDEST_SUPPORTED_VERSION = VERSION_3_0_0
    64  )
    65  
    66  const (
    67  	EXIT_VERSION_SAVE                   = 1003
    68  	EXIT_THEME_MIGRATION                = 1004
    69  	EXIT_TEAM_INVITEID_MIGRATION_FAILED = 1006
    70  )
    71  
    72  // UpgradeDatabase attempts to migrate the schema to the latest supported version.
    73  // The value of model.CurrentVersion is accepted as a parameter for unit testing, but it is not
    74  // used to stop migrations at that version.
    75  func UpgradeDatabase(sqlStore SqlStore, currentModelVersionString string) error {
    76  	currentModelVersion, err := semver.Parse(currentModelVersionString)
    77  	if err != nil {
    78  		return errors.Wrapf(err, "failed to parse current model version %s", currentModelVersionString)
    79  	}
    80  
    81  	nextUnsupportedMajorVersion := semver.Version{
    82  		Major: currentModelVersion.Major + 1,
    83  	}
    84  
    85  	oldestSupportedVersion, err := semver.Parse(OLDEST_SUPPORTED_VERSION)
    86  	if err != nil {
    87  		return errors.Wrapf(err, "failed to parse oldest supported version %s", OLDEST_SUPPORTED_VERSION)
    88  	}
    89  
    90  	var currentSchemaVersion *semver.Version
    91  	currentSchemaVersionString := sqlStore.GetCurrentSchemaVersion()
    92  	if currentSchemaVersionString != "" {
    93  		currentSchemaVersion, err = semver.New(currentSchemaVersionString)
    94  		if err != nil {
    95  			return errors.Wrapf(err, "failed to parse database schema version %s", currentSchemaVersionString)
    96  		}
    97  	}
    98  
    99  	// Assume a fresh database if no schema version has been recorded.
   100  	if currentSchemaVersion == nil {
   101  		if err := sqlStore.System().SaveOrUpdate(&model.System{Name: "Version", Value: currentModelVersion.String()}); err != nil {
   102  			return errors.Wrap(err, "failed to initialize schema version for fresh database")
   103  		}
   104  
   105  		currentSchemaVersion = &currentModelVersion
   106  		mlog.Info(fmt.Sprintf("The database schema has been set to version %s", *currentSchemaVersion))
   107  		return nil
   108  	}
   109  
   110  	// Upgrades prior to the oldest supported version are not supported.
   111  	if currentSchemaVersion.LT(oldestSupportedVersion) {
   112  		return errors.Errorf("Database schema version %s is no longer supported. This Xenia server supports automatic upgrades from schema version %s through schema version %s. Please manually upgrade to at least version %s before continuing.", *currentSchemaVersion, oldestSupportedVersion, currentModelVersion, oldestSupportedVersion)
   113  	}
   114  
   115  	// Allow forwards compatibility only within the same major version.
   116  	if currentSchemaVersion.GTE(nextUnsupportedMajorVersion) {
   117  		return errors.Errorf("Database schema version %s is not supported. This Xenia server supports only >=%s, <%s. Please upgrade to at least version %s before continuing.", *currentSchemaVersion, currentModelVersion, nextUnsupportedMajorVersion, nextUnsupportedMajorVersion)
   118  	} else if currentSchemaVersion.GT(currentModelVersion) {
   119  		mlog.Warn(fmt.Sprintf("The database schema with version %s is newer than Xenia version %s.", currentSchemaVersion, currentModelVersion))
   120  	}
   121  
   122  	// Otherwise, apply any necessary migrations. Note that these methods currently invoke
   123  	// os.Exit instead of returning an error.
   124  	UpgradeDatabaseToVersion31(sqlStore)
   125  	UpgradeDatabaseToVersion32(sqlStore)
   126  	UpgradeDatabaseToVersion33(sqlStore)
   127  	UpgradeDatabaseToVersion34(sqlStore)
   128  	UpgradeDatabaseToVersion35(sqlStore)
   129  	UpgradeDatabaseToVersion36(sqlStore)
   130  	UpgradeDatabaseToVersion37(sqlStore)
   131  	UpgradeDatabaseToVersion38(sqlStore)
   132  	UpgradeDatabaseToVersion39(sqlStore)
   133  	UpgradeDatabaseToVersion310(sqlStore)
   134  	UpgradeDatabaseToVersion40(sqlStore)
   135  	UpgradeDatabaseToVersion41(sqlStore)
   136  	UpgradeDatabaseToVersion42(sqlStore)
   137  	UpgradeDatabaseToVersion43(sqlStore)
   138  	UpgradeDatabaseToVersion44(sqlStore)
   139  	UpgradeDatabaseToVersion45(sqlStore)
   140  	UpgradeDatabaseToVersion46(sqlStore)
   141  	UpgradeDatabaseToVersion47(sqlStore)
   142  	UpgradeDatabaseToVersion471(sqlStore)
   143  	UpgradeDatabaseToVersion472(sqlStore)
   144  	UpgradeDatabaseToVersion48(sqlStore)
   145  	UpgradeDatabaseToVersion481(sqlStore)
   146  	UpgradeDatabaseToVersion49(sqlStore)
   147  	UpgradeDatabaseToVersion410(sqlStore)
   148  	UpgradeDatabaseToVersion50(sqlStore)
   149  	UpgradeDatabaseToVersion51(sqlStore)
   150  	UpgradeDatabaseToVersion52(sqlStore)
   151  	UpgradeDatabaseToVersion53(sqlStore)
   152  	UpgradeDatabaseToVersion54(sqlStore)
   153  	UpgradeDatabaseToVersion55(sqlStore)
   154  	UpgradeDatabaseToVersion56(sqlStore)
   155  	UpgradeDatabaseToVersion57(sqlStore)
   156  	UpgradeDatabaseToVersion58(sqlStore)
   157  	UpgradeDatabaseToVersion59(sqlStore)
   158  	UpgradeDatabaseToVersion510(sqlStore)
   159  	UpgradeDatabaseToVersion511(sqlStore)
   160  	UpgradeDatabaseToVersion512(sqlStore)
   161  	UpgradeDatabaseToVersion513(sqlStore)
   162  	UpgradeDatabaseToVersion514(sqlStore)
   163  
   164  	return nil
   165  }
   166  
   167  func saveSchemaVersion(sqlStore SqlStore, version string) {
   168  	if err := sqlStore.System().SaveOrUpdate(&model.System{Name: "Version", Value: version}); err != nil {
   169  		mlog.Critical(err.Error())
   170  		time.Sleep(time.Second)
   171  		os.Exit(EXIT_VERSION_SAVE)
   172  	}
   173  
   174  	mlog.Warn(fmt.Sprintf("The database schema has been upgraded to version %v", version))
   175  }
   176  
   177  func shouldPerformUpgrade(sqlStore SqlStore, currentSchemaVersion string, expectedSchemaVersion string) bool {
   178  	if sqlStore.GetCurrentSchemaVersion() == currentSchemaVersion {
   179  		mlog.Warn(fmt.Sprintf("Attempting to upgrade the database schema version from %s to %v", currentSchemaVersion, expectedSchemaVersion))
   180  
   181  		return true
   182  	}
   183  
   184  	return false
   185  }
   186  
   187  func UpgradeDatabaseToVersion31(sqlStore SqlStore) {
   188  	if shouldPerformUpgrade(sqlStore, VERSION_3_0_0, VERSION_3_1_0) {
   189  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
   190  		saveSchemaVersion(sqlStore, VERSION_3_1_0)
   191  	}
   192  }
   193  
   194  func UpgradeDatabaseToVersion32(sqlStore SqlStore) {
   195  	if shouldPerformUpgrade(sqlStore, VERSION_3_1_0, VERSION_3_2_0) {
   196  		sqlStore.CreateColumnIfNotExists("TeamMembers", "DeleteAt", "bigint(20)", "bigint", "0")
   197  
   198  		saveSchemaVersion(sqlStore, VERSION_3_2_0)
   199  	}
   200  }
   201  
   202  func themeMigrationFailed(err error) {
   203  	mlog.Critical(fmt.Sprintf("Failed to migrate User.ThemeProps to Preferences table %v", err))
   204  	time.Sleep(time.Second)
   205  	os.Exit(EXIT_THEME_MIGRATION)
   206  }
   207  
   208  func UpgradeDatabaseToVersion33(sqlStore SqlStore) {
   209  	if shouldPerformUpgrade(sqlStore, VERSION_3_2_0, VERSION_3_3_0) {
   210  		if sqlStore.DoesColumnExist("Users", "ThemeProps") {
   211  			params := map[string]interface{}{
   212  				"Category": model.PREFERENCE_CATEGORY_THEME,
   213  				"Name":     "",
   214  			}
   215  
   216  			transaction, err := sqlStore.GetMaster().Begin()
   217  			if err != nil {
   218  				themeMigrationFailed(err)
   219  			}
   220  			defer finalizeTransaction(transaction)
   221  
   222  			// increase size of Value column of Preferences table to match the size of the ThemeProps column
   223  			if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   224  				if _, err := transaction.Exec("ALTER TABLE Preferences ALTER COLUMN Value TYPE varchar(2000)"); err != nil {
   225  					themeMigrationFailed(err)
   226  					return
   227  				}
   228  			} else if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL {
   229  				if _, err := transaction.Exec("ALTER TABLE Preferences MODIFY Value text"); err != nil {
   230  					themeMigrationFailed(err)
   231  					return
   232  				}
   233  			}
   234  
   235  			// copy data across
   236  			if _, err := transaction.Exec(
   237  				`INSERT INTO
   238  					Preferences(UserId, Category, Name, Value)
   239  				SELECT
   240  					Id, '`+model.PREFERENCE_CATEGORY_THEME+`', '', ThemeProps
   241  				FROM
   242  					Users
   243  				WHERE
   244  					Users.ThemeProps != 'null'`, params); err != nil {
   245  				themeMigrationFailed(err)
   246  				return
   247  			}
   248  
   249  			// delete old data
   250  			if _, err := transaction.Exec("ALTER TABLE Users DROP COLUMN ThemeProps"); err != nil {
   251  				themeMigrationFailed(err)
   252  				return
   253  			}
   254  
   255  			if err := transaction.Commit(); err != nil {
   256  				themeMigrationFailed(err)
   257  				return
   258  			}
   259  
   260  			// rename solarized_* code themes to solarized-* to match client changes in 3.0
   261  			var data model.Preferences
   262  			if _, err := sqlStore.GetMaster().Select(&data, "SELECT * FROM Preferences WHERE Category = '"+model.PREFERENCE_CATEGORY_THEME+"' AND Value LIKE '%solarized_%'"); err == nil {
   263  				for i := range data {
   264  					data[i].Value = strings.Replace(data[i].Value, "solarized_", "solarized-", -1)
   265  				}
   266  
   267  				sqlStore.Preference().Save(&data)
   268  			}
   269  		}
   270  
   271  		sqlStore.CreateColumnIfNotExists("OAuthApps", "IsTrusted", "tinyint(1)", "boolean", "0")
   272  		sqlStore.CreateColumnIfNotExists("OAuthApps", "IconURL", "varchar(512)", "varchar(512)", "")
   273  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ClientId", "varchar(26)", "varchar(26)", "")
   274  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "UserId", "varchar(26)", "varchar(26)", "")
   275  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ExpiresAt", "bigint", "bigint", "0")
   276  
   277  		if sqlStore.DoesColumnExist("OAuthAccessData", "AuthCode") {
   278  			sqlStore.RemoveIndexIfExists("idx_oauthaccessdata_auth_code", "OAuthAccessData")
   279  			sqlStore.RemoveColumnIfExists("OAuthAccessData", "AuthCode")
   280  		}
   281  
   282  		sqlStore.RemoveColumnIfExists("Users", "LastActivityAt")
   283  		sqlStore.RemoveColumnIfExists("Users", "LastPingAt")
   284  
   285  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "TriggerWhen", "tinyint", "integer", "0")
   286  
   287  		saveSchemaVersion(sqlStore, VERSION_3_3_0)
   288  	}
   289  }
   290  
   291  func UpgradeDatabaseToVersion34(sqlStore SqlStore) {
   292  	if shouldPerformUpgrade(sqlStore, VERSION_3_3_0, VERSION_3_4_0) {
   293  		sqlStore.CreateColumnIfNotExists("Status", "Manual", "BOOLEAN", "BOOLEAN", "0")
   294  		sqlStore.CreateColumnIfNotExists("Status", "ActiveChannel", "varchar(26)", "varchar(26)", "")
   295  
   296  		saveSchemaVersion(sqlStore, VERSION_3_4_0)
   297  	}
   298  }
   299  
   300  func UpgradeDatabaseToVersion35(sqlStore SqlStore) {
   301  	if shouldPerformUpgrade(sqlStore, VERSION_3_4_0, VERSION_3_5_0) {
   302  		sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user' WHERE Roles = ''")
   303  		sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user system_admin' WHERE Roles = 'system_admin'")
   304  		sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user' WHERE Roles = ''")
   305  		sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user team_admin' WHERE Roles = 'admin'")
   306  		sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user' WHERE Roles = ''")
   307  		sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user channel_admin' WHERE Roles = 'admin'")
   308  
   309  		// The rest of the migration from Filenames -> FileIds is done lazily in api.GetFileInfosForPost
   310  		sqlStore.CreateColumnIfNotExists("Posts", "FileIds", "varchar(150)", "varchar(150)", "[]")
   311  
   312  		// Increase maximum length of the Channel table Purpose column.
   313  		if sqlStore.GetMaxLengthOfColumnIfExists("Channels", "Purpose") != "250" {
   314  			sqlStore.AlterColumnTypeIfExists("Channels", "Purpose", "varchar(250)", "varchar(250)")
   315  		}
   316  
   317  		sqlStore.Session().RemoveAllSessions()
   318  
   319  		saveSchemaVersion(sqlStore, VERSION_3_5_0)
   320  	}
   321  }
   322  
   323  func UpgradeDatabaseToVersion36(sqlStore SqlStore) {
   324  	if shouldPerformUpgrade(sqlStore, VERSION_3_5_0, VERSION_3_6_0) {
   325  		sqlStore.CreateColumnIfNotExists("Posts", "HasReactions", "tinyint", "boolean", "0")
   326  
   327  		// Create Team Description column
   328  		sqlStore.CreateColumnIfNotExists("Teams", "Description", "varchar(255)", "varchar(255)", "")
   329  
   330  		// Add a Position column to users.
   331  		sqlStore.CreateColumnIfNotExists("Users", "Position", "varchar(64)", "varchar(64)", "")
   332  
   333  		// Remove ActiveChannel column from Status
   334  		sqlStore.RemoveColumnIfExists("Status", "ActiveChannel")
   335  
   336  		saveSchemaVersion(sqlStore, VERSION_3_6_0)
   337  	}
   338  }
   339  
   340  func UpgradeDatabaseToVersion37(sqlStore SqlStore) {
   341  	if shouldPerformUpgrade(sqlStore, VERSION_3_6_0, VERSION_3_7_0) {
   342  		// Add EditAt column to Posts
   343  		sqlStore.CreateColumnIfNotExists("Posts", "EditAt", " bigint", " bigint", "0")
   344  
   345  		saveSchemaVersion(sqlStore, VERSION_3_7_0)
   346  	}
   347  }
   348  
   349  func UpgradeDatabaseToVersion38(sqlStore SqlStore) {
   350  	if shouldPerformUpgrade(sqlStore, VERSION_3_7_0, VERSION_3_8_0) {
   351  		// Add the IsPinned column to posts.
   352  		sqlStore.CreateColumnIfNotExists("Posts", "IsPinned", "boolean", "boolean", "0")
   353  
   354  		saveSchemaVersion(sqlStore, VERSION_3_8_0)
   355  	}
   356  }
   357  
   358  func UpgradeDatabaseToVersion39(sqlStore SqlStore) {
   359  	if shouldPerformUpgrade(sqlStore, VERSION_3_8_0, VERSION_3_9_0) {
   360  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "Scope", "varchar(128)", "varchar(128)", model.DEFAULT_SCOPE)
   361  		sqlStore.RemoveTableIfExists("PasswordRecovery")
   362  
   363  		saveSchemaVersion(sqlStore, VERSION_3_9_0)
   364  	}
   365  }
   366  
   367  func UpgradeDatabaseToVersion310(sqlStore SqlStore) {
   368  	if shouldPerformUpgrade(sqlStore, VERSION_3_9_0, VERSION_3_10_0) {
   369  		saveSchemaVersion(sqlStore, VERSION_3_10_0)
   370  	}
   371  }
   372  
   373  func UpgradeDatabaseToVersion40(sqlStore SqlStore) {
   374  	if shouldPerformUpgrade(sqlStore, VERSION_3_10_0, VERSION_4_0_0) {
   375  		saveSchemaVersion(sqlStore, VERSION_4_0_0)
   376  	}
   377  }
   378  
   379  func UpgradeDatabaseToVersion41(sqlStore SqlStore) {
   380  	if shouldPerformUpgrade(sqlStore, VERSION_4_0_0, VERSION_4_1_0) {
   381  		// Increase maximum length of the Users table Roles column.
   382  		if sqlStore.GetMaxLengthOfColumnIfExists("Users", "Roles") != "256" {
   383  			sqlStore.AlterColumnTypeIfExists("Users", "Roles", "varchar(256)", "varchar(256)")
   384  		}
   385  
   386  		sqlStore.RemoveTableIfExists("JobStatuses")
   387  
   388  		saveSchemaVersion(sqlStore, VERSION_4_1_0)
   389  	}
   390  }
   391  
   392  func UpgradeDatabaseToVersion42(sqlStore SqlStore) {
   393  	if shouldPerformUpgrade(sqlStore, VERSION_4_1_0, VERSION_4_2_0) {
   394  		saveSchemaVersion(sqlStore, VERSION_4_2_0)
   395  	}
   396  }
   397  
   398  func UpgradeDatabaseToVersion43(sqlStore SqlStore) {
   399  	if shouldPerformUpgrade(sqlStore, VERSION_4_2_0, VERSION_4_3_0) {
   400  		saveSchemaVersion(sqlStore, VERSION_4_3_0)
   401  	}
   402  }
   403  
   404  func UpgradeDatabaseToVersion44(sqlStore SqlStore) {
   405  	if shouldPerformUpgrade(sqlStore, VERSION_4_3_0, VERSION_4_4_0) {
   406  		// Add the IsActive column to UserAccessToken.
   407  		sqlStore.CreateColumnIfNotExists("UserAccessTokens", "IsActive", "boolean", "boolean", "1")
   408  
   409  		saveSchemaVersion(sqlStore, VERSION_4_4_0)
   410  	}
   411  }
   412  
   413  func UpgradeDatabaseToVersion45(sqlStore SqlStore) {
   414  	if shouldPerformUpgrade(sqlStore, VERSION_4_4_0, VERSION_4_5_0) {
   415  		saveSchemaVersion(sqlStore, VERSION_4_5_0)
   416  	}
   417  }
   418  
   419  func UpgradeDatabaseToVersion46(sqlStore SqlStore) {
   420  	if shouldPerformUpgrade(sqlStore, VERSION_4_5_0, VERSION_4_6_0) {
   421  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
   422  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
   423  		saveSchemaVersion(sqlStore, VERSION_4_6_0)
   424  	}
   425  }
   426  
   427  func UpgradeDatabaseToVersion47(sqlStore SqlStore) {
   428  	if shouldPerformUpgrade(sqlStore, VERSION_4_6_0, VERSION_4_7_0) {
   429  		sqlStore.AlterColumnTypeIfExists("Users", "Position", "varchar(128)", "varchar(128)")
   430  		sqlStore.AlterColumnTypeIfExists("OAuthAuthData", "State", "varchar(1024)", "varchar(1024)")
   431  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
   432  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Username")
   433  		saveSchemaVersion(sqlStore, VERSION_4_7_0)
   434  	}
   435  }
   436  
   437  // If any new instances started with 4.7, they would have the bad Email column on the
   438  // ChannelMemberHistory table. So for those cases we need to do an upgrade between
   439  // 4.7.0 and 4.7.1
   440  func UpgradeDatabaseToVersion471(sqlStore SqlStore) {
   441  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_7_1) {
   442  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
   443  		saveSchemaVersion(sqlStore, VERSION_4_7_1)
   444  	}
   445  }
   446  
   447  func UpgradeDatabaseToVersion472(sqlStore SqlStore) {
   448  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_1, VERSION_4_7_2) {
   449  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   450  		saveSchemaVersion(sqlStore, VERSION_4_7_2)
   451  	}
   452  }
   453  
   454  func UpgradeDatabaseToVersion48(sqlStore SqlStore) {
   455  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_2, VERSION_4_8_0) {
   456  		saveSchemaVersion(sqlStore, VERSION_4_8_0)
   457  	}
   458  }
   459  
   460  func UpgradeDatabaseToVersion481(sqlStore SqlStore) {
   461  	if shouldPerformUpgrade(sqlStore, VERSION_4_8_0, VERSION_4_8_1) {
   462  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   463  		saveSchemaVersion(sqlStore, VERSION_4_8_1)
   464  	}
   465  }
   466  
   467  func UpgradeDatabaseToVersion49(sqlStore SqlStore) {
   468  	// This version of Xenia includes an App-Layer migration which migrates from hard-coded roles configured by
   469  	// a number of parameters in `config.json` to a `Roles` table in the database. The migration code can be seen
   470  	// in the file `app/app.go` in the function `DoAdvancedPermissionsMigration()`.
   471  
   472  	if shouldPerformUpgrade(sqlStore, VERSION_4_8_1, VERSION_4_9_0) {
   473  		sqlStore.CreateColumnIfNotExists("Teams", "LastTeamIconUpdate", "bigint", "bigint", "0")
   474  		defaultTimezone := timezones.DefaultUserTimezone()
   475  		defaultTimezoneValue, err := json.Marshal(defaultTimezone)
   476  		if err != nil {
   477  			mlog.Critical(fmt.Sprint(err))
   478  		}
   479  		sqlStore.CreateColumnIfNotExists("Users", "Timezone", "varchar(256)", "varchar(256)", string(defaultTimezoneValue))
   480  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   481  		saveSchemaVersion(sqlStore, VERSION_4_9_0)
   482  	}
   483  }
   484  
   485  func UpgradeDatabaseToVersion410(sqlStore SqlStore) {
   486  	if shouldPerformUpgrade(sqlStore, VERSION_4_9_0, VERSION_4_10_0) {
   487  
   488  		sqlStore.RemoveIndexIfExists("Name_2", "Channels")
   489  		sqlStore.RemoveIndexIfExists("Name_2", "Emoji")
   490  		sqlStore.RemoveIndexIfExists("ClientId_2", "OAuthAccessData")
   491  
   492  		saveSchemaVersion(sqlStore, VERSION_4_10_0)
   493  		sqlStore.GetMaster().Exec("UPDATE Users SET AuthData=LOWER(AuthData) WHERE AuthService = 'saml'")
   494  	}
   495  }
   496  
   497  func UpgradeDatabaseToVersion50(sqlStore SqlStore) {
   498  	// This version of Xenia includes an App-Layer migration which migrates from hard-coded emojis configured
   499  	// in `config.json` to a `Permission` in the database. The migration code can be seen
   500  	// in the file `app/app.go` in the function `DoEmojisPermissionsMigration()`.
   501  
   502  	// This version of Xenia also includes a online-migration which migrates some roles from the `Roles` columns of
   503  	// TeamMember and ChannelMember rows to the new SchemeAdmin and SchemeUser columns. If you need to downgrade to a
   504  	// version of Xenia prior to 5.0, you should take your server offline and run the following SQL statements
   505  	// prior to launching the downgraded version:
   506  	//
   507  	//    UPDATE Teams SET SchemeId = NULL;
   508  	//    UPDATE Channels SET SchemeId = NULL;
   509  	//    UPDATE TeamMembers SET Roles = CONCAT(Roles, ' team_user'), SchemeUser = NULL where SchemeUser = 1;
   510  	//    UPDATE TeamMembers SET Roles = CONCAT(Roles, ' team_admin'), SchemeAdmin = NULL where SchemeAdmin = 1;
   511  	//    UPDATE ChannelMembers SET Roles = CONCAT(Roles, ' channel_user'), SchemeUser = NULL where SchemeUser = 1;
   512  	//    UPDATE ChannelMembers SET Roles = CONCAT(Roles, ' channel_admin'), SchemeAdmin = NULL where SchemeAdmin = 1;
   513  	//    DELETE from Systems WHERE Name = 'migration_advanced_permissions_phase_2';
   514  
   515  	if shouldPerformUpgrade(sqlStore, VERSION_4_10_0, VERSION_5_0_0) {
   516  
   517  		sqlStore.CreateColumnIfNotExistsNoDefault("Teams", "SchemeId", "varchar(26)", "varchar(26)")
   518  		sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "SchemeId", "varchar(26)", "varchar(26)")
   519  
   520  		sqlStore.CreateColumnIfNotExistsNoDefault("TeamMembers", "SchemeUser", "boolean", "boolean")
   521  		sqlStore.CreateColumnIfNotExistsNoDefault("TeamMembers", "SchemeAdmin", "boolean", "boolean")
   522  		sqlStore.CreateColumnIfNotExistsNoDefault("ChannelMembers", "SchemeUser", "boolean", "boolean")
   523  		sqlStore.CreateColumnIfNotExistsNoDefault("ChannelMembers", "SchemeAdmin", "boolean", "boolean")
   524  
   525  		sqlStore.CreateColumnIfNotExists("Roles", "BuiltIn", "boolean", "boolean", "0")
   526  		sqlStore.GetMaster().Exec("UPDATE Roles SET BuiltIn=true")
   527  		sqlStore.GetMaster().Exec("UPDATE Roles SET SchemeManaged=false WHERE Name NOT IN ('system_user', 'system_admin', 'team_user', 'team_admin', 'channel_user', 'channel_admin')")
   528  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "ChannelLocked", "boolean", "boolean", "0")
   529  
   530  		sqlStore.RemoveIndexIfExists("idx_channels_txt", "Channels")
   531  
   532  		saveSchemaVersion(sqlStore, VERSION_5_0_0)
   533  	}
   534  }
   535  
   536  func UpgradeDatabaseToVersion51(sqlStore SqlStore) {
   537  	if shouldPerformUpgrade(sqlStore, VERSION_5_0_0, VERSION_5_1_0) {
   538  		saveSchemaVersion(sqlStore, VERSION_5_1_0)
   539  	}
   540  }
   541  
   542  func UpgradeDatabaseToVersion52(sqlStore SqlStore) {
   543  	if shouldPerformUpgrade(sqlStore, VERSION_5_1_0, VERSION_5_2_0) {
   544  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
   545  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
   546  		saveSchemaVersion(sqlStore, VERSION_5_2_0)
   547  	}
   548  }
   549  
   550  func UpgradeDatabaseToVersion53(sqlStore SqlStore) {
   551  	if shouldPerformUpgrade(sqlStore, VERSION_5_2_0, VERSION_5_3_0) {
   552  		saveSchemaVersion(sqlStore, VERSION_5_3_0)
   553  	}
   554  }
   555  
   556  func UpgradeDatabaseToVersion54(sqlStore SqlStore) {
   557  	if shouldPerformUpgrade(sqlStore, VERSION_5_3_0, VERSION_5_4_0) {
   558  		sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "Description", "varchar(500)", "varchar(500)")
   559  		sqlStore.AlterColumnTypeIfExists("IncomingWebhooks", "Description", "varchar(500)", "varchar(500)")
   560  		if err := sqlStore.Channel().MigratePublicChannels(); err != nil {
   561  			mlog.Critical("Failed to migrate PublicChannels table", mlog.Err(err))
   562  			time.Sleep(time.Second)
   563  			os.Exit(EXIT_GENERIC_FAILURE)
   564  		}
   565  		saveSchemaVersion(sqlStore, VERSION_5_4_0)
   566  	}
   567  }
   568  
   569  func UpgradeDatabaseToVersion55(sqlStore SqlStore) {
   570  	if shouldPerformUpgrade(sqlStore, VERSION_5_4_0, VERSION_5_5_0) {
   571  		saveSchemaVersion(sqlStore, VERSION_5_5_0)
   572  	}
   573  }
   574  
   575  func UpgradeDatabaseToVersion56(sqlStore SqlStore) {
   576  	if shouldPerformUpgrade(sqlStore, VERSION_5_5_0, VERSION_5_6_0) {
   577  		sqlStore.CreateColumnIfNotExists("PluginKeyValueStore", "ExpireAt", "bigint(20)", "bigint", "0")
   578  
   579  		// migrating user's accepted terms of service data into the new table
   580  		sqlStore.GetMaster().Exec("INSERT INTO UserTermsOfService SELECT Id, AcceptedTermsOfServiceId as TermsOfServiceId, :CreateAt FROM Users WHERE AcceptedTermsOfServiceId != \"\" AND AcceptedTermsOfServiceId IS NOT NULL", map[string]interface{}{"CreateAt": model.GetMillis()})
   581  
   582  		if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   583  			sqlStore.RemoveIndexIfExists("idx_users_email_lower", "lower(Email)")
   584  			sqlStore.RemoveIndexIfExists("idx_users_username_lower", "lower(Username)")
   585  			sqlStore.RemoveIndexIfExists("idx_users_nickname_lower", "lower(Nickname)")
   586  			sqlStore.RemoveIndexIfExists("idx_users_firstname_lower", "lower(FirstName)")
   587  			sqlStore.RemoveIndexIfExists("idx_users_lastname_lower", "lower(LastName)")
   588  		}
   589  
   590  		saveSchemaVersion(sqlStore, VERSION_5_6_0)
   591  	}
   592  
   593  }
   594  
   595  func UpgradeDatabaseToVersion57(sqlStore SqlStore) {
   596  	if shouldPerformUpgrade(sqlStore, VERSION_5_6_0, VERSION_5_7_0) {
   597  		saveSchemaVersion(sqlStore, VERSION_5_7_0)
   598  	}
   599  }
   600  
   601  func getRole(sqlStore SqlStore, name string) (*model.Role, error) {
   602  	var dbRole Role
   603  
   604  	if err := sqlStore.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
   605  		if err == sql.ErrNoRows {
   606  			return nil, errors.Wrapf(err, "failed to find role %s", name)
   607  		} else {
   608  			return nil, errors.Wrapf(err, "failed to query role %s", name)
   609  		}
   610  	}
   611  
   612  	return dbRole.ToModel(), nil
   613  }
   614  
   615  func saveRole(sqlStore SqlStore, role *model.Role) error {
   616  	dbRole := NewRoleFromModel(role)
   617  
   618  	dbRole.UpdateAt = model.GetMillis()
   619  	if rowsChanged, err := sqlStore.GetMaster().Update(dbRole); err != nil {
   620  		return errors.Wrap(err, "failed to update role")
   621  	} else if rowsChanged != 1 {
   622  		return errors.New("found no role to update")
   623  	}
   624  
   625  	return nil
   626  }
   627  
   628  func UpgradeDatabaseToVersion58(sqlStore SqlStore) {
   629  	if shouldPerformUpgrade(sqlStore, VERSION_5_7_0, VERSION_5_8_0) {
   630  		// idx_channels_txt was removed in `UpgradeDatabaseToVersion50`, but merged as part of
   631  		// v5.1, so the migration wouldn't apply to anyone upgrading from v5.0. Remove it again to
   632  		// bring the upgraded (from v5.0) and fresh install schemas back in sync.
   633  		sqlStore.RemoveIndexIfExists("idx_channels_txt", "Channels")
   634  
   635  		// Fix column types and defaults where gorp converged on a different schema value than the
   636  		// original migration.
   637  		sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "Description", "text", "VARCHAR(500)")
   638  		sqlStore.AlterColumnTypeIfExists("IncomingWebhooks", "Description", "text", "VARCHAR(500)")
   639  		sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "IconURL", "text", "VARCHAR(1024)")
   640  		sqlStore.AlterColumnDefaultIfExists("OutgoingWebhooks", "Username", model.NewString("NULL"), model.NewString(""))
   641  		sqlStore.AlterColumnDefaultIfExists("OutgoingWebhooks", "IconURL", nil, model.NewString(""))
   642  		sqlStore.AlterColumnDefaultIfExists("PluginKeyValueStore", "ExpireAt", model.NewString("NULL"), model.NewString("NULL"))
   643  
   644  		saveSchemaVersion(sqlStore, VERSION_5_8_0)
   645  	}
   646  }
   647  
   648  func UpgradeDatabaseToVersion59(sqlStore SqlStore) {
   649  	if shouldPerformUpgrade(sqlStore, VERSION_5_8_0, VERSION_5_9_0) {
   650  		saveSchemaVersion(sqlStore, VERSION_5_9_0)
   651  	}
   652  }
   653  
   654  func UpgradeDatabaseToVersion510(sqlStore SqlStore) {
   655  	if shouldPerformUpgrade(sqlStore, VERSION_5_9_0, VERSION_5_10_0) {
   656  		sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "GroupConstrained", "tinyint(4)", "boolean")
   657  		sqlStore.CreateColumnIfNotExistsNoDefault("Teams", "GroupConstrained", "tinyint(4)", "boolean")
   658  
   659  		sqlStore.CreateIndexIfNotExists("idx_groupteams_teamid", "GroupTeams", "TeamId")
   660  		sqlStore.CreateIndexIfNotExists("idx_groupchannels_channelid", "GroupChannels", "ChannelId")
   661  
   662  		saveSchemaVersion(sqlStore, VERSION_5_10_0)
   663  	}
   664  }
   665  
   666  func UpgradeDatabaseToVersion511(sqlStore SqlStore) {
   667  	if shouldPerformUpgrade(sqlStore, VERSION_5_10_0, VERSION_5_11_0) {
   668  		// Enforce all teams have an InviteID set
   669  		var teams []*model.Team
   670  		if _, err := sqlStore.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE InviteId = ''"); err != nil {
   671  			mlog.Error("Error fetching Teams without InviteID: " + err.Error())
   672  		} else {
   673  			for _, team := range teams {
   674  				team.InviteId = model.NewId()
   675  				if _, err := sqlStore.Team().Update(team); err != nil {
   676  					mlog.Error("Error updating Team InviteIDs: " + err.Error())
   677  				}
   678  			}
   679  		}
   680  
   681  		saveSchemaVersion(sqlStore, VERSION_5_11_0)
   682  	}
   683  }
   684  
   685  func UpgradeDatabaseToVersion512(sqlStore SqlStore) {
   686  	if shouldPerformUpgrade(sqlStore, VERSION_5_11_0, VERSION_5_12_0) {
   687  		sqlStore.CreateColumnIfNotExistsNoDefault("TeamMembers", "SchemeGuest", "boolean", "boolean")
   688  		sqlStore.CreateColumnIfNotExistsNoDefault("ChannelMembers", "SchemeGuest", "boolean", "boolean")
   689  		sqlStore.CreateColumnIfNotExistsNoDefault("Schemes", "DefaultTeamGuestRole", "text", "VARCHAR(64)")
   690  		sqlStore.CreateColumnIfNotExistsNoDefault("Schemes", "DefaultChannelGuestRole", "text", "VARCHAR(64)")
   691  		sqlStore.GetMaster().Exec("UPDATE Schemes SET DefaultTeamGuestRole = '', DefaultChannelGuestRole = ''")
   692  
   693  		// Saturday, January 24, 2065 5:20:00 AM GMT. To remove all personal access token sessions.
   694  		sqlStore.GetMaster().Exec("DELETE FROM Sessions WHERE ExpiresAt > 3000000000000")
   695  
   696  		saveSchemaVersion(sqlStore, VERSION_5_12_0)
   697  	}
   698  }
   699  
   700  func UpgradeDatabaseToVersion513(sqlStore SqlStore) {
   701  	if shouldPerformUpgrade(sqlStore, VERSION_5_12_0, VERSION_5_13_0) {
   702  		saveSchemaVersion(sqlStore, VERSION_5_13_0)
   703  	}
   704  }
   705  
   706  func UpgradeDatabaseToVersion514(sqlStore SqlStore) {
   707  	// TODO: Uncomment following condition when version 5.14.0 is released
   708  	// if shouldPerformUpgrade(sqlStore, VERSION_5_13_0, VERSION_5_14_0) {
   709  
   710  	// 	saveSchemaVersion(sqlStore, VERSION_5_14_0)
   711  	// }
   712  }