Files
backend/internal/handler/comment_handler.go

254 lines
6.4 KiB
Go
Raw Normal View History

package handler
import (
"encoding/json"
"errors"
"strconv"
"github.com/gin-gonic/gin"
"carrot_bbs/internal/dto"
"carrot_bbs/internal/pkg/response"
"carrot_bbs/internal/service"
)
// CommentHandler 评论处理器
type CommentHandler struct {
commentService *service.CommentService
}
// NewCommentHandler 创建评论处理器
func NewCommentHandler(commentService *service.CommentService) *CommentHandler {
return &CommentHandler{
commentService: commentService,
}
}
// Create 创建评论
func (h *CommentHandler) Create(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
response.Unauthorized(c, "")
return
}
type CreateRequest struct {
PostID string `json:"post_id" binding:"required"`
Content string `json:"content"` // 内容可选,允许只发图片
ParentID *string `json:"parent_id"`
Images []string `json:"images"` // 图片URL列表
}
var req CreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
// 验证:评论必须有内容或图片
if req.Content == "" && len(req.Images) == 0 {
response.BadRequest(c, "评论内容或图片不能同时为空")
return
}
// 将图片列表转换为JSON字符串
var imagesJSON string
if len(req.Images) > 0 {
imagesBytes, _ := json.Marshal(req.Images)
imagesJSON = string(imagesBytes)
}
comment, err := h.commentService.Create(c.Request.Context(), req.PostID, userID, req.Content, req.ParentID, imagesJSON, req.Images)
if err != nil {
var moderationErr *service.CommentModerationRejectedError
if errors.As(err, &moderationErr) {
response.BadRequest(c, moderationErr.UserMessage())
return
}
response.InternalServerError(c, "failed to create comment")
return
}
response.Success(c, dto.ConvertCommentToResponse(comment, false))
}
// GetByID 获取单条评论详情
func (h *CommentHandler) GetByID(c *gin.Context) {
userID := c.GetString("user_id")
id := c.Param("id")
comment, err := h.commentService.GetByID(c.Request.Context(), id)
if err != nil {
response.NotFound(c, "comment not found")
return
}
resp := dto.ConvertCommentToResponse(comment, h.commentService.IsLiked(c.Request.Context(), id, userID))
response.Success(c, resp)
}
// GetByPostID 获取帖子评论
func (h *CommentHandler) GetByPostID(c *gin.Context) {
userID := c.GetString("user_id")
postID := c.Param("id")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
comments, total, err := h.commentService.GetByPostID(c.Request.Context(), postID, page, pageSize)
if err != nil {
response.InternalServerError(c, "failed to get comments")
return
}
// 转换为响应结构,检查每个评论的点赞状态
commentResponses := dto.ConvertCommentsToResponseWithUser(comments, userID, h.commentService)
response.Paginated(c, commentResponses, total, page, pageSize)
}
// GetReplies 获取回复
func (h *CommentHandler) GetReplies(c *gin.Context) {
userID := c.GetString("user_id")
parentID := c.Param("id")
comments, err := h.commentService.GetReplies(c.Request.Context(), parentID)
if err != nil {
response.InternalServerError(c, "failed to get replies")
return
}
// 转换为响应结构,检查每个回复的点赞状态
commentResponses := dto.ConvertCommentsToResponseWithUser(comments, userID, h.commentService)
response.Success(c, commentResponses)
}
// GetRepliesByRootID 根据根评论ID分页获取回复扁平化
func (h *CommentHandler) GetRepliesByRootID(c *gin.Context) {
userID := c.GetString("user_id")
rootID := c.Param("id")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
replies, total, err := h.commentService.GetRepliesByRootID(c.Request.Context(), rootID, page, pageSize)
if err != nil {
response.InternalServerError(c, "failed to get replies")
return
}
// 转换为响应结构,检查每个回复的点赞状态
replyResponses := dto.ConvertCommentsToResponseWithUser(replies, userID, h.commentService)
response.Paginated(c, replyResponses, total, page, pageSize)
}
// Update 更新评论
func (h *CommentHandler) Update(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
response.Unauthorized(c, "")
return
}
id := c.Param("id")
comment, err := h.commentService.GetByID(c.Request.Context(), id)
if err != nil {
response.NotFound(c, "comment not found")
return
}
if comment.UserID != userID {
response.Forbidden(c, "cannot update others' comment")
return
}
type UpdateRequest struct {
Content string `json:"content" binding:"required"`
}
var req UpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
comment.Content = req.Content
err = h.commentService.Update(c.Request.Context(), comment)
if err != nil {
response.InternalServerError(c, "failed to update comment")
return
}
response.Success(c, dto.ConvertCommentToResponse(comment, false))
}
// Delete 删除评论
func (h *CommentHandler) Delete(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
response.Unauthorized(c, "")
return
}
id := c.Param("id")
comment, err := h.commentService.GetByID(c.Request.Context(), id)
if err != nil {
response.NotFound(c, "comment not found")
return
}
if comment.UserID != userID {
response.Forbidden(c, "cannot delete others' comment")
return
}
err = h.commentService.Delete(c.Request.Context(), id)
if err != nil {
response.InternalServerError(c, "failed to delete comment")
return
}
response.SuccessWithMessage(c, "comment deleted", nil)
}
// Like 点赞评论
func (h *CommentHandler) Like(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
response.Unauthorized(c, "")
return
}
id := c.Param("id")
err := h.commentService.Like(c.Request.Context(), id, userID)
if err != nil {
response.InternalServerError(c, "failed to like comment")
return
}
response.SuccessWithMessage(c, "liked", nil)
}
// Unlike 取消点赞评论
func (h *CommentHandler) Unlike(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
response.Unauthorized(c, "")
return
}
id := c.Param("id")
err := h.commentService.Unlike(c.Request.Context(), id, userID)
if err != nil {
response.InternalServerError(c, "failed to unlike comment")
return
}
response.SuccessWithMessage(c, "unliked", nil)
}