package service import ( "context" "fmt" "io" "os" "path/filepath" "strings" "github.com/cloudprint/cloudprint-backend/internal/model" "github.com/cloudprint/cloudprint-backend/internal/repository" "github.com/cloudprint/cloudprint-backend/pkg/upload" ) type FileService struct { fileRepo *repository.FileRepository uploader *upload.FileUploader uploadDir string } func NewFileService(fileRepo *repository.FileRepository, uploader *upload.FileUploader, uploadDir string) *FileService { return &FileService{ fileRepo: fileRepo, uploader: uploader, uploadDir: uploadDir, } } func (s *FileService) Upload(ctx context.Context, fileName string, fileType string, uploaderType string, uploaderID int32, data []byte) (*model.File, error) { if !s.uploader.ValidateFileType(fileName) { return nil, fmt.Errorf("file type not allowed") } // Save file filePath := s.uploader.GenerateFilePath(fileName) fullPath := s.uploader.GetFilePath(filePath) if err := os.WriteFile(fullPath, data, 0644); err != nil { return nil, fmt.Errorf("failed to write file: %w", err) } // Create file record file := &model.File{ FileName: fileName, FilePath: filePath, FileType: strings.ToLower(fileType), FileSize: int64(len(data)), UploaderType: uploaderType, UploaderID: uploaderID, } if err := s.fileRepo.Create(ctx, file); err != nil { // Clean up file on error os.Remove(fullPath) return nil, fmt.Errorf("failed to create file record: %w", err) } return file, nil } func (s *FileService) GetFile(ctx context.Context, fileID int32) (*model.File, error) { return s.fileRepo.GetByID(ctx, fileID) } func (s *FileService) GetFileReader(ctx context.Context, file *model.File) (io.ReadCloser, error) { fullPath := filepath.Join(s.uploadDir, file.FilePath) return os.Open(fullPath) } func (s *FileService) DeleteFile(ctx context.Context, fileID int32, uploaderType string, uploaderID int32) error { file, err := s.fileRepo.GetByID(ctx, fileID) if err != nil || file == nil { return fmt.Errorf("file not found") } // Verify ownership if file.UploaderType != uploaderType || file.UploaderID != uploaderID { return fmt.Errorf("unauthorized") } // Delete physical file fullPath := s.uploader.GetFilePath(file.FilePath) os.Remove(fullPath) // Delete record return s.fileRepo.Delete(ctx, fileID) } func (s *FileService) GetFileList(ctx context.Context, uploaderType string, uploaderID int32, page, pageSize int) ([]*model.File, int64, error) { return s.fileRepo.GetListByUploader(ctx, uploaderType, uploaderID, page, pageSize) } func (s *FileService) AddWatermark(ctx context.Context, fileID int32, text string, opacity float32, position int, fontSize int) (*model.File, error) { file, err := s.fileRepo.GetByID(ctx, fileID) if err != nil || file == nil { return nil, fmt.Errorf("file not found") } // In production, use a PDF library to add watermark // For now, just return the original file // TODO: Implement actual watermark using pdf-lib or similar return file, nil }