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 = ¤tModelVersion 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 }