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.
This commit is contained in:
@@ -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 评论游标分页响应
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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"),
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
// 转换字符串参数为整数
|
||||
|
||||
Reference in New Issue
Block a user