Files
jiang13-bbs/backend/handler/moderation.go
freefire 42c395a864 feat: 实时消息与管理端运营能力
新增群聊/私信与公共 WebSocket 总线,站长用户内容档案,并将通知与待审角标改为推送驱动;同步精简管理仪表盘并修复主题换肤 DOM 冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 22:58:16 +08:00

118 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"errors"
"net/http"
"strconv"
"github.com/freefire/jiang13-bbs/middleware"
"github.com/freefire/jiang13-bbs/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ===== 内容审核队列(RequireStaff 基础鉴权,板块范围由 service 按 Actor 隔离) =====
// AdminPendingPosts 待审核帖子分页
func (h *Handlers) AdminPendingPosts(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
posts, total, err := h.Moderation.PendingPosts(middleware.CurrentActor(c), page, 15)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取待审帖子失败"})
return
}
c.JSON(http.StatusOK, gin.H{"posts": posts, "total": total, "page": page})
}
// AdminPendingComments 待审核评论分页
func (h *Handlers) AdminPendingComments(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
comments, total, err := h.Moderation.PendingComments(middleware.CurrentActor(c), page, 15)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取待审评论失败"})
return
}
c.JSON(http.StatusOK, gin.H{"comments": comments, "total": total, "page": page})
}
// AdminPendingCounts 当前操作者可见的待审数量(导航角标)
func (h *Handlers) AdminPendingCounts(c *gin.Context) {
posts, comments := h.Moderation.PendingCounts(middleware.CurrentActor(c))
c.JSON(http.StatusOK, gin.H{"posts": posts, "comments": comments})
}
// AdminApprovePost 通过帖子
func (h *Handlers) AdminApprovePost(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
return
}
actor := middleware.CurrentActor(c)
boardID, err := h.Moderation.ApprovePost(actor, uint(id))
if err != nil {
h.writeModerationError(c, err)
return
}
h.broadcastFeedChanged("post", uint(id), boardID, actor.ID)
h.broadcastModerationChanged()
c.JSON(http.StatusOK, gin.H{"message": "操作成功"})
}
// AdminRejectPost 拒绝帖子
func (h *Handlers) AdminRejectPost(c *gin.Context) {
h.execModeration(c, h.Moderation.RejectPost)
}
// AdminApproveComment 通过评论
func (h *Handlers) AdminApproveComment(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
return
}
actor := middleware.CurrentActor(c)
postID, boardID, err := h.Moderation.ApproveComment(actor, uint(id))
if err != nil {
h.writeModerationError(c, err)
return
}
h.broadcastFeedChanged("comment", postID, boardID, actor.ID)
h.broadcastModerationChanged()
c.JSON(http.StatusOK, gin.H{"message": "操作成功"})
}
// AdminRejectComment 拒绝评论
func (h *Handlers) AdminRejectComment(c *gin.Context) {
h.execModeration(c, h.Moderation.RejectComment)
}
// writeModerationError 映射审核业务错误为 HTTP 响应
func (h *Handlers) writeModerationError(c *gin.Context, err error) {
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
c.JSON(http.StatusNotFound, gin.H{"error": "内容不存在"})
case errors.Is(err, service.ErrModerationForbidden):
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
case errors.Is(err, service.ErrNotPending):
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
default:
c.JSON(http.StatusInternalServerError, gin.H{"error": "操作失败"})
}
}
// execModeration 统一解析 :id 并映射审核业务错误(拒绝等无额外副作用的操作)
func (h *Handlers) execModeration(c *gin.Context, fn func(*service.Actor, uint) error) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
return
}
if err := fn(middleware.CurrentActor(c), uint(id)); err != nil {
h.writeModerationError(c, err)
return
}
h.broadcastModerationChanged()
c.JSON(http.StatusOK, gin.H{"message": "操作成功"})
}