diff --git a/backend/internal/router/admin/package_util.go b/backend/internal/router/admin/package_util.go index d8b3d9d..92a37ee 100644 --- a/backend/internal/router/admin/package_util.go +++ b/backend/internal/router/admin/package_util.go @@ -8,6 +8,9 @@ import ( "os" "path/filepath" "time" + + "verification-platform-backend/internal/database" + "verification-platform-backend/internal/model" ) // MergePatchWithFullPackage 合并补丁包和全量包,生成新的全量包 @@ -70,6 +73,98 @@ func MergePatchWithFullPackage(fullPackagePath, patchPath string, appID, userID return "/" + filepath.ToSlash(newFilePath), fileInfo.Size(), hash, nil } +// RegenerateFullPackage 重新生成指定版本的完整包 +// 用于版本删除后的回退 +func RegenerateFullPackage(versionID uint) error { + var version model.Version + if err := database.DB.First(&version, versionID).Error; err != nil { + return fmt.Errorf("version not found: %v", err) + } + + // 全量包:完整包就是自己 + if version.UpdateType == "full" { + version.FullPackagePath = version.FilePath + version.FullPackageSize = version.FileSize + version.FullPackageHash = version.FileHash + } else if version.UpdateType == "patch" { + // 补丁包:需要找到新的基础版本 + if version.BaseVersionID == nil { + return fmt.Errorf("patch version has no base version") + } + + var baseVersion model.Version + if err := database.DB.First(&baseVersion, *version.BaseVersionID).Error; err != nil { + return fmt.Errorf("base version not found: %v", err) + } + + // 确保基础版本有完整包 + if baseVersion.FullPackagePath == "" { + if err := RegenerateFullPackage(baseVersion.ID); err != nil { + return fmt.Errorf("failed to regenerate base version: %v", err) + } + // 重新加载基础版本 + database.DB.First(&baseVersion, *version.BaseVersionID) + } + + // 合并生成新的完整包 + fullPkgPath, fullPkgSize, fullPkgHash, err := MergePatchWithFullPackage( + baseVersion.FullPackagePath, + version.FilePath, + version.ApplicationID, + 0, // userID 不重要,用于生成文件名 + ) + if err != nil { + return fmt.Errorf("failed to merge: %v", err) + } + + version.FullPackagePath = fullPkgPath + version.FullPackageSize = fullPkgSize + version.FullPackageHash = fullPkgHash + } + + // 保存更新 + return database.DB.Model(&version).Updates(map[string]interface{}{ + "full_package_path": version.FullPackagePath, + "full_package_size": version.FullPackageSize, + "full_package_hash": version.FullPackageHash, + }).Error +} + +// RegenerateDependentVersions 重新生成所有依赖指定版本的后续版本 +// 在删除版本时调用 +func RegenerateDependentVersions(deletedVersionID uint) error { + // 找到所有以被删除版本为基础版本的版本 + var dependentVersions []model.Version + if err := database.DB.Where("base_version_id = ?", deletedVersionID).Find(&dependentVersions).Error; err != nil { + return err + } + + for _, dv := range dependentVersions { + log.Printf("[INFO] Regenerating dependent version %d after deletion of %d\n", dv.ID, deletedVersionID) + + // 重新找到该应用最新的全量包作为新的基础 + var newBaseVersion model.Version + if err := database.DB.Where("application_id = ? AND update_type = ? AND id != ? AND id < ?", + dv.ApplicationID, "full", dv.ID, dv.ID). + Order("id DESC").First(&newBaseVersion).Error; err == nil { + // 更新基础版本ID + dv.BaseVersionID = &newBaseVersion.ID + database.DB.Model(&dv).Update("base_version_id", newBaseVersion.ID) + } + + // 重新生成完整包 + if err := RegenerateFullPackage(dv.ID); err != nil { + log.Printf("[ERROR] Failed to regenerate version %d: %v\n", dv.ID, err) + continue + } + + // 递归处理依赖这个版本的后续版本 + RegenerateDependentVersions(dv.ID) + } + + return nil +} + // extractZip 解压zip文件到指定目录 func extractZip(zipPath, destDir string) error { r, err := zip.OpenReader(zipPath) diff --git a/backend/internal/router/admin/versions.go b/backend/internal/router/admin/versions.go index 029e32c..92e29b2 100644 --- a/backend/internal/router/admin/versions.go +++ b/backend/internal/router/admin/versions.go @@ -571,6 +571,11 @@ func handleBatchDeleteVersions(c *gin.Context) { return } + // 删除后重新生成依赖这些版本的后续版本 + for _, id := range req.IDs { + RegenerateDependentVersions(id) + } + response.Success(c, nil) }