func convertTeamTo30(primaryTeamName string, team *TeamForUpgrade, uniqueEmails map[string]bool, uniqueUsernames map[string]bool) []*UserForUpgrade { store := api.Srv.Store.(*store.SqlStore) var users []*UserForUpgrade if _, err := store.GetMaster().Select(&users, "SELECT Users.Id, Users.Username, Users.Email, Users.Roles, Users.TeamId FROM Users WHERE Users.TeamId = :TeamId", map[string]interface{}{"TeamId": team.Id}); err != nil { l4g.Error("Failed to load profiles for team details=%v", err) flushLogAndExit(1) } var members []*model.TeamMember if result := <-api.Srv.Store.Team().GetMembers(team.Id); result.Err != nil { l4g.Error("Failed to load team membership details=%v", result.Err) flushLogAndExit(1) } else { members = result.Data.([]*model.TeamMember) } for _, user := range users { shouldUpdateUser := false previousRole := user.Roles previousEmail := user.Email previousUsername := user.Username member := &model.TeamMember{ TeamId: team.Id, UserId: user.Id, } if model.IsInRole(user.Roles, model.ROLE_TEAM_ADMIN) { member.Roles = model.ROLE_TEAM_ADMIN user.Roles = "" shouldUpdateUser = true } exists := false for _, member := range members { if member.UserId == user.Id { exists = true break } } if !exists { if result := <-api.Srv.Store.Team().SaveMember(member); result.Err != nil { l4g.Error("Failed to save membership for %v details=%v", user.Email, result.Err) flushLogAndExit(1) } } err := api.MoveFile( "teams/"+team.Id+"/users/"+user.Id+"/profile.png", "users/"+user.Id+"/profile.png", ) if err != nil { l4g.Warn("No profile image to move for %v", user.Email) } if uniqueEmails[user.Email] { shouldUpdateUser = true emailParts := strings.Split(user.Email, "@") if len(emailParts) == 2 { user.Email = emailParts[0] + "+" + team.Name + "@" + emailParts[1] } else { user.Email = user.Email + "." + team.Name } if len(user.Email) > 127 { user.Email = user.Email[:127] } } if uniqueUsernames[user.Username] { shouldUpdateUser = true user.Username = team.Name + "." + user.Username if len(user.Username) > 63 { user.Username = user.Username[:63] } } if shouldUpdateUser { if _, err := store.GetMaster().Exec(` UPDATE Users SET Email = :Email, Username = :Username, Roles = :Roles WHERE Id = :Id `, map[string]interface{}{ "Email": user.Email, "Username": user.Username, "Roles": user.Roles, "Id": user.Id, }, ); err != nil { l4g.Error("Failed to update user %v details=%v", user.Email, err) flushLogAndExit(1) } l4g.Info("modified user_id=%v, changed email from=%v to=%v, changed username from=%v to %v changed roles from=%v to=%v", user.Id, previousEmail, user.Email, previousUsername, user.Username, previousRole, user.Roles) emailChanged := previousEmail != user.Email usernameChanged := previousUsername != user.Username if emailChanged || usernameChanged { bodyPage := utils.NewHTMLTemplate("upgrade_30_body", "") EmailChanged := "" UsernameChanged := "" if emailChanged { EmailChanged = "true" } if usernameChanged { UsernameChanged = "true" } bodyPage.Html["Info"] = template.HTML(utils.T("api.templates.upgrade_30_body.info", map[string]interface{}{ "SiteName": utils.ClientCfg["SiteName"], "TeamName": team.Name, "Email": user.Email, "Username": user.Username, "EmailChanged": EmailChanged, "UsernameChanged": UsernameChanged, })) utils.SendMail( previousEmail, utils.T("api.templates.upgrade_30_subject.info"), bodyPage.Render(), ) } } uniqueEmails[user.Email] = true uniqueUsernames[user.Username] = true } return users }
// ADDED for 3.0 REMOVE for 3.4 func cmdUpdateDb30() { if flagCmdUpdateDb30 { api.Srv = &api.Server{} api.Srv.Store = store.NewSqlStoreForUpgrade30() store := api.Srv.Store.(*store.SqlStore) utils.InitHTML() l4g.Info("Attempting to run speical upgrade of the database schema to version 3.0 for user model changes") time.Sleep(time.Second) if !store.DoesColumnExist("Users", "TeamId") { fmt.Println("**WARNING** the database schema appears to be upgraded to 3.0") flushLogAndExit(1) } if !(store.SchemaVersion == "2.2.0" || store.SchemaVersion == "2.1.0" || store.SchemaVersion == "2.0.0") { fmt.Println("**WARNING** the database schema needs to be version 2.2.0, 2.1.0 or 2.0.0 to upgrade") flushLogAndExit(1) } var confirmBackup string fmt.Println("\nPlease see http://www.mattermost.org/upgrade-to-3-0/") fmt.Println("**WARNING** This upgrade process will be irreversible.") fmt.Print("Have you performed a database backup? (YES/NO): ") fmt.Scanln(&confirmBackup) if confirmBackup != "YES" { fmt.Fprintln(os.Stderr, "ABORTED: You did not answer YES exactly, in all capitals.") flushLogAndExit(1) } var flagTeamName string var teams []*TeamForUpgrade if _, err := store.GetMaster().Select(&teams, "SELECT Id, Name FROM Teams"); err != nil { l4g.Error("Failed to load all teams details=%v", err) flushLogAndExit(1) } fmt.Println(fmt.Sprintf("We found %v teams.", len(teams))) for _, team := range teams { fmt.Println(team.Name) } fmt.Print("Please pick a primary team from the list above: ") fmt.Scanln(&flagTeamName) var team *TeamForUpgrade for _, t := range teams { if t.Name == flagTeamName { team = t break } } if team == nil { l4g.Error("Failed to find primary team details") flushLogAndExit(1) } l4g.Info("Starting speical 3.0 database upgrade with performed_backup=YES team_name=%v", team.Name) l4g.Info("Primary team %v will be left unchanged", team.Name) l4g.Info("Upgrading primary team %v", team.Name) uniqueEmails := make(map[string]bool) uniqueUsernames := make(map[string]bool) primaryUsers := convertTeamTo30(team.Name, team, uniqueEmails, uniqueUsernames) l4g.Info("Upgraded %v users", len(primaryUsers)) for _, otherTeam := range teams { if otherTeam.Id != team.Id { l4g.Info("Upgrading team %v", otherTeam.Name) users := convertTeamTo30(team.Name, otherTeam, uniqueEmails, uniqueUsernames) l4g.Info("Upgraded %v users", len(users)) } } l4g.Info("Altering other scheme changes needed 3.0 for user model changes") if _, err := store.GetMaster().Exec(` UPDATE Channels SET TeamId = '' WHERE Type = 'D' `, ); err != nil { l4g.Error("Failed to update direct channel types details=%v", err) flushLogAndExit(1) } extraLength := store.GetMaxLengthOfColumnIfExists("Audits", "ExtraInfo") if len(extraLength) > 0 && extraLength != "1024" { store.AlterColumnTypeIfExists("Audits", "ExtraInfo", "VARCHAR(1024)", "VARCHAR(1024)") } actionLength := store.GetMaxLengthOfColumnIfExists("Audits", "Action") if len(actionLength) > 0 && actionLength != "512" { store.AlterColumnTypeIfExists("Audits", "Action", "VARCHAR(512)", "VARCHAR(512)") } if store.DoesColumnExist("Sessions", "TeamId") { store.RemoveColumnIfExists("Sessions", "TeamId") store.GetMaster().Exec(`TRUNCATE Sessions`) } // ADDED for 2.2 REMOVE for 2.6 store.CreateColumnIfNotExists("Users", "MfaActive", "tinyint(1)", "boolean", "0") store.CreateColumnIfNotExists("Users", "MfaSecret", "varchar(128)", "character varying(128)", "") // ADDED for 2.2 REMOVE for 2.6 if store.DoesColumnExist("Users", "TeamId") { store.RemoveIndexIfExists("idx_users_team_id", "Users") store.CreateUniqueIndexIfNotExists("idx_users_email_unique", "Users", "Email") store.CreateUniqueIndexIfNotExists("idx_users_username_unique", "Users", "Username") store.RemoveColumnIfExists("Teams", "AllowTeamListing") store.RemoveColumnIfExists("Users", "TeamId") } l4g.Info("Finished running speical upgrade of the database schema to version 3.0 for user model changes") if result := <-store.System().Update(&model.System{Name: "Version", Value: model.CurrentVersion}); result.Err != nil { l4g.Error("Failed to update system schema version details=%v", result.Err) flushLogAndExit(1) } l4g.Info(utils.T("store.sql.upgraded.warn"), model.CurrentVersion) fmt.Println("**SUCCESS** with upgrade") flushLogAndExit(0) } }