2026-03-09 21:28:58 +08:00
|
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
|
|
|
|
|
|
"carrot_bbs/internal/dto"
|
|
|
|
|
|
"carrot_bbs/internal/model"
|
|
|
|
|
|
"carrot_bbs/internal/pkg/response"
|
|
|
|
|
|
"carrot_bbs/internal/service"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// PostHandler 帖子处理器
|
|
|
|
|
|
type PostHandler struct {
|
|
|
|
|
|
postService *service.PostService
|
|
|
|
|
|
userService *service.UserService
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewPostHandler 创建帖子处理器
|
|
|
|
|
|
func NewPostHandler(postService *service.PostService, userService *service.UserService) *PostHandler {
|
|
|
|
|
|
return &PostHandler{
|
|
|
|
|
|
postService: postService,
|
|
|
|
|
|
userService: userService,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create 创建帖子
|
|
|
|
|
|
func (h *PostHandler) Create(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type CreateRequest struct {
|
|
|
|
|
|
Title string `json:"title" binding:"required"`
|
|
|
|
|
|
Content string `json:"content" binding:"required"`
|
|
|
|
|
|
Images []string `json:"images"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var req CreateRequest
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
response.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
post, err := h.postService.Create(c.Request.Context(), userID, req.Title, req.Content, req.Images)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
var moderationErr *service.PostModerationRejectedError
|
|
|
|
|
|
if errors.As(err, &moderationErr) {
|
|
|
|
|
|
response.BadRequest(c, moderationErr.UserMessage())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
response.InternalServerError(c, "failed to create post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response.Success(c, dto.ConvertPostToResponse(post, false, false))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetByID 获取帖子(不增加浏览量)
|
|
|
|
|
|
func (h *PostHandler) GetByID(c *gin.Context) {
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.NotFound(c, "post not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 非作者不可查看未发布内容
|
|
|
|
|
|
currentUserID := c.GetString("user_id")
|
|
|
|
|
|
if post.Status != model.PostStatusPublished && post.UserID != currentUserID {
|
|
|
|
|
|
response.NotFound(c, "post not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:不再自动增加浏览量,浏览量通过 RecordView 端点单独记录
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 获取交互状态
|
|
|
|
|
|
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, currentUserID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 如果有当前用户,检查与帖子作者的相互关注状态
|
|
|
|
|
|
var authorWithFollowStatus *dto.UserResponse
|
|
|
|
|
|
if currentUserID != "" && post.User != nil {
|
|
|
|
|
|
_, isFollowing, isFollowingMe, err := h.userService.GetUserByIDWithMutualFollowStatus(c.Request.Context(), post.UserID, currentUserID)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
authorWithFollowStatus = dto.ConvertUserToResponseWithMutualFollow(post.User, isFollowing, isFollowingMe)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果出错,使用默认的author
|
|
|
|
|
|
authorWithFollowStatus = dto.ConvertUserToResponse(post.User)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建响应
|
|
|
|
|
|
responseData := &dto.PostResponse{
|
|
|
|
|
|
ID: post.ID,
|
|
|
|
|
|
UserID: post.UserID,
|
|
|
|
|
|
Title: post.Title,
|
|
|
|
|
|
Content: post.Content,
|
|
|
|
|
|
Images: dto.ConvertPostImagesToResponse(post.Images),
|
2026-03-10 12:58:23 +08:00
|
|
|
|
Status: string(post.Status),
|
2026-03-09 21:28:58 +08:00
|
|
|
|
LikesCount: post.LikesCount,
|
|
|
|
|
|
CommentsCount: post.CommentsCount,
|
|
|
|
|
|
FavoritesCount: post.FavoritesCount,
|
|
|
|
|
|
SharesCount: post.SharesCount,
|
|
|
|
|
|
ViewsCount: post.ViewsCount,
|
|
|
|
|
|
IsPinned: post.IsPinned,
|
|
|
|
|
|
IsLocked: post.IsLocked,
|
|
|
|
|
|
IsVote: post.IsVote,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(post.CreatedAt),
|
2026-03-10 12:58:23 +08:00
|
|
|
|
UpdatedAt: dto.FormatTime(post.UpdatedAt),
|
2026-03-09 21:28:58 +08:00
|
|
|
|
Author: authorWithFollowStatus,
|
|
|
|
|
|
IsLiked: isLiked,
|
|
|
|
|
|
IsFavorited: isFavorited,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response.Success(c, responseData)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// RecordView 记录帖子浏览(增加浏览量)
|
|
|
|
|
|
func (h *PostHandler) RecordView(c *gin.Context) {
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
|
|
|
|
|
|
// 验证帖子存在
|
|
|
|
|
|
_, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.NotFound(c, "post not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 增加浏览量
|
|
|
|
|
|
if err := h.postService.IncrementViews(c.Request.Context(), id, userID); err != nil {
|
2026-03-09 22:18:53 +08:00
|
|
|
|
fmt.Printf("[ERROR] Failed to increment views for post %s: %v\n", id, err)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
response.InternalServerError(c, "failed to record view")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response.Success(c, gin.H{"success": true})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// List 获取帖子列表
|
|
|
|
|
|
func (h *PostHandler) List(c *gin.Context) {
|
|
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
|
|
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
|
|
userID := c.Query("user_id")
|
|
|
|
|
|
tab := c.Query("tab") // recommend, follow, hot, latest
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前用户ID
|
|
|
|
|
|
currentUserID := c.GetString("user_id")
|
|
|
|
|
|
|
|
|
|
|
|
var posts []*model.Post
|
|
|
|
|
|
var total int64
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
|
|
// 根据 tab 参数选择不同的获取方式
|
|
|
|
|
|
switch tab {
|
|
|
|
|
|
case "follow":
|
|
|
|
|
|
// 获取关注用户的帖子,需要登录
|
|
|
|
|
|
if currentUserID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "请先登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
posts, total, err = h.postService.GetFollowingPosts(c.Request.Context(), currentUserID, page, pageSize)
|
|
|
|
|
|
case "hot":
|
|
|
|
|
|
// 获取热门帖子
|
|
|
|
|
|
posts, total, err = h.postService.GetHotPosts(c.Request.Context(), page, pageSize)
|
|
|
|
|
|
case "recommend":
|
|
|
|
|
|
// 推荐帖子(从Gorse获取个性化推荐)
|
|
|
|
|
|
posts, total, err = h.postService.GetRecommendedPosts(c.Request.Context(), currentUserID, page, pageSize)
|
|
|
|
|
|
case "latest":
|
|
|
|
|
|
// 最新帖子
|
2026-03-10 12:58:23 +08:00
|
|
|
|
if userID != "" && userID == currentUserID {
|
|
|
|
|
|
posts, total, err = h.postService.GetLatestPostsForOwner(c.Request.Context(), page, pageSize, userID)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
posts, total, err = h.postService.GetLatestPosts(c.Request.Context(), page, pageSize, userID)
|
|
|
|
|
|
}
|
2026-03-09 21:28:58 +08:00
|
|
|
|
default:
|
|
|
|
|
|
// 默认获取最新帖子
|
2026-03-10 12:58:23 +08:00
|
|
|
|
if userID != "" && userID == currentUserID {
|
|
|
|
|
|
posts, total, err = h.postService.GetLatestPostsForOwner(c.Request.Context(), page, pageSize, userID)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
posts, total, err = h.postService.GetLatestPosts(c.Request.Context(), page, pageSize, userID)
|
|
|
|
|
|
}
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get posts")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 批量获取交互状态
|
|
|
|
|
|
postIDs := make([]string, len(posts))
|
|
|
|
|
|
for i, post := range posts {
|
|
|
|
|
|
postIDs[i] = post.ID
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
2026-03-10 20:52:50 +08:00
|
|
|
|
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 转换为响应结构
|
2026-03-10 20:52:50 +08:00
|
|
|
|
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
response.Paginated(c, postResponses, total, page, pageSize)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Update 更新帖子
|
|
|
|
|
|
func (h *PostHandler) Update(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.NotFound(c, "post not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if post.UserID != userID {
|
|
|
|
|
|
response.Forbidden(c, "cannot update others' post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type UpdateRequest struct {
|
2026-03-10 12:58:23 +08:00
|
|
|
|
Title string `json:"title"`
|
|
|
|
|
|
Content string `json:"content"`
|
|
|
|
|
|
Images *[]string `json:"images"`
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var req UpdateRequest
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
response.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if req.Title != "" {
|
|
|
|
|
|
post.Title = req.Title
|
|
|
|
|
|
}
|
|
|
|
|
|
if req.Content != "" {
|
|
|
|
|
|
post.Content = req.Content
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 12:58:23 +08:00
|
|
|
|
err = h.postService.UpdateWithImages(c.Request.Context(), post, req.Images)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to update post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 12:58:23 +08:00
|
|
|
|
post, err = h.postService.GetByID(c.Request.Context(), post.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get updated post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 获取交互状态
|
2026-03-09 21:28:58 +08:00
|
|
|
|
currentUserID := c.GetString("user_id")
|
2026-03-10 20:52:50 +08:00
|
|
|
|
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), post.ID, currentUserID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Delete 删除帖子
|
|
|
|
|
|
func (h *PostHandler) Delete(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.NotFound(c, "post not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if post.UserID != userID {
|
|
|
|
|
|
response.Forbidden(c, "cannot delete others' post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err = h.postService.Delete(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to delete post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response.SuccessWithMessage(c, "post deleted", nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Like 点赞帖子
|
|
|
|
|
|
func (h *PostHandler) Like(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
err := h.postService.Like(c.Request.Context(), id, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to like post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取更新后的帖子状态
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 获取交互状态
|
|
|
|
|
|
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Unlike 取消点赞
|
|
|
|
|
|
func (h *PostHandler) Unlike(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
err := h.postService.Unlike(c.Request.Context(), id, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to unlike post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取更新后的帖子状态
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 获取交互状态
|
|
|
|
|
|
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Favorite 收藏帖子
|
|
|
|
|
|
func (h *PostHandler) Favorite(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
err := h.postService.Favorite(c.Request.Context(), id, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to favorite post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取更新后的帖子状态
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 获取交互状态
|
|
|
|
|
|
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Unfavorite 取消收藏
|
|
|
|
|
|
func (h *PostHandler) Unfavorite(c *gin.Context) {
|
|
|
|
|
|
userID := c.GetString("user_id")
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
response.Unauthorized(c, "")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
|
|
|
|
err := h.postService.Unfavorite(c.Request.Context(), id, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to unfavorite post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取更新后的帖子状态
|
|
|
|
|
|
post, err := h.postService.GetByID(c.Request.Context(), id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get post")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 获取交互状态
|
|
|
|
|
|
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserPosts 获取用户帖子列表
|
|
|
|
|
|
func (h *PostHandler) GetUserPosts(c *gin.Context) {
|
|
|
|
|
|
userID := c.Param("id")
|
|
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
|
|
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
|
|
|
2026-03-10 12:58:23 +08:00
|
|
|
|
currentUserID := c.GetString("user_id")
|
|
|
|
|
|
includePending := currentUserID != "" && currentUserID == userID
|
|
|
|
|
|
posts, total, err := h.postService.GetUserPosts(c.Request.Context(), userID, page, pageSize, includePending)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get user posts")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 批量获取交互状态
|
|
|
|
|
|
postIDs := make([]string, len(posts))
|
|
|
|
|
|
for i, post := range posts {
|
|
|
|
|
|
postIDs[i] = post.ID
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
2026-03-10 20:52:50 +08:00
|
|
|
|
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 转换为响应结构
|
2026-03-10 20:52:50 +08:00
|
|
|
|
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
response.Paginated(c, postResponses, total, page, pageSize)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetFavorites 获取收藏列表
|
|
|
|
|
|
func (h *PostHandler) GetFavorites(c *gin.Context) {
|
|
|
|
|
|
userID := c.Param("id")
|
|
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
|
|
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
|
|
|
|
|
|
|
|
posts, total, err := h.postService.GetFavorites(c.Request.Context(), userID, page, pageSize)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to get favorites")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 批量获取交互状态
|
2026-03-09 21:28:58 +08:00
|
|
|
|
currentUserID := c.GetString("user_id")
|
2026-03-10 20:52:50 +08:00
|
|
|
|
postIDs := make([]string, len(posts))
|
|
|
|
|
|
for i, post := range posts {
|
|
|
|
|
|
postIDs[i] = post.ID
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
2026-03-10 20:52:50 +08:00
|
|
|
|
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 转换为响应结构
|
2026-03-10 20:52:50 +08:00
|
|
|
|
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
response.Paginated(c, postResponses, total, page, pageSize)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Search 搜索帖子
|
|
|
|
|
|
func (h *PostHandler) Search(c *gin.Context) {
|
|
|
|
|
|
keyword := c.Query("keyword")
|
|
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
|
|
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
|
|
|
|
|
|
|
|
posts, total, err := h.postService.Search(c.Request.Context(), keyword, page, pageSize)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.InternalServerError(c, "failed to search posts")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// 批量获取交互状态
|
2026-03-09 21:28:58 +08:00
|
|
|
|
currentUserID := c.GetString("user_id")
|
2026-03-10 20:52:50 +08:00
|
|
|
|
postIDs := make([]string, len(posts))
|
|
|
|
|
|
for i, post := range posts {
|
|
|
|
|
|
postIDs[i] = post.ID
|
2026-03-09 21:28:58 +08:00
|
|
|
|
}
|
2026-03-10 20:52:50 +08:00
|
|
|
|
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 转换为响应结构
|
2026-03-10 20:52:50 +08:00
|
|
|
|
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
|
2026-03-09 21:28:58 +08:00
|
|
|
|
|
|
|
|
|
|
response.Paginated(c, postResponses, total, page, pageSize)
|
|
|
|
|
|
}
|