- 新增站长/超级管理员/管理员/板块管理员四级角色体系 - 实现实时权限快照加载与细粒度权限校验 - 新增内容审核队列与前后端页面 - 重构用户权限管理与站点管理逻辑 - 新增评论/帖子审核状态与通知推送 - 优化前端权限控制与角色徽章展示 - 修正数据库迁移与默认值问题
114 lines
3.9 KiB
Go
114 lines
3.9 KiB
Go
package handler
|
||
|
||
import (
|
||
"errors"
|
||
"net/http"
|
||
"strconv"
|
||
|
||
"github.com/freefire/jiang13-bbs/middleware"
|
||
"github.com/freefire/jiang13-bbs/model"
|
||
"github.com/freefire/jiang13-bbs/service"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// PostComments 获取帖子评论树(楼层分页:主评论算楼层,每楼附带全部子回复,时间正序)
|
||
func (h *Handlers) PostComments(c *gin.Context) {
|
||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的帖子 ID"})
|
||
return
|
||
}
|
||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
||
|
||
// 待审/被拒帖子的评论不对公众开放
|
||
var viewerID uint
|
||
var loadActor func() *service.Actor
|
||
if claims := middleware.CurrentUser(c); claims != nil {
|
||
viewerID = claims.ID
|
||
loadActor = h.actorLoader(claims.ID)
|
||
}
|
||
if err := h.Post.EnsurePostVisible(uint(id), viewerID, loadActor); err != nil {
|
||
c.JSON(http.StatusNotFound, gin.H{"error": "帖子不存在"})
|
||
return
|
||
}
|
||
|
||
comments, floors, totalComments, err := h.Comment.ListFloorPaged(uint(id), page, size)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"comments": comments,
|
||
"total": floors, // 楼层数(主评论数)→ 前端分页与楼层号计算
|
||
"total_comments": totalComments, // 全部评论数(含回复)→ 展示徽标
|
||
"page": page,
|
||
"size": size,
|
||
})
|
||
}
|
||
|
||
// CreateCommentRequest 评论请求
|
||
type CreateCommentRequest struct {
|
||
Content string `json:"content" binding:"required,min=1"`
|
||
ParentID *uint `json:"parent_id"` // 非空 = 回复该评论(发为其子评论)
|
||
}
|
||
|
||
// CreateComment 创建评论(主评论或子回复)
|
||
func (h *Handlers) CreateComment(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
|
||
}
|
||
var req CreateCommentRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
// 管理团队成员评论免审;普通用户评论进入待审核队列,审核通过时才发业务通知
|
||
status := model.ContentStatusPending
|
||
if model.IsStaff(model.Role(claims.Role)) {
|
||
status = model.ContentStatusPublished
|
||
}
|
||
comment, parent, err := h.Comment.Create(claims.ID, uint(id), req.Content, req.ParentID, status)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
if comment.Status == model.ContentStatusPublished {
|
||
if parent == nil {
|
||
// 主评论:通知帖子作者(排除自己评论自己的帖子)
|
||
if authorID, e := h.Post.GetAuthorID(uint(id)); e == nil {
|
||
h.Notification.Create(authorID, claims.ID, model.NotificationTypeComment, uint(id), comment.ID, req.Content)
|
||
}
|
||
} else {
|
||
// 子回复:通知父评论作者(Notification.Create 内部排除自我通知)
|
||
h.Notification.Create(parent.UserID, claims.ID, model.NotificationTypeReply, uint(id), comment.ID, req.Content)
|
||
}
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"comment": comment})
|
||
}
|
||
|
||
// DeleteComment 删除评论
|
||
func (h *Handlers) DeleteComment(c *gin.Context) {
|
||
claims := middleware.CurrentUser(c)
|
||
cid, err := strconv.ParseUint(c.Param("cid"), 10, 64)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的评论 ID"})
|
||
return
|
||
}
|
||
if err := h.Comment.Delete(h.loadActor(claims.ID), uint(cid), claims.ID); err != nil {
|
||
switch {
|
||
case errors.Is(err, service.ErrCommentNotFound):
|
||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||
case errors.Is(err, service.ErrCommentForbidden):
|
||
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
||
default:
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
}
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"message": "已删除"})
|
||
}
|