From ff3d223794e6bd0ff457df91a410ac87842affe3 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Mon, 2 Oct 2023 19:21:16 +1100 Subject: [PATCH 1/2] Add data correction migration --- pkg/sqlite/database.go | 2 +- pkg/sqlite/migrations/52_postmigrate.go | 79 +++++++++++++++++++ .../52_zip_folder_data_correct.up.sql | 1 + 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 pkg/sqlite/migrations/52_postmigrate.go create mode 100644 pkg/sqlite/migrations/52_zip_folder_data_correct.up.sql diff --git a/pkg/sqlite/database.go b/pkg/sqlite/database.go index 6b3b4171dcf..75a0f42a9e5 100644 --- a/pkg/sqlite/database.go +++ b/pkg/sqlite/database.go @@ -33,7 +33,7 @@ const ( dbConnTimeout = 30 ) -var appSchemaVersion uint = 51 +var appSchemaVersion uint = 52 //go:embed migrations/*.sql var migrationsBox embed.FS diff --git a/pkg/sqlite/migrations/52_postmigrate.go b/pkg/sqlite/migrations/52_postmigrate.go new file mode 100644 index 00000000000..3db07fde8c5 --- /dev/null +++ b/pkg/sqlite/migrations/52_postmigrate.go @@ -0,0 +1,79 @@ +package migrations + +import ( + "context" + "fmt" + "path/filepath" + "strings" + + "github.com/jmoiron/sqlx" + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/sqlite" +) + +type schema52Migrator struct { + migrator +} + +func post52(ctx context.Context, db *sqlx.DB) error { + logger.Info("Running post-migration for schema version 52") + + m := schema52Migrator{ + migrator: migrator{ + db: db, + }, + } + + return m.migrate(ctx) +} + +func (m *schema52Migrator) migrate(ctx context.Context) error { + if err := m.withTxn(ctx, func(tx *sqlx.Tx) error { + query := "SELECT `folders`.`id`, `folders`.`path`, `parent_folder`.`path` FROM `folders` " + + "INNER JOIN `folders` AS `parent_folder` ON `parent_folder`.`id` = `folders`.`parent_folder_id`" + + rows, err := m.db.Query(query) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var ( + id int + folderPath string + parentFolderPath string + ) + + err := rows.Scan(&id, &folderPath, &parentFolderPath) + if err != nil { + return err + } + + // ensure folder path is correct + if !strings.HasPrefix(folderPath, parentFolderPath) { + logger.Debugf("folder path %s does not have prefix %s. Correcting...", folderPath, parentFolderPath) + + // get the basename of the zip folder path and append it to the correct path + folderBasename := filepath.Base(folderPath) + correctPath := filepath.Join(parentFolderPath, folderBasename) + + logger.Infof("correcting folder path %s to %s", folderPath, correctPath) + + if _, err := m.db.Exec("UPDATE folders SET path = ? WHERE id = ?", correctPath, id); err != nil { + return fmt.Errorf("error updating folder path %s to %s: %w", folderPath, correctPath, err) + } + } + } + + return rows.Err() + }); err != nil { + return err + } + + return nil +} + +func init() { + sqlite.RegisterPostMigration(52, post52) +} diff --git a/pkg/sqlite/migrations/52_zip_folder_data_correct.up.sql b/pkg/sqlite/migrations/52_zip_folder_data_correct.up.sql new file mode 100644 index 00000000000..fdf3e9cde73 --- /dev/null +++ b/pkg/sqlite/migrations/52_zip_folder_data_correct.up.sql @@ -0,0 +1 @@ +-- no schema changes \ No newline at end of file From 9f2283b5a1c9c397c0e9fe14efa64c6254d93965 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:33:54 +1100 Subject: [PATCH 2/2] Correct folder hierarchy after folder move --- pkg/file/move.go | 31 +++++++++++++++++++++++++++++++ pkg/file/scan.go | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/pkg/file/move.go b/pkg/file/move.go index 64a83fed645..d591e13b36c 100644 --- a/pkg/file/move.go +++ b/pkg/file/move.go @@ -212,3 +212,34 @@ func (m *Mover) rollback() { } } } + +// correctSubFolderHierarchy sets the path of all contained folders to be relative to the given folder. +// It does not move the folder hierarchy in the filesystem. +func correctSubFolderHierarchy(ctx context.Context, rw models.FolderReaderWriter, folder *models.Folder) error { + folders, err := rw.FindByParentFolderID(ctx, folder.ID) + if err != nil { + return fmt.Errorf("finding contained folders in folder %s: %w", folder.Path, err) + } + + folderPath := folder.Path + + for _, f := range folders { + oldPath := f.Path + folderBasename := filepath.Base(f.Path) + correctPath := filepath.Join(folderPath, folderBasename) + + logger.Debugf("updating folder %s to %s", oldPath, correctPath) + + f.Path = correctPath + if err := rw.Update(ctx, f); err != nil { + return fmt.Errorf("updating folder path %s -> %s: %w", oldPath, f.Path, err) + } + + // recurse + if err := correctSubFolderHierarchy(ctx, rw, f); err != nil { + return err + } + } + + return nil +} diff --git a/pkg/file/scan.go b/pkg/file/scan.go index a0d301e60c2..b6034ae8700 100644 --- a/pkg/file/scan.go +++ b/pkg/file/scan.go @@ -593,6 +593,11 @@ func (s *scanJob) handleFolderRename(ctx context.Context, file scanFile) (*model return nil, fmt.Errorf("updating folder for rename %q: %w", renamedFrom.Path, err) } + // #4146 - correct sub-folders to have the correct path + if err := correctSubFolderHierarchy(ctx, s.Repository.FolderStore, renamedFrom); err != nil { + return nil, fmt.Errorf("correcting sub folder hierarchy for %q: %w", renamedFrom.Path, err) + } + return renamedFrom, nil }