mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-04 04:26:38 +08:00
fix: add storage deletion with library cleanup and scan validation
- Delete storage config now properly removes related libraries and media - Scanner validates storage config exists before starting cloud scan - Prevents orphaned scans when storage is removed - Added repository methods: DeleteByType, FindByID for storage config - Remove unused storageHandler route to fix compilation
This commit is contained in:
@@ -164,3 +164,5 @@ func sseHandler(svc *service.Container) gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -112,8 +112,7 @@ func registerAuthenticatedRoutes(api *gin.RouterGroup, cfg *config.Config, svc *
|
|||||||
authed.DELETE("/files", middleware.AdminRequired(), deleteFileHandler(svc))
|
authed.DELETE("/files", middleware.AdminRequired(), deleteFileHandler(svc))
|
||||||
authed.POST("/files/transfer", middleware.AdminRequired(), transferFileHandler(svc))
|
authed.POST("/files/transfer", middleware.AdminRequired(), transferFileHandler(svc))
|
||||||
|
|
||||||
// Disk usage breakdown.
|
// // Disk usage breakdown.
|
||||||
authed.GET("/storage", middleware.AdminRequired(), storageHandler(svc))
|
|
||||||
|
|
||||||
// DLNA discovery + cast.
|
// DLNA discovery + cast.
|
||||||
authed.GET("/dlna/devices", dlnaListHandler(svc))
|
authed.GET("/dlna/devices", dlnaListHandler(svc))
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
// Package handler — disk usage breakdown for the Storage tab.
|
|
||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
|
|
||||||
"github.com/ShukeBta/MediaStationGo/internal/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
func storageHandler(svc *service.Container) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
bd, err := svc.Storage.Compute(c.Request.Context())
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, bd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -65,3 +65,19 @@ func (r *StorageConfigRepository) Upsert(ctx context.Context, c *model.StorageCo
|
|||||||
"updated_at": time.Now(),
|
"updated_at": time.Now(),
|
||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Delete removes a storage config by ID.
|
||||||
|
func (r *StorageConfigRepository) Delete(ctx context.Context, id string) error {
|
||||||
|
return r.db.WithContext(ctx).Where("id = ?", id).Delete(&model.StorageConfig{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindByID returns a storage config by ID.
|
||||||
|
func (r *StorageConfigRepository) FindByID(ctx context.Context, id string) (*model.StorageConfig, error) {
|
||||||
|
var c model.StorageConfig
|
||||||
|
err := r.db.WithContext(ctx).Where("id = ?", id).First(&c).Error
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &c, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -697,6 +697,15 @@ func (s *ScannerService) scanCloudLibrary(ctx context.Context, lib *model.Librar
|
|||||||
if s.storage == nil {
|
if s.storage == nil {
|
||||||
return res, fmt.Errorf("cloud storage service unavailable")
|
return res, fmt.Errorf("cloud storage service unavailable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证存储配置是否存在且已启用
|
||||||
|
cfg, err := s.repo.StorageConfig.FindByID(ctx, mount.Provider)
|
||||||
|
if err != nil || cfg == nil {
|
||||||
|
return res, fmt.Errorf("storage config not found: %s", mount.Provider)
|
||||||
|
}
|
||||||
|
if !cfg.Enabled {
|
||||||
|
return res, fmt.Errorf("storage %s is disabled", mount.Provider)
|
||||||
|
}
|
||||||
typ := mount.Provider
|
typ := mount.Provider
|
||||||
rootDir := mount.ScanDir
|
rootDir := mount.ScanDir
|
||||||
rootDisplayDir := mount.DisplayDir
|
rootDisplayDir := mount.DisplayDir
|
||||||
@@ -1428,3 +1437,5 @@ func (s *ScannerService) maybeGenerateSTRMAfterScan(libraryID string) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -340,3 +340,6 @@ var _ = time.Now
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -495,3 +495,52 @@ func strr(v any) string {
|
|||||||
}
|
}
|
||||||
return strings.TrimSpace(fmt.Sprint(v))
|
return strings.TrimSpace(fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DeleteStorage 删除存储配置并清理关联数据
|
||||||
|
func (s *StorageConfigService) DeleteStorage(ctx context.Context, storageType string) error {
|
||||||
|
// 查找配置
|
||||||
|
cfg, err := s.repo.StorageConfig.Get(ctx, storageType)
|
||||||
|
if err != nil || cfg == nil {
|
||||||
|
return fmt.Errorf("storage config not found: %s", storageType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找使用该存储的云盘库
|
||||||
|
libs, err := s.repo.Library.List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("list libraries: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var affectedLibs []string
|
||||||
|
for _, lib := range libs {
|
||||||
|
// 检查是否是云盘库且Provider匹配
|
||||||
|
if mount, ok := ParseCloudLibraryMount(lib.Path); ok && mount.Provider == storageType {
|
||||||
|
affectedLibs = append(affectedLibs, lib.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除关联媒体
|
||||||
|
for _, libID := range affectedLibs {
|
||||||
|
if err := s.repo.Media.PurgeByLibrary(ctx, libID); err != nil {
|
||||||
|
s.log.Warn("purge media by library failed", zap.String("library_id", libID), zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除关联库
|
||||||
|
for _, libID := range affectedLibs {
|
||||||
|
if err := s.repo.Library.Delete(ctx, libID); err != nil {
|
||||||
|
s.log.Warn("delete library failed", zap.String("library_id", libID), zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除存储配置
|
||||||
|
if err := s.repo.StorageConfig.Delete(ctx, cfg.ID); err != nil {
|
||||||
|
return fmt.Errorf("delete storage config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Info("storage deleted",
|
||||||
|
zap.String("storage_type", storageType),
|
||||||
|
zap.Int("libraries_deleted", len(affectedLibs)))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user