package handler import ( "errors" "io" "net/http" "strconv" "github.com/freefire/jiang13-bbs/middleware" "github.com/freefire/jiang13-bbs/service" "github.com/gin-gonic/gin" ) // UploadAvatar 上传裁剪后的头像(multipart 字段 file,内容必须是 WebP) func (h *Handlers) UploadAvatar(c *gin.Context) { claims := middleware.CurrentUser(c) // 限制请求体:以裁剪后文件为依据,允许少量 multipart 边界开销 c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, service.AvatarMaxBytes+4096) fh, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "图片过大(裁剪后不能超过 2MB)或格式不正确"}) return } if fh.Size > service.AvatarMaxBytes { c.JSON(http.StatusBadRequest, gin.H{"error": "裁剪后的图片不能超过 2MB"}) return } f, err := fh.Open() if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "读取图片失败"}) return } defer f.Close() // fh.Size 已受 MaxBytesReader 约束;读取时二次防御 data, err := io.ReadAll(io.LimitReader(f, service.AvatarMaxBytes+1)) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "读取图片失败"}) return } att, err := h.Upload.SaveAvatar(claims.ID, data) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"url": att.URL, "attachment": att}) } // UseAvatarRequest 选用历史头像请求 type UseAvatarRequest struct { URL string `json:"url"` } // UseAvatar 选用本人历史上传的头像 func (h *Handlers) UseAvatar(c *gin.Context) { claims := middleware.CurrentUser(c) var req UseAvatarRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数格式错误"}) return } if err := h.Upload.UseAvatar(claims.ID, req.URL); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"url": req.URL}) } // MyMedia 媒体库:本人上传的全部图片(头像、帖子插图等) func (h *Handlers) MyMedia(c *gin.Context) { claims := middleware.CurrentUser(c) list, err := h.Upload.ListMedia(claims.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"attachments": list}) } // DeleteAttachment 彻底删除本人附件(DB + 物理文件) func (h *Handlers) DeleteAttachment(c *gin.Context) { claims := middleware.CurrentUser(c) id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的附件 ID"}) return } if err := h.Upload.DeleteAttachment(claims.ID, uint(id)); err != nil { if errors.Is(err, service.ErrAttachmentInUse) { c.JSON(http.StatusConflict, gin.H{"error": err.Error()}) return } c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }