Files
backend/internal/dto/post_converter.go
lan 9a1851f023
Some checks failed
Build Backend / build (push) Successful in 1m56s
Build Backend / build-docker (push) Has been cancelled
refactor: cleanup unused code and simplify internal packages
This commit performs a significant cleanup of the codebase by removing unused functions, methods, and entire files across various internal modules. This reduces technical debt and simplifies the project structure.

Key changes include:
- **cache**: Removed unused cache key generators and metrics snapshots.
- **dto**: Removed redundant converter functions and segment creation helpers.
- **middleware**: Deleted the unused `logger.go` middleware and simplified `ratelimit.go` and `casbin.go`.
- **model**: Removed unused ID helpers, database closing functions, and batch decryption logic.
- **pkg**: Cleaned up unused utility functions in `circuitbreaker`, `crypto`, `cursor`, `hook`, and `utils`.
- **service**: Deleted `account_cleanup_service.go` and removed unused helper functions in `log_cleanup_service.go` and `sensitive_service.go`.
- **repository**: Removed unused private loading methods in `comment_repo.go`.
2026-05-14 02:24:30 +08:00

292 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package dto
import (
"context"
"encoding/json"
"with_you/internal/model"
)
// ==================== 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,
PreviewURL: img.PreviewURL,
PreviewURLLarge: img.PreviewURLLarge,
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
}
func postChannelBrief(post *model.Post, channelByID map[string]*model.Channel) *PostChannelBrief {
if post == nil || post.ChannelID == nil || *post.ChannelID == "" || channelByID == nil {
return nil
}
ch := channelByID[*post.ChannelID]
if ch == nil {
return nil
}
return &PostChannelBrief{ID: ch.ID, Name: ch.Name}
}
// CollectPostChannelIDs 从帖子列表收集去重后的频道 ID用于批量查库填充 channel 名称)
func CollectPostChannelIDs(posts []*model.Post) []string {
seen := make(map[string]struct{})
out := make([]string, 0)
for _, p := range posts {
if p == nil || p.ChannelID == nil || *p.ChannelID == "" {
continue
}
id := *p.ChannelID
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
out = append(out, id)
}
return out
}
// PostChannelBriefForPost 根据帖子与频道映射生成频道摘要(供 Handler 手动组装响应)
func PostChannelBriefForPost(post *model.Post, channelByID map[string]*model.Channel) *PostChannelBrief {
return postChannelBrief(post, channelByID)
}
// SegmentsOrDefault 如果 segments 为空但 content 非空,
// 返回降级的单 text segment否则原样返回。
func SegmentsOrDefault(segments model.MessageSegments, content string) model.MessageSegments {
if len(segments) > 0 {
return segments
}
if content != "" {
return model.MessageSegments{
{Type: string(SegmentTypeText), Data: map[string]any{"text": content}},
}
}
return nil
}
// ConvertPostToResponse 将Post转换为PostResponse列表用channelByID 可为 nil
func ConvertPostToResponse(post *model.Post, channelByID map[string]*model.Channel, 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,
ChannelID: post.ChannelID,
Title: post.Title,
Content: post.Content,
Segments: SegmentsOrDefault(post.Segments, 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,
Channel: postChannelBrief(post, channelByID),
}
}
// ConvertPostsToResponse 将Post列表转换为响应列表channelByID 可为 nil
func ConvertPostsToResponse(posts []*model.Post, channelByID map[string]*model.Channel, 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, channelByID, isLiked, isFavorited))
}
return result
}
// BuildPostResponse 构建单个帖子响应(包含交互状态)
// 这是一个语义化的辅助函数,便于 Handler 层调用
func BuildPostResponse(post *model.Post, channelByID map[string]*model.Channel, isLiked, isFavorited bool) *PostResponse {
return ConvertPostToResponse(post, channelByID, isLiked, isFavorited)
}
// BuildPostsWithInteractionResponse 批量构建帖子响应(包含交互状态)
// 这是一个语义化的辅助函数,便于 Handler 层调用
func BuildPostsWithInteractionResponse(posts []*model.Post, channelByID map[string]*model.Channel, isLikedMap, isFavoritedMap map[string]bool) []*PostResponse {
return ConvertPostsToResponse(posts, channelByID, 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,
Segments: SegmentsOrDefault(comment.Segments, comment.Content),
Images: images,
LikesCount: comment.LikesCount,
RepliesCount: comment.RepliesCount,
CreatedAt: FormatTime(comment.CreatedAt),
Author: author,
IsLiked: isLiked,
TargetID: targetID,
Replies: replies,
}
}
// 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,
Segments: SegmentsOrDefault(comment.Segments, 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
}