fix(canvas): 资源引用 - 校验递归素材并修复断链

This commit is contained in:
ddCat
2026-09-24 00:04:43 +08:00
parent 5bbd208bef
commit 117fa7d70b
24 changed files with 697 additions and 218 deletions

View File

@@ -119,6 +119,10 @@ func (r *Repository) ResourceStorageReferenceCount(resource *model.Resource, exc
}
func (r *Repository) ResourceReferenceSnapshot(userID string, excludingAssetID string, resourceIDs []string) (ResourceReferenceSnapshot, error) {
return r.ResourceReferenceSnapshotExcludingAssets(userID, []string{excludingAssetID}, resourceIDs)
}
func (r *Repository) ResourceReferenceSnapshotExcludingAssets(userID string, excludingAssetIDs []string, resourceIDs []string) (ResourceReferenceSnapshot, error) {
snapshot := ResourceReferenceSnapshot{Documents: []ResourceReferenceDocument{}, Direct: []ResourceDirectReference{}}
if len(resourceIDs) == 0 {
return snapshot, nil
@@ -154,7 +158,10 @@ func (r *Repository) ResourceReferenceSnapshot(userID string, excludingAssetID s
snapshot.Documents = append(snapshot.Documents, ResourceReferenceDocument{Kind: "工具", ID: strconv.FormatInt(tool.ID, 10), Title: tool.Label, PrimaryJSON: string(payload)})
}
var assets []model.Asset
assetQuery := r.db.Where("user_id = ? AND id <> ?", userID, excludingAssetID)
assetQuery := r.db.Where("user_id = ?", userID)
if len(excludingAssetIDs) > 0 {
assetQuery = assetQuery.Where("id NOT IN ?", excludingAssetIDs)
}
if err := assetQuery.Find(&assets).Error; err != nil {
return snapshot, err
}
@@ -240,7 +247,10 @@ func (r *Repository) ResourceReferenceSnapshot(userID string, excludingAssetID s
versionQuery := r.db.Table("asset_versions").
Select("asset_versions.id, assets.title, asset_versions.definition_json AS primary_json").
Joins("JOIN assets ON assets.id = asset_versions.asset_id").
Where("assets.user_id = ? AND assets.id <> ?", userID, excludingAssetID)
Where("assets.user_id = ?", userID)
if len(excludingAssetIDs) > 0 {
versionQuery = versionQuery.Where("assets.id NOT IN ?", excludingAssetIDs)
}
if err := versionQuery.Scan(&versions).Error; err != nil {
return snapshot, err
}
@@ -292,12 +302,15 @@ func (r *Repository) ResourceReferenceSnapshot(userID string, excludingAssetID s
ResourceID string
}
var representations []joinedRepresentation
if err := r.db.Table("asset_representations").
representationQuery := r.db.Table("asset_representations").
Select("asset_representations.id, assets.title, asset_representations.resource_id").
Joins("JOIN asset_versions ON asset_versions.id = asset_representations.asset_version_id").
Joins("JOIN assets ON assets.id = asset_versions.asset_id").
Where("assets.user_id = ? AND assets.id <> ? AND asset_representations.resource_id IN ?", userID, excludingAssetID, resourceIDs).
Scan(&representations).Error; err != nil {
Where("assets.user_id = ? AND asset_representations.resource_id IN ?", userID, resourceIDs)
if len(excludingAssetIDs) > 0 {
representationQuery = representationQuery.Where("assets.id NOT IN ?", excludingAssetIDs)
}
if err := representationQuery.Scan(&representations).Error; err != nil {
return snapshot, err
}
for _, representation := range representations {
@@ -403,23 +416,9 @@ func (r *Repository) DeleteAssetsAndResources(userID string, assetIDs []string,
if len(assetIDs) == 0 || len(ownedAssets) != len(assetIDs) {
return gorm.ErrRecordNotFound
}
if deleteReferencedResources {
if len(resourceIDs) > 0 {
// 与历史快照写入串行化,避免清除索引后又插入外键引用。
if r.Dialect() == "postgres" {
var resources []model.Resource
if err := tx.Select("id").Where("id IN ?", resourceIDs).Order("id").Clauses(clause.Locking{Strength: "UPDATE"}).Find(&resources).Error; err != nil {
return err
}
}
if err := tx.Where("resource_id IN ?", resourceIDs).Delete(&model.CanvasSnapshotResource{}).Error; err != nil {
return err
}
}
} else {
if err := New(tx).RequireNoCanvasHistoryReferences(resourceIDs); err != nil {
return err
}
// Explicit deletion and archive expiry must never invalidate a snapshot.
if err := New(tx).RequireNoCanvasHistoryReferences(resourceIDs); err != nil {
return err
}
versionIDs := tx.Model(&model.AssetVersion{}).Select("id").Where("asset_id IN ?", assetIDs)
if err := tx.Where("asset_version_id IN (?)", versionIDs).Delete(&model.ShotAssetReference{}).Error; err != nil {