141 lines
3.6 KiB
Go
141 lines
3.6 KiB
Go
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"})
|
|
} |