106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
|
|
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
|
||
|
|
}
|