package service import ( "fmt" "os" "path/filepath" "filestoragesystem/internal/config" "filestoragesystem/internal/model" "filestoragesystem/internal/repository" "filestoragesystem/pkg/apperr" ) // ProjectService 项目服务 type ProjectService struct { cfg *config.Config projectRepo *repository.ProjectRepo fileRepo *repository.FileRepo settingRepo *repository.SettingRepo opLogRepo *repository.OpLogRepo webhookSvc *WebhookService } // Create 创建项目 func (s *ProjectService) Create(userID uint, name, description string, storageLimit int64) (*model.Project, error) { if name == "" || len(name) > 100 { return nil, fmt.Errorf("项目名称不能为空且不超过100字符") } if _, err := s.projectRepo.FindByName(userID, name); err == nil { return nil, apperr.ErrProjectExists } if storageLimit <= 0 { storageLimit = 5368709120 // 5GB if v, err := s.settingRepo.GetValue("default_project_limit"); err == nil { var n int64 if _, e := fmt.Sscanf(v, "%d", &n); e == nil && n > 0 { storageLimit = n } } } p := &model.Project{ UserID: userID, Name: name, Description: description, StorageLimit: storageLimit, Status: 1, } if err := s.projectRepo.Create(p); err != nil { return nil, err } return p, nil } // List 项目列表,all=true时管理员查看全部 func (s *ProjectService) List(userID uint, keyword string, all bool, page, pageSize int) ([]model.Project, int64, error) { return s.projectRepo.List(userID, keyword, all, page, pageSize) } // Get 项目详情(所有者或管理员) func (s *ProjectService) Get(userID uint, id uint, isAdmin bool) (*model.Project, error) { p, err := s.projectRepo.FindByID(id) if err != nil { return nil, apperr.ErrNotFound } if !isAdmin && p.UserID != userID { return nil, apperr.ErrForbidden } return p, nil } // Update 更新项目 func (s *ProjectService) Update(userID uint, id uint, isAdmin bool, name, description string, storageLimit int64) (*model.Project, error) { p, err := s.Get(userID, id, isAdmin) if err != nil { return nil, err } if name != "" && name != p.Name { if _, err := s.projectRepo.FindByName(userID, name); err == nil { return nil, apperr.ErrProjectExists } p.Name = name } if description != "" { p.Description = description } if storageLimit > 0 { p.StorageLimit = storageLimit } if err := s.projectRepo.Update(p); err != nil { return nil, err } return p, nil } // Delete 删除项目及其全部文件(硬删除) func (s *ProjectService) Delete(userID uint, id uint, isAdmin bool) error { if _, err := s.Get(userID, id, isAdmin); err != nil { return err } // 删除物理文件 files, _ := s.fileRepo.ListByProject(id) seen := make(map[string]bool) for _, f := range files { if f.StoredPath != "" && !seen[f.StoredPath] { seen[f.StoredPath] = true _ = os.Remove(filepath.Join(s.cfg.Storage.Root, f.StoredPath)) } } _ = s.fileRepo.DB.Exec("DELETE FROM files WHERE project_id = ?", id).Error _ = s.fileRepo.DB.Exec("DELETE FROM temp_links WHERE file_id IN (SELECT id FROM files WHERE project_id = ?)", id).Error return s.projectRepo.Delete(id) }