feat: 类型帖互动、积分经济与发帖体验

补齐问答采纳/重开、投票匿名与有票禁编、悬赏过期退回、抽奖回帖开奖,并接入积分账本与发帖附件可见性。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 03:17:07 +08:00
parent 1ef3d8e299
commit b9ba8cb8c9
58 changed files with 6913 additions and 506 deletions

View File

@@ -49,6 +49,46 @@ func (h *Handlers) UploadAvatar(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"url": att.URL, "attachment": att})
}
// UploadImage 上传帖子插图(multipart 字段 file:JPEG / PNG / WebP)
func (h *Handlers) UploadImage(c *gin.Context) {
claims := middleware.CurrentUser(c)
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, service.ImageMaxBytes+4096)
fh, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "图片过大(不能超过 5MB)或格式不正确"})
return
}
if fh.Size > service.ImageMaxBytes {
c.JSON(http.StatusBadRequest, gin.H{"error": "图片不能超过 5MB"})
return
}
f, err := fh.Open()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "读取图片失败"})
return
}
defer f.Close()
data, err := io.ReadAll(io.LimitReader(f, service.ImageMaxBytes+1))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "读取图片失败"})
return
}
if len(data) > service.ImageMaxBytes {
c.JSON(http.StatusBadRequest, gin.H{"error": "图片不能超过 5MB"})
return
}
att, err := h.Upload.SaveImage(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"`