mirror of
https://github.com/mattermost/focalboard.git
synced 2025-03-26 20:53:55 +02:00
Adds data migration to clean badly assigned boards (#3635)
* Adds data migration to clean badly assigned boards This data migration fetches all boards whose owner has a deleted membership on the board's team and fixes them by processing them again, this time with the fix applied to the `getBestTeamForBoard` function that skips deleted teams and team memberships * Do not create a transaction if there are no offending boards found * Fix linter
This commit is contained in:
parent
2f29266767
commit
19ef6533f6
@ -19,10 +19,11 @@ const (
|
||||
// query, so we want to stay safely below.
|
||||
CategoryInsertBatch = 1000
|
||||
|
||||
TemplatesToTeamsMigrationKey = "TemplatesToTeamsMigrationComplete"
|
||||
UniqueIDsMigrationKey = "UniqueIDsMigrationComplete"
|
||||
CategoryUUIDIDMigrationKey = "CategoryUuidIdMigrationComplete"
|
||||
TeamLessBoardsMigrationKey = "TeamLessBoardsMigrationComplete"
|
||||
TemplatesToTeamsMigrationKey = "TemplatesToTeamsMigrationComplete"
|
||||
UniqueIDsMigrationKey = "UniqueIDsMigrationComplete"
|
||||
CategoryUUIDIDMigrationKey = "CategoryUuidIdMigrationComplete"
|
||||
TeamLessBoardsMigrationKey = "TeamLessBoardsMigrationComplete"
|
||||
DeletedMembershipBoardsMigrationKey = "DeletedMembershipBoardsMigrationComplete"
|
||||
)
|
||||
|
||||
func (s *SQLStore) getBlocksWithSameID(db sq.BaseRunner) ([]model.Block, error) {
|
||||
@ -390,6 +391,7 @@ func (s *SQLStore) runTeamLessBoardsMigration() error {
|
||||
if err != nil {
|
||||
// don't let one board's error spoil
|
||||
// the mood for others
|
||||
s.logger.Error("could not find the best team for board during team less boards migration. Continuing", mlog.String("boardID", boards[i].ID))
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -411,7 +413,7 @@ func (s *SQLStore) runTeamLessBoardsMigration() error {
|
||||
|
||||
if err := s.setSystemSetting(tx, TeamLessBoardsMigrationKey, strconv.FormatBool(true)); err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
s.logger.Error("transaction rollback error", mlog.Err(rollbackErr), mlog.String("methodName", "migrateTeamLessBoards"))
|
||||
s.logger.Error("transaction rollback error", mlog.Err(rollbackErr), mlog.String("methodName", "runTeamLessBoardsMigration"))
|
||||
}
|
||||
return fmt.Errorf("cannot mark migration as completed: %w", err)
|
||||
}
|
||||
@ -547,3 +549,99 @@ func (s *SQLStore) getBoardUserTeams(tx sq.BaseRunner, board *model.Board) (map[
|
||||
|
||||
return userTeams, nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) runDeletedMembershipBoardsMigration() error {
|
||||
if !s.isPlugin {
|
||||
return nil
|
||||
}
|
||||
|
||||
setting, err := s.GetSystemSetting(DeletedMembershipBoardsMigrationKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get deleted membership boards migration state: %w", err)
|
||||
}
|
||||
|
||||
// If the migration is already completed, do not run it again.
|
||||
if hasAlreadyRun, _ := strconv.ParseBool(setting); hasAlreadyRun {
|
||||
return nil
|
||||
}
|
||||
|
||||
boards, err := s.getDeletedMembershipBoards(s.db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(boards) == 0 {
|
||||
s.logger.Debug("No boards with owner not anymore on their team found, marking runDeletedMembershipBoardsMigration as done")
|
||||
if sErr := s.SetSystemSetting(DeletedMembershipBoardsMigrationKey, strconv.FormatBool(true)); sErr != nil {
|
||||
return fmt.Errorf("cannot mark migration as completed: %w", sErr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
s.logger.Debug("Migrating boards with owner not anymore on their team", mlog.Int("count", len(boards)))
|
||||
|
||||
tx, err := s.db.BeginTx(context.Background(), nil)
|
||||
if err != nil {
|
||||
s.logger.Error("error starting transaction in runDeletedMembershipBoardsMigration", mlog.Err(err))
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range boards {
|
||||
teamID, err := s.getBestTeamForBoard(s.db, boards[i])
|
||||
if err != nil {
|
||||
// don't let one board's error spoil
|
||||
// the mood for others
|
||||
s.logger.Error("could not find the best team for board during deleted membership boards migration. Continuing", mlog.String("boardID", boards[i].ID))
|
||||
continue
|
||||
}
|
||||
|
||||
boards[i].TeamID = teamID
|
||||
|
||||
query := s.getQueryBuilder(tx).
|
||||
Update(s.tablePrefix+"boards").
|
||||
Set("team_id", teamID).
|
||||
Where(sq.Eq{"id": boards[i].ID})
|
||||
|
||||
if _, err := query.Exec(); err != nil {
|
||||
s.logger.Error("failed to set team id for board", mlog.String("board_id", boards[i].ID), mlog.String("team_id", teamID), mlog.Err(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.setSystemSetting(tx, DeletedMembershipBoardsMigrationKey, strconv.FormatBool(true)); err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
s.logger.Error("transaction rollback error", mlog.Err(rollbackErr), mlog.String("methodName", "runDeletedMembershipBoardsMigration"))
|
||||
}
|
||||
return fmt.Errorf("cannot mark migration as completed: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
s.logger.Error("failed to commit runDeletedMembershipBoardsMigration transaction", mlog.Err(err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDeletedMembershipBoards retrieves those boards whose creator is
|
||||
// associated to the board's team with a deleted team membership.
|
||||
func (s *SQLStore) getDeletedMembershipBoards(tx sq.BaseRunner) ([]*model.Board, error) {
|
||||
rows, err := s.getQueryBuilder(tx).
|
||||
Select(legacyBoardFields("b.")...).
|
||||
From(s.tablePrefix + "boards b").
|
||||
Join("TeamMembers tm ON b.created_by = tm.UserId").
|
||||
Where("b.team_id = tm.TeamId").
|
||||
Where(sq.NotEq{"tm.DeleteAt": 0}).
|
||||
Query()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.CloseRows(rows)
|
||||
|
||||
boards, err := s.boardsFromRows(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return boards, err
|
||||
}
|
||||
|
@ -44,9 +44,12 @@ func legacyBoardFields(prefix string) []string {
|
||||
|
||||
prefixedFields := make([]string, len(fields))
|
||||
for i, field := range fields {
|
||||
if strings.HasPrefix(field, "COALESCE(") {
|
||||
switch {
|
||||
case strings.HasPrefix(field, "COALESCE("):
|
||||
prefixedFields[i] = strings.Replace(field, "COALESCE(", "COALESCE("+prefix, 1)
|
||||
} else {
|
||||
case field == "''":
|
||||
prefixedFields[i] = field
|
||||
default:
|
||||
prefixedFields[i] = prefix + field
|
||||
}
|
||||
}
|
||||
|
@ -241,6 +241,10 @@ func (s *SQLStore) Migrate() error {
|
||||
return mErr
|
||||
}
|
||||
|
||||
if mErr := s.runDeletedMembershipBoardsMigration(); mErr != nil {
|
||||
return mErr
|
||||
}
|
||||
|
||||
if mErr := s.ensureMigrationsAppliedUpToVersion(engine, driver, categoriesUUIDIDMigrationRequiredVersion); mErr != nil {
|
||||
return mErr
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user