Files
backend/internal/dto/post_converter.go

285 lines
8.6 KiB
Go
Raw Normal View History

package dto
import (
"carrot_bbs/internal/model"
"context"
"encoding/json"
)
// ==================== Post 转换 ====================
// ConvertPostImageToResponse 将PostImage转换为PostImageResponse
func ConvertPostImageToResponse(img *model.PostImage) PostImageResponse {
if img == nil {
return PostImageResponse{}
}
return PostImageResponse{
ID: img.ID,
URL: img.URL,
ThumbnailURL: img.ThumbnailURL,
Width: img.Width,
Height: img.Height,
}
}
// ConvertPostImagesToResponse 将PostImage列表转换为响应列表
func ConvertPostImagesToResponse(images []model.PostImage) []PostImageResponse {
result := make([]PostImageResponse, 0, len(images))
for i := range images {
result = append(result, ConvertPostImageToResponse(&images[i]))
}
return result
}
// ConvertPostToResponse 将Post转换为PostResponse列表用
func ConvertPostToResponse(post *model.Post, isLiked, isFavorited bool) *PostResponse {
if post == nil {
return nil
}
images := make([]PostImageResponse, 0)
for _, img := range post.Images {
images = append(images, ConvertPostImageToResponse(&img))
}
var author *UserResponse
if post.User != nil {
author = ConvertUserToResponse(post.User)
}
return &PostResponse{
ID: post.ID,
UserID: post.UserID,
Title: post.Title,
Content: post.Content,
Images: images,
Status: string(post.Status),
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: FormatTime(post.CreatedAt),
UpdatedAt: FormatTime(post.UpdatedAt),
ContentEditedAt: FormatTimePointer(post.ContentEditedAt),
Author: author,
IsLiked: isLiked,
IsFavorited: isFavorited,
}
}
// ConvertPostToDetailResponse 将Post转换为PostDetailResponse
func ConvertPostToDetailResponse(post *model.Post, isLiked, isFavorited bool) *PostDetailResponse {
if post == nil {
return nil
}
images := make([]PostImageResponse, 0)
for _, img := range post.Images {
images = append(images, ConvertPostImageToResponse(&img))
}
var author *UserResponse
if post.User != nil {
author = ConvertUserToResponse(post.User)
}
return &PostDetailResponse{
ID: post.ID,
UserID: post.UserID,
Title: post.Title,
Content: post.Content,
Images: images,
Status: string(post.Status),
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: FormatTime(post.CreatedAt),
UpdatedAt: FormatTime(post.UpdatedAt),
ContentEditedAt: FormatTimePointer(post.ContentEditedAt),
Author: author,
IsLiked: isLiked,
IsFavorited: isFavorited,
}
}
// ConvertPostsToResponse 将Post列表转换为响应列表每个帖子独立检查点赞/收藏状态)
func ConvertPostsToResponse(posts []*model.Post, isLikedMap, isFavoritedMap map[string]bool) []*PostResponse {
result := make([]*PostResponse, 0, len(posts))
for _, post := range posts {
isLiked := false
isFavorited := false
if isLikedMap != nil {
isLiked = isLikedMap[post.ID]
}
if isFavoritedMap != nil {
isFavorited = isFavoritedMap[post.ID]
}
result = append(result, ConvertPostToResponse(post, isLiked, isFavorited))
}
return result
}
// BuildPostResponse 构建单个帖子响应(包含交互状态)
// 这是一个语义化的辅助函数,便于 Handler 层调用
func BuildPostResponse(post *model.Post, isLiked, isFavorited bool) *PostResponse {
return ConvertPostToResponse(post, isLiked, isFavorited)
}
// BuildPostsWithInteractionResponse 批量构建帖子响应(包含交互状态)
// 这是一个语义化的辅助函数,便于 Handler 层调用
func BuildPostsWithInteractionResponse(posts []*model.Post, isLikedMap, isFavoritedMap map[string]bool) []*PostResponse {
return ConvertPostsToResponse(posts, isLikedMap, isFavoritedMap)
}
// ==================== Comment 转换 ====================
// ConvertCommentToResponse 将Comment转换为CommentResponse
func ConvertCommentToResponse(comment *model.Comment, isLiked bool) *CommentResponse {
if comment == nil {
return nil
}
var author *UserResponse
if comment.User != nil {
author = ConvertUserToResponse(comment.User)
}
// 转换子回复(扁平化结构)
var replies []*CommentResponse
if len(comment.Replies) > 0 {
replies = make([]*CommentResponse, 0, len(comment.Replies))
for _, reply := range comment.Replies {
replies = append(replies, ConvertCommentToResponse(reply, false))
}
}
// TargetID 就是 ParentID前端根据这个 ID 找到被回复用户的昵称
var targetID *string
if comment.ParentID != nil && *comment.ParentID != "" {
targetID = comment.ParentID
}
// 解析图片JSON
var images []CommentImageResponse
if comment.Images != "" {
var urlList []string
if err := json.Unmarshal([]byte(comment.Images), &urlList); err == nil {
images = make([]CommentImageResponse, 0, len(urlList))
for _, url := range urlList {
images = append(images, CommentImageResponse{URL: url})
}
}
}
return &CommentResponse{
ID: comment.ID,
PostID: comment.PostID,
UserID: comment.UserID,
ParentID: comment.ParentID,
RootID: comment.RootID,
Content: comment.Content,
Images: images,
LikesCount: comment.LikesCount,
RepliesCount: comment.RepliesCount,
CreatedAt: FormatTime(comment.CreatedAt),
Author: author,
IsLiked: isLiked,
TargetID: targetID,
Replies: replies,
}
}
// ConvertCommentsToResponse 将Comment列表转换为响应列表
func ConvertCommentsToResponse(comments []*model.Comment, isLiked bool) []*CommentResponse {
result := make([]*CommentResponse, 0, len(comments))
for _, comment := range comments {
result = append(result, ConvertCommentToResponse(comment, isLiked))
}
return result
}
// IsLikedChecker 点赞状态检查器接口
type IsLikedChecker interface {
IsLiked(ctx context.Context, commentID, userID string) bool
}
// ConvertCommentToResponseWithUser 将Comment转换为CommentResponse根据用户ID检查点赞状态
func ConvertCommentToResponseWithUser(comment *model.Comment, userID string, checker IsLikedChecker) *CommentResponse {
if comment == nil {
return nil
}
// 检查当前用户是否点赞了该评论
isLiked := false
if userID != "" && checker != nil {
isLiked = checker.IsLiked(context.Background(), comment.ID, userID)
}
var author *UserResponse
if comment.User != nil {
author = ConvertUserToResponse(comment.User)
}
// 转换子回复(扁平化结构),递归检查点赞状态
var replies []*CommentResponse
if len(comment.Replies) > 0 {
replies = make([]*CommentResponse, 0, len(comment.Replies))
for _, reply := range comment.Replies {
replies = append(replies, ConvertCommentToResponseWithUser(reply, userID, checker))
}
}
// TargetID 就是 ParentID前端根据这个 ID 找到被回复用户的昵称
var targetID *string
if comment.ParentID != nil && *comment.ParentID != "" {
targetID = comment.ParentID
}
// 解析图片JSON
var images []CommentImageResponse
if comment.Images != "" {
var urlList []string
if err := json.Unmarshal([]byte(comment.Images), &urlList); err == nil {
images = make([]CommentImageResponse, 0, len(urlList))
for _, url := range urlList {
images = append(images, CommentImageResponse{URL: url})
}
}
}
return &CommentResponse{
ID: comment.ID,
PostID: comment.PostID,
UserID: comment.UserID,
ParentID: comment.ParentID,
RootID: comment.RootID,
Content: comment.Content,
Images: images,
LikesCount: comment.LikesCount,
RepliesCount: comment.RepliesCount,
CreatedAt: FormatTime(comment.CreatedAt),
Author: author,
IsLiked: isLiked,
TargetID: targetID,
Replies: replies,
}
}
// ConvertCommentsToResponseWithUser 将Comment列表转换为响应列表根据用户ID检查点赞状态
func ConvertCommentsToResponseWithUser(comments []*model.Comment, userID string, checker IsLikedChecker) []*CommentResponse {
result := make([]*CommentResponse, 0, len(comments))
for _, comment := range comments {
result = append(result, ConvertCommentToResponseWithUser(comment, userID, checker))
}
return result
}