fix(#135): migrate old task envs and tags to data relations during restore

This commit is contained in:
duorameng
2026-06-22 09:44:42 +08:00
parent 05bbb05c37
commit db24fdfa30
+101 -1
View File
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"reflect"
"strings"
"time"
"github.com/engigu/baihu-panel/internal/cache"
@@ -15,6 +16,7 @@ import (
"github.com/engigu/baihu-panel/internal/database"
"github.com/engigu/baihu-panel/internal/models"
"github.com/engigu/baihu-panel/internal/systime"
"github.com/rs/xid"
"gorm.io/gorm"
)
@@ -320,7 +322,7 @@ func (s *BackupService) restoreFromZipFile(tx *gorm.DB, f *zip.File, filename st
case "users.json":
return restoreStreamBatch[models.User](tx, decoder)
case "tasks.json":
return restoreStreamBatch[models.Task](tx, decoder)
return s.restoreTasks(tx, decoder)
case "task_logs.json":
return restoreStreamBatch[models.TaskLog](tx, decoder)
case "envs.json":
@@ -353,6 +355,104 @@ func (s *BackupService) restoreFromZipFile(tx *gorm.DB, f *zip.File, filename st
}
}
func (s *BackupService) restoreTasks(tx *gorm.DB, decoder *json.Decoder) error {
batchSize := 1000
var batch []*models.Task
for decoder.More() {
var m models.Task
if err := decoder.Decode(&m); err != nil {
return err
}
batch = append(batch, &m)
if len(batch) >= batchSize {
if err := s.insertTasksBatch(tx, batch); err != nil {
return err
}
batch = nil // reset
}
}
if len(batch) > 0 {
return s.insertTasksBatch(tx, batch)
}
return nil
}
func (s *BackupService) insertTasksBatch(tx *gorm.DB, batch []*models.Task) error {
if err := tx.Select("*").CreateInBatches(batch, len(batch)).Error; err != nil {
return err
}
// [COMPATIBILITY CODE - TEMPORARY]
// 为旧版备份数据做向下兼容(在旧版本中 tags/envs 还是直接存储在 tasks.json 中)。
// 此段代码将旧数据迁移到新的 data_relations 和 data_storages 中,确保旧备份包能正常恢复。
// 由于新版本的备份中 tasks.json 已不再包含这些字段,未来某次大版本更新后,这段兼容代码将被移除。
for _, t := range batch {
if t.Tags != "" {
tags := strings.Split(t.Tags, ",")
for _, tag := range tags {
tag = strings.TrimSpace(tag)
if tag == "" {
continue
}
var storage models.DataStorage
res := tx.Where("type = ? AND name = ?", constant.RelationTypeTaskTag, tag).Limit(1).Find(&storage)
if res.RowsAffected == 0 {
storage = models.DataStorage{
ID: xid.New().String(),
Type: constant.RelationTypeTaskTag,
Name: tag,
CreatedAt: models.Now(),
UpdatedAt: models.Now(),
}
tx.Create(&storage)
}
var count int64
tx.Model(&models.DataRelation{}).Where("data_id = ? AND relate_id = ? AND type = ?", t.ID, storage.ID, constant.RelationTypeTaskTag).Count(&count)
if count == 0 {
relation := models.DataRelation{
ID: xid.New().String(),
DataID: t.ID,
RelateID: storage.ID,
Type: constant.RelationTypeTaskTag,
CreatedAt: models.Now(),
UpdatedAt: models.Now(),
}
tx.Create(&relation)
}
}
}
if string(t.Envs) != "" {
envs := strings.Split(string(t.Envs), ",")
for _, envID := range envs {
envID = strings.TrimSpace(envID)
if envID == "" {
continue
}
var count int64
tx.Model(&models.DataRelation{}).Where("data_id = ? AND relate_id = ? AND type = ?", t.ID, envID, constant.RelationTypeTaskEnv).Count(&count)
if count == 0 {
relation := models.DataRelation{
ID: xid.New().String(),
DataID: t.ID,
RelateID: envID,
Type: constant.RelationTypeTaskEnv,
CreatedAt: models.Now(),
UpdatedAt: models.Now(),
}
tx.Create(&relation)
}
}
}
}
return nil
}
// insertRecords, restoreFromData 方法已合并入 restoreFromZipFile,此处删除冗余方法
func (s *BackupService) restoreScriptsDir(r *zip.ReadCloser) {