feat(moderation): add manual content review system with three-tier AI moderation
All checks were successful
Build Backend / build (push) Successful in 2m43s
Build Backend / build-docker (push) Successful in 1m22s

Add admin comment moderation endpoints (single and batch) and introduce a three-tier moderation system (pass/review/block) for content flagged by AI. Content with unclear violations is now held for manual review instead of being auto-rejected. Deleted the legacy audit_service.go in favor of the unified hook-based moderation system.
This commit is contained in:
lafay
2026-04-11 04:23:24 +08:00
parent 6af6aaa9d0
commit 1bb82e1e2b
17 changed files with 432 additions and 732 deletions

View File

@@ -11,15 +11,12 @@ import (
// AdminCommentService 管理端评论服务接口
type AdminCommentService interface {
// GetCommentList 获取评论列表(分页、搜索、状态筛选)
GetCommentList(ctx context.Context, page, pageSize int, keyword, postID, authorID, status, startDate, endDate string) ([]dto.AdminCommentListResponse, int64, error)
// GetCommentDetail 获取评论详情
GetCommentDetail(ctx context.Context, commentID string) (*dto.AdminCommentDetailResponse, error)
// DeleteComment 删除评论
DeleteComment(ctx context.Context, commentID string) error
// BatchDeleteComments 批量删除评论
BatchDeleteComments(ctx context.Context, ids []string) (*dto.AdminBatchOperationResponse, error)
// GetCommentsByPostID 获取帖子的评论列表
ModerateComment(ctx context.Context, commentID string, status model.CommentStatus, reason, reviewedBy string) (*dto.AdminCommentDetailResponse, error)
BatchModerateComments(ctx context.Context, ids []string, status model.CommentStatus, reviewedBy string) (*dto.AdminBatchOperationResponse, error)
GetCommentsByPostID(ctx context.Context, postID string, page, pageSize int) ([]dto.AdminCommentListResponse, int64, error)
}
@@ -103,6 +100,54 @@ func (s *adminCommentServiceImpl) BatchDeleteComments(ctx context.Context, ids [
}, nil
}
func (s *adminCommentServiceImpl) ModerateComment(ctx context.Context, commentID string, status model.CommentStatus, reason, reviewedBy string) (*dto.AdminCommentDetailResponse, error) {
_, err := s.commentRepo.GetAdminCommentByID(commentID)
if err != nil {
return nil, err
}
if err := s.commentRepo.UpdateModerationStatus(commentID, status, reason, reviewedBy); err != nil {
return nil, err
}
comment, err := s.commentRepo.GetAdminCommentByID(commentID)
if err != nil {
return nil, err
}
return s.convertCommentToAdminDetailResponse(comment), nil
}
func (s *adminCommentServiceImpl) BatchModerateComments(ctx context.Context, ids []string, status model.CommentStatus, reviewedBy string) (*dto.AdminBatchOperationResponse, error) {
var failedIDs []string
for _, id := range ids {
if err := s.commentRepo.UpdateModerationStatus(id, status, "", reviewedBy); err != nil {
failedIDs = append(failedIDs, id)
}
}
if len(failedIDs) == 0 {
return &dto.AdminBatchOperationResponse{
Success: true,
Message: "批量审核成功",
}, nil
}
if len(failedIDs) == len(ids) {
return &dto.AdminBatchOperationResponse{
Success: false,
Message: "批量审核失败",
Failed: failedIDs,
}, nil
}
return &dto.AdminBatchOperationResponse{
Success: true,
Message: "部分评论审核成功",
Failed: failedIDs,
}, nil
}
// GetCommentsByPostID 获取帖子的评论列表
func (s *adminCommentServiceImpl) GetCommentsByPostID(ctx context.Context, postID string, page, pageSize int) ([]dto.AdminCommentListResponse, int64, error) {
comments, total, err := s.commentRepo.GetCommentsByPostIDForAdmin(postID, page, pageSize)
@@ -160,6 +205,9 @@ func (s *adminCommentServiceImpl) convertCommentToAdminListResponse(comment *mod
Content: comment.Content,
Images: images,
Status: string(comment.Status),
RejectReason: comment.RejectReason,
ReviewedAt: dto.FormatTimePointer(comment.ReviewedAt),
ReviewedBy: comment.ReviewedBy,
LikesCount: comment.LikesCount,
RepliesCount: comment.RepliesCount,
CreatedAt: comment.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
@@ -211,6 +259,9 @@ func (s *adminCommentServiceImpl) convertCommentToAdminDetailResponse(comment *m
Content: comment.Content,
Images: images,
Status: string(comment.Status),
RejectReason: comment.RejectReason,
ReviewedAt: dto.FormatTimePointer(comment.ReviewedAt),
ReviewedBy: comment.ReviewedBy,
LikesCount: comment.LikesCount,
RepliesCount: comment.RepliesCount,
CreatedAt: comment.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),