From e0f34653a2f20c6be24d305d646c8f9db5455fe6 Mon Sep 17 00:00:00 2001 From: lafay <2021211506@stu.hit.edu.cn> Date: Sat, 25 Apr 2026 11:25:43 +0800 Subject: [PATCH] feat(posts): filter posts by blocked users Add functionality to filter out posts from blocked users in post listing endpoints. Includes a new `IsBlockedBatch` method for efficient batch checking of blocked relationships and `is_blocked` field in API responses when viewing a blocked user's posts. --- internal/dto/dto.go | 1 + internal/handler/post_handler.go | 71 +++++++++++++++++++ .../repository/system_notification_repo.go | 5 +- internal/service/push_service.go | 1 + internal/service/user_service.go | 6 ++ 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/internal/dto/dto.go b/internal/dto/dto.go index 6d5c219..ea77d6d 100644 --- a/internal/dto/dto.go +++ b/internal/dto/dto.go @@ -1285,6 +1285,7 @@ type PostCursorPageResponse struct { NextCursor string `json:"next_cursor,omitempty"` PrevCursor string `json:"prev_cursor,omitempty"` HasMore bool `json:"has_more"` + IsBlocked bool `json:"is_blocked,omitempty"` } // CommentCursorPageResponse 评论游标分页响应 diff --git a/internal/handler/post_handler.go b/internal/handler/post_handler.go index 8b8d427..243987b 100644 --- a/internal/handler/post_handler.go +++ b/internal/handler/post_handler.go @@ -1,6 +1,7 @@ package handler import ( + "context" "errors" "fmt" "strconv" @@ -31,6 +32,41 @@ func NewPostHandler(postService service.PostService, userService service.UserSer } } +// collectAuthorIDs 从帖子列表中收集去重的作者ID +func collectAuthorIDs(posts []*model.Post) []string { + seen := make(map[string]struct{}) + ids := make([]string, 0, len(posts)) + for _, p := range posts { + if _, ok := seen[p.UserID]; !ok { + seen[p.UserID] = struct{}{} + ids = append(ids, p.UserID) + } + } + return ids +} + +// filterBlockedPosts 过滤掉被当前用户拉黑的作者发布的帖子 +func (h *PostHandler) filterBlockedPosts(ctx context.Context, posts []*model.Post, currentUserID string) []*model.Post { + if currentUserID == "" || len(posts) == 0 { + return posts + } + + authorIDs := collectAuthorIDs(posts) + blockedMap, err := h.userService.IsBlockedBatch(ctx, currentUserID, authorIDs) + if err != nil { + return posts + } + + filtered := make([]*model.Post, 0, len(posts)) + for _, p := range posts { + if blockedMap[p.UserID] { + continue + } + filtered = append(filtered, p) + } + return filtered +} + // channelMapForPosts 批量解析帖子中的频道 ID,用于填充响应里的 channel 名称 func (h *PostHandler) channelMapForPosts(posts []*model.Post) map[string]*model.Channel { ids := dto.CollectPostChannelIDs(posts) @@ -267,6 +303,8 @@ func (h *PostHandler) List(c *gin.Context) { return } + posts = h.filterBlockedPosts(c.Request.Context(), posts, currentUserID) + // 批量获取交互状态 postIDs := make([]string, len(posts)) for i, post := range posts { @@ -324,6 +362,8 @@ func (h *PostHandler) ListByCursor(c *gin.Context) { return } + result.Items = h.filterBlockedPosts(c.Request.Context(), result.Items, currentUserID) + // 批量获取交互状态 postIDs := make([]string, len(result.Items)) for i, post := range result.Items { @@ -577,6 +617,32 @@ func (h *PostHandler) GetUserPosts(c *gin.Context) { return } + // 检查是否拉黑了对方 + if currentUserID != "" && currentUserID != userID { + isBlocked, _ := h.userService.IsBlocked(c.Request.Context(), currentUserID, userID) + if isBlocked { + // 检查是否使用游标分页 + cursorStr := c.Query("cursor") + if cursorStr != "" { + response.Success(c, &dto.PostCursorPageResponse{ + Items: []*dto.PostResponse{}, + HasMore: false, + IsBlocked: true, + }) + } else { + response.Success(c, gin.H{ + "list": []*dto.PostResponse{}, + "total": 0, + "page": 1, + "page_size": 20, + "total_pages": 0, + "is_blocked": true, + }) + } + return + } + } + // 检查是否使用游标分页 cursorStr := c.Query("cursor") if cursorStr != "" { @@ -709,6 +775,9 @@ func (h *PostHandler) Search(c *gin.Context) { // 批量获取交互状态 currentUserID := c.GetString("user_id") + + posts = h.filterBlockedPosts(c.Request.Context(), posts, currentUserID) + postIDs := make([]string, len(posts)) for i, post := range posts { postIDs[i] = post.ID @@ -736,6 +805,8 @@ func (h *PostHandler) SearchByCursor(c *gin.Context) { return } + result.Items = h.filterBlockedPosts(c.Request.Context(), result.Items, currentUserID) + // 批量获取交互状态 postIDs := make([]string, len(result.Items)) for i, post := range result.Items { diff --git a/internal/repository/system_notification_repo.go b/internal/repository/system_notification_repo.go index d17e70b..be3f138 100644 --- a/internal/repository/system_notification_repo.go +++ b/internal/repository/system_notification_repo.go @@ -3,6 +3,7 @@ import ( "context" "strconv" + "time" "with_you/internal/model" "with_you/internal/pkg/cursor" @@ -88,7 +89,7 @@ func (r *systemNotificationRepository) GetUnreadCount(receiverID string) (int64, // MarkAsRead 标记单条通知为已读 func (r *systemNotificationRepository) MarkAsRead(id int64, receiverID string) error { - now := model.SystemNotification{}.UpdatedAt + now := time.Now() return r.db.Model(&model.SystemNotification{}). Where("id = ? AND receiver_id = ?", id, receiverID). Updates(map[string]any{ @@ -99,7 +100,7 @@ func (r *systemNotificationRepository) MarkAsRead(id int64, receiverID string) e // MarkAllAsRead 标记用户所有通知为已读 func (r *systemNotificationRepository) MarkAllAsRead(receiverID string) error { - now := model.SystemNotification{}.UpdatedAt + now := time.Now() return r.db.Model(&model.SystemNotification{}). Where("receiver_id = ? AND is_read = ?", receiverID, false). Updates(map[string]any{ diff --git a/internal/service/push_service.go b/internal/service/push_service.go index ee4d459..f8ef1d7 100644 --- a/internal/service/push_service.go +++ b/internal/service/push_service.go @@ -482,6 +482,7 @@ func (s *pushServiceImpl) pushSystemNotificationViaWebSocket(ctx context.Context "type": string(notification.Type), "title": notification.Title, "content": notification.Content, + "is_read": notification.IsRead, "extra": map[string]any{}, "created_at": notification.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), } diff --git a/internal/service/user_service.go b/internal/service/user_service.go index 50aaae7..eed0b8b 100644 --- a/internal/service/user_service.go +++ b/internal/service/user_service.go @@ -53,6 +53,7 @@ type UserService interface { UnblockUser(ctx context.Context, blockerID, blockedID string) error GetBlockedUsers(ctx context.Context, blockerID string, page, pageSize int) ([]*model.User, int64, error) IsBlocked(ctx context.Context, blockerID, blockedID string) (bool, error) + IsBlockedBatch(ctx context.Context, blockerID string, blockedIDs []string) (map[string]bool, error) // 隐私设置 GetPrivacySettings(ctx context.Context, userID string) (*model.PrivacySettings, error) @@ -583,6 +584,11 @@ func (s *userServiceImpl) IsBlocked(ctx context.Context, blockerID, blockedID st return s.userRepo.IsBlocked(blockerID, blockedID) } +// IsBlockedBatch 批量检查拉黑关系 +func (s *userServiceImpl) IsBlockedBatch(ctx context.Context, blockerID string, blockedIDs []string) (map[string]bool, error) { + return s.userRepo.IsBlockedBatch(blockerID, blockedIDs) +} + // GetFollowingList 获取关注列表(字符串参数版本) func (s *userServiceImpl) GetFollowingList(ctx context.Context, userID, page, pageSize string) ([]*model.User, error) { // 转换字符串参数为整数