Files
hfb_sys/backend/internal/modules/file/service.go
T
2026-05-29 12:56:25 +08:00

82 lines
1.9 KiB
Go

package file
import (
"context"
"errors"
"mime/multipart"
"net/url"
"strings"
)
var (
ErrDependencyUnavailable = errors.New("dependency unavailable")
ErrInvalidFile = errors.New("invalid file")
)
const maxUploadSize = 10 * 1024 * 1024
var allowedContentTypes = map[string]bool{
"image/jpeg": true,
"image/png": true,
"image/webp": true,
"application/pdf": true,
}
type Service struct {
storage *Storage
}
func NewService(storage *Storage) *Service {
return &Service{storage: storage}
}
func (s *Service) Upload(req uploadRequest) (*UploadDTO, error) {
if s.storage == nil {
return nil, ErrDependencyUnavailable
}
if req.Header == nil || req.Reader == nil || req.Header.Size <= 0 || req.Header.Size > maxUploadSize {
return nil, ErrInvalidFile
}
contentType := req.ContentType
if contentType == "" {
contentType = req.Header.Header.Get("Content-Type")
}
scene := normalizeScene(req.Scene)
if !allowedContentTypes[contentType] || (scene == "chat" && !strings.HasPrefix(contentType, "image/")) {
return nil, ErrInvalidFile
}
key, err := s.storage.Put(req.Context, scene, req.Header, req.Reader, contentType)
if err != nil {
return nil, err
}
fileURL := "/api/files/object?key=" + url.QueryEscape(key)
if scene == "home-banner" || scene == "avatar" {
fileURL = "/api/public/files/object?key=" + url.QueryEscape(key)
}
return &UploadDTO{
ObjectKey: key,
URL: fileURL,
Filename: req.Header.Filename,
ContentType: contentType,
Size: req.Header.Size,
}, nil
}
func normalizeScene(scene string) string {
scene = strings.TrimSpace(strings.ToLower(scene))
switch scene {
case "listing", "handoff", "dispute", "realname", "avatar", "home-banner", "chat":
return scene
default:
return "misc"
}
}
type uploadRequest struct {
Context context.Context
Scene string
Header *multipart.FileHeader
Reader multipart.File
ContentType string
}