package handlers import ( "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/novablog/server/internal/database" "github.com/novablog/server/internal/middleware" "github.com/novablog/server/internal/models" "gorm.io/gorm" ) // CommentHandler 评论处理器 type CommentHandler struct{} // NewCommentHandler 创建评论处理器 func NewCommentHandler() *CommentHandler { return &CommentHandler{} } // CreateCommentRequest 创建评论请求 type CreateCommentRequest struct { PostID string `json:"post_id" binding:"required"` ParentID *uint `json:"parent_id"` Content string `json:"content" binding:"required,min=1,max=2000"` } // CreateComment 创建评论 func (h *CommentHandler) CreateComment(c *gin.Context) { userID, _ := middleware.GetUserID(c) var req CreateCommentRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } comment := models.Comment{ PostID: req.PostID, UserID: userID, ParentID: req.ParentID, Content: req.Content, Status: "approved", // 默认直接通过,可改为 pending 需审核 } if err := database.DB.Create(&comment).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create comment"}) return } // 加载用户信息 database.DB.Preload("User").First(&comment, comment.ID) c.JSON(http.StatusCreated, comment) } // GetComments 获取文章评论列表 func (h *CommentHandler) GetComments(c *gin.Context) { postID := c.Query("post_id") if postID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "post_id is required"}) return } // 分页参数 page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 20 } // 获取顶级评论(非回复) var comments []models.Comment var total int64 query := database.DB.Model(&models.Comment{}). Where("post_id = ? AND status = ? AND parent_id IS NULL", postID, "approved") query.Count(&total) if err := query.Preload("User"). Preload("Replies.User"). Order("created_at DESC"). Offset((page - 1) * pageSize). Limit(pageSize). Find(&comments).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get comments"}) return } c.JSON(http.StatusOK, gin.H{ "data": comments, "pagination": gin.H{ "page": page, "page_size": pageSize, "total": total, "total_page": (total + int64(pageSize) - 1) / int64(pageSize), }, }) } // DeleteComment 删除评论(仅限本人或管理员) func (h *CommentHandler) DeleteComment(c *gin.Context) { userID, _ := middleware.GetUserID(c) role, _ := c.Get("role") idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid comment id"}) return } var comment models.Comment if err := database.DB.First(&comment, id).Error; err != nil { if err == gorm.ErrRecordNotFound { c.JSON(http.StatusNotFound, gin.H{"error": "comment not found"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"}) return } // 检查权限:本人或管理员可删除 if comment.UserID != userID && role != "admin" { c.JSON(http.StatusForbidden, gin.H{"error": "permission denied"}) return } // 软删除 if err := database.DB.Delete(&comment).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete comment"}) return } c.JSON(http.StatusOK, gin.H{"message": "comment deleted"}) }