217 lines
4.8 KiB
Go
217 lines
4.8 KiB
Go
|
|
package handler
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"net/http"
|
|||
|
|
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
|
|||
|
|
"carrot_bbs/internal/dto"
|
|||
|
|
"carrot_bbs/internal/pkg/response"
|
|||
|
|
"carrot_bbs/internal/service"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// VoteHandler 投票处理器
|
|||
|
|
type VoteHandler struct {
|
|||
|
|
voteService *service.VoteService
|
|||
|
|
postService *service.PostService
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewVoteHandler 创建投票处理器
|
|||
|
|
func NewVoteHandler(voteService *service.VoteService, postService *service.PostService) *VoteHandler {
|
|||
|
|
return &VoteHandler{
|
|||
|
|
voteService: voteService,
|
|||
|
|
postService: postService,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CreateVotePost 创建投票帖子
|
|||
|
|
// POST /api/v1/posts/vote
|
|||
|
|
func (h *VoteHandler) CreateVotePost(c *gin.Context) {
|
|||
|
|
userID := c.GetString("user_id")
|
|||
|
|
if userID == "" {
|
|||
|
|
response.Unauthorized(c, "请先登录")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var req dto.CreateVotePostRequest
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
response.BadRequest(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
post, err := h.voteService.CreateVotePost(c.Request.Context(), userID, &req)
|
|||
|
|
if err != nil {
|
|||
|
|
var moderationErr *service.PostModerationRejectedError
|
|||
|
|
if errors.As(err, &moderationErr) {
|
|||
|
|
response.BadRequest(c, moderationErr.UserMessage())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
response.Error(c, http.StatusBadRequest, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, post)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetVoteResult 获取投票结果
|
|||
|
|
// GET /api/v1/posts/:id/vote
|
|||
|
|
func (h *VoteHandler) GetVoteResult(c *gin.Context) {
|
|||
|
|
postID := c.Param("id")
|
|||
|
|
if postID == "" {
|
|||
|
|
response.BadRequest(c, "帖子ID不能为空")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证帖子存在
|
|||
|
|
_, err := h.postService.GetByID(c.Request.Context(), postID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.NotFound(c, "帖子不存在")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取当前用户ID(可选登录)
|
|||
|
|
userID := c.GetString("user_id")
|
|||
|
|
|
|||
|
|
// 如果用户未登录,返回不带has_voted的结果
|
|||
|
|
if userID == "" {
|
|||
|
|
options, err := h.voteService.GetVoteOptions(postID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.InternalServerError(c, "获取投票选项失败")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算总票数
|
|||
|
|
totalVotes := 0
|
|||
|
|
for _, option := range options {
|
|||
|
|
totalVotes += option.VotesCount
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result := &dto.VoteResultDTO{
|
|||
|
|
Options: options,
|
|||
|
|
TotalVotes: totalVotes,
|
|||
|
|
HasVoted: false,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, result)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 用户已登录,获取完整的投票结果
|
|||
|
|
result, err := h.voteService.GetVoteResult(postID, userID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.InternalServerError(c, "获取投票结果失败")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, result)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Vote 投票
|
|||
|
|
// POST /api/v1/posts/:id/vote
|
|||
|
|
func (h *VoteHandler) Vote(c *gin.Context) {
|
|||
|
|
userID := c.GetString("user_id")
|
|||
|
|
if userID == "" {
|
|||
|
|
response.Unauthorized(c, "请先登录")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
postID := c.Param("id")
|
|||
|
|
if postID == "" {
|
|||
|
|
response.BadRequest(c, "帖子ID不能为空")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证帖子存在
|
|||
|
|
_, err := h.postService.GetByID(c.Request.Context(), postID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.NotFound(c, "帖子不存在")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析请求体
|
|||
|
|
var req struct {
|
|||
|
|
OptionID string `json:"option_id" binding:"required"`
|
|||
|
|
}
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
response.BadRequest(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if err := h.voteService.Vote(c.Request.Context(), postID, userID, req.OptionID); err != nil {
|
|||
|
|
response.Error(c, http.StatusBadRequest, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Unvote 取消投票
|
|||
|
|
// DELETE /api/v1/posts/:id/vote
|
|||
|
|
func (h *VoteHandler) Unvote(c *gin.Context) {
|
|||
|
|
userID := c.GetString("user_id")
|
|||
|
|
if userID == "" {
|
|||
|
|
response.Unauthorized(c, "请先登录")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
postID := c.Param("id")
|
|||
|
|
if postID == "" {
|
|||
|
|
response.BadRequest(c, "帖子ID不能为空")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证帖子存在
|
|||
|
|
_, err := h.postService.GetByID(c.Request.Context(), postID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.NotFound(c, "帖子不存在")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if err := h.voteService.Unvote(c.Request.Context(), postID, userID); err != nil {
|
|||
|
|
response.Error(c, http.StatusBadRequest, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateVoteOption 更新投票选项(仅作者)
|
|||
|
|
// PUT /api/v1/vote-options/:id
|
|||
|
|
func (h *VoteHandler) UpdateVoteOption(c *gin.Context) {
|
|||
|
|
userID := c.GetString("user_id")
|
|||
|
|
if userID == "" {
|
|||
|
|
response.Unauthorized(c, "请先登录")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
optionID := c.Param("id")
|
|||
|
|
if optionID == "" {
|
|||
|
|
response.BadRequest(c, "选项ID不能为空")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析请求体
|
|||
|
|
var req struct {
|
|||
|
|
Content string `json:"content" binding:"required"`
|
|||
|
|
}
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
response.BadRequest(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取帖子ID(从查询参数或请求体中获取)
|
|||
|
|
postID := c.Query("post_id")
|
|||
|
|
if postID == "" {
|
|||
|
|
response.BadRequest(c, "帖子ID不能为空")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if err := h.voteService.UpdateVoteOption(c.Request.Context(), postID, optionID, userID, req.Content); err != nil {
|
|||
|
|
response.Error(c, http.StatusForbidden, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, gin.H{"success": true})
|
|||
|
|
}
|