Files
backend/internal/handler/vote_handler.go

217 lines
4.8 KiB
Go
Raw Permalink Normal View History

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})
}