Files
0451meishi/backend/internal/handlers/upload.go
2026-01-15 11:37:22 +08:00

83 lines
1.8 KiB
Go

package handlers
import (
"crypto/rand"
"encoding/hex"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"0451meishiditu/backend/internal/resp"
"github.com/gin-gonic/gin"
)
func (h *Handlers) Upload(c *gin.Context) {
url, ok := h.handleUpload(c)
if !ok {
return
}
resp.OK(c, gin.H{"url": url})
}
// UserUpload allows logged-in users to upload images for reviews.
func (h *Handlers) UserUpload(c *gin.Context) {
url, ok := h.handleUpload(c)
if !ok {
return
}
resp.OK(c, gin.H{"url": url})
}
func (h *Handlers) handleUpload(c *gin.Context) (string, bool) {
maxMB := h.cfg.MaxUploadMB
if maxMB <= 0 {
maxMB = 10
}
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxMB*1024*1024)
file, err := c.FormFile("file")
if err != nil {
resp.Fail(c, http.StatusBadRequest, "missing file")
return "", false
}
ext := strings.ToLower(filepath.Ext(file.Filename))
switch ext {
case ".jpg", ".jpeg", ".png", ".webp", ".gif":
default:
resp.Fail(c, http.StatusBadRequest, "unsupported file type")
return "", false
}
now := time.Now()
dir := filepath.Join(h.cfg.UploadDir, strconv.Itoa(now.Year()), now.Format("01"))
if err := os.MkdirAll(dir, 0o755); err != nil {
resp.Fail(c, http.StatusInternalServerError, "mkdir failed")
return "", false
}
name := randomHex(16) + ext
dst := filepath.Join(dir, name)
if err := c.SaveUploadedFile(file, dst); err != nil {
resp.Fail(c, http.StatusInternalServerError, "save failed")
return "", false
}
rel := strings.TrimPrefix(filepath.ToSlash(dst), ".")
if !strings.HasPrefix(rel, "/") {
rel = "/" + rel
}
url := strings.TrimRight(h.cfg.PublicBaseURL, "/") + rel
return url, true
}
func randomHex(n int) string {
b := make([]byte, n)
_, _ = rand.Read(b)
return hex.EncodeToString(b)
}