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"`
|
NextCursor string `json:"next_cursor,omitempty"`
|
||||||
PrevCursor string `json:"prev_cursor,omitempty"`
|
PrevCursor string `json:"prev_cursor,omitempty"`
|
||||||
HasMore bool `json:"has_more"`
|
HasMore bool `json:"has_more"`
|
||||||
|
IsBlocked bool `json:"is_blocked,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommentCursorPageResponse 评论游标分页响应
|
// CommentCursorPageResponse 评论游标分页响应
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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 名称
|
// channelMapForPosts 批量解析帖子中的频道 ID,用于填充响应里的 channel 名称
|
||||||
func (h *PostHandler) channelMapForPosts(posts []*model.Post) map[string]*model.Channel {
|
func (h *PostHandler) channelMapForPosts(posts []*model.Post) map[string]*model.Channel {
|
||||||
ids := dto.CollectPostChannelIDs(posts)
|
ids := dto.CollectPostChannelIDs(posts)
|
||||||
@@ -267,6 +303,8 @@ func (h *PostHandler) List(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
posts = h.filterBlockedPosts(c.Request.Context(), posts, currentUserID)
|
||||||
|
|
||||||
// 批量获取交互状态
|
// 批量获取交互状态
|
||||||
postIDs := make([]string, len(posts))
|
postIDs := make([]string, len(posts))
|
||||||
for i, post := range posts {
|
for i, post := range posts {
|
||||||
@@ -324,6 +362,8 @@ func (h *PostHandler) ListByCursor(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.Items = h.filterBlockedPosts(c.Request.Context(), result.Items, currentUserID)
|
||||||
|
|
||||||
// 批量获取交互状态
|
// 批量获取交互状态
|
||||||
postIDs := make([]string, len(result.Items))
|
postIDs := make([]string, len(result.Items))
|
||||||
for i, post := range result.Items {
|
for i, post := range result.Items {
|
||||||
@@ -577,6 +617,32 @@ func (h *PostHandler) GetUserPosts(c *gin.Context) {
|
|||||||
return
|
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")
|
cursorStr := c.Query("cursor")
|
||||||
if cursorStr != "" {
|
if cursorStr != "" {
|
||||||
@@ -709,6 +775,9 @@ func (h *PostHandler) Search(c *gin.Context) {
|
|||||||
|
|
||||||
// 批量获取交互状态
|
// 批量获取交互状态
|
||||||
currentUserID := c.GetString("user_id")
|
currentUserID := c.GetString("user_id")
|
||||||
|
|
||||||
|
posts = h.filterBlockedPosts(c.Request.Context(), posts, currentUserID)
|
||||||
|
|
||||||
postIDs := make([]string, len(posts))
|
postIDs := make([]string, len(posts))
|
||||||
for i, post := range posts {
|
for i, post := range posts {
|
||||||
postIDs[i] = post.ID
|
postIDs[i] = post.ID
|
||||||
@@ -736,6 +805,8 @@ func (h *PostHandler) SearchByCursor(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.Items = h.filterBlockedPosts(c.Request.Context(), result.Items, currentUserID)
|
||||||
|
|
||||||
// 批量获取交互状态
|
// 批量获取交互状态
|
||||||
postIDs := make([]string, len(result.Items))
|
postIDs := make([]string, len(result.Items))
|
||||||
for i, post := range result.Items {
|
for i, post := range result.Items {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"with_you/internal/model"
|
"with_you/internal/model"
|
||||||
"with_you/internal/pkg/cursor"
|
"with_you/internal/pkg/cursor"
|
||||||
@@ -88,7 +89,7 @@ func (r *systemNotificationRepository) GetUnreadCount(receiverID string) (int64,
|
|||||||
|
|
||||||
// MarkAsRead 标记单条通知为已读
|
// MarkAsRead 标记单条通知为已读
|
||||||
func (r *systemNotificationRepository) MarkAsRead(id int64, receiverID string) error {
|
func (r *systemNotificationRepository) MarkAsRead(id int64, receiverID string) error {
|
||||||
now := model.SystemNotification{}.UpdatedAt
|
now := time.Now()
|
||||||
return r.db.Model(&model.SystemNotification{}).
|
return r.db.Model(&model.SystemNotification{}).
|
||||||
Where("id = ? AND receiver_id = ?", id, receiverID).
|
Where("id = ? AND receiver_id = ?", id, receiverID).
|
||||||
Updates(map[string]any{
|
Updates(map[string]any{
|
||||||
@@ -99,7 +100,7 @@ func (r *systemNotificationRepository) MarkAsRead(id int64, receiverID string) e
|
|||||||
|
|
||||||
// MarkAllAsRead 标记用户所有通知为已读
|
// MarkAllAsRead 标记用户所有通知为已读
|
||||||
func (r *systemNotificationRepository) MarkAllAsRead(receiverID string) error {
|
func (r *systemNotificationRepository) MarkAllAsRead(receiverID string) error {
|
||||||
now := model.SystemNotification{}.UpdatedAt
|
now := time.Now()
|
||||||
return r.db.Model(&model.SystemNotification{}).
|
return r.db.Model(&model.SystemNotification{}).
|
||||||
Where("receiver_id = ? AND is_read = ?", receiverID, false).
|
Where("receiver_id = ? AND is_read = ?", receiverID, false).
|
||||||
Updates(map[string]any{
|
Updates(map[string]any{
|
||||||
|
|||||||
@@ -482,6 +482,7 @@ func (s *pushServiceImpl) pushSystemNotificationViaWebSocket(ctx context.Context
|
|||||||
"type": string(notification.Type),
|
"type": string(notification.Type),
|
||||||
"title": notification.Title,
|
"title": notification.Title,
|
||||||
"content": notification.Content,
|
"content": notification.Content,
|
||||||
|
"is_read": notification.IsRead,
|
||||||
"extra": map[string]any{},
|
"extra": map[string]any{},
|
||||||
"created_at": notification.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
"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
|
UnblockUser(ctx context.Context, blockerID, blockedID string) error
|
||||||
GetBlockedUsers(ctx context.Context, blockerID string, page, pageSize int) ([]*model.User, int64, error)
|
GetBlockedUsers(ctx context.Context, blockerID string, page, pageSize int) ([]*model.User, int64, error)
|
||||||
IsBlocked(ctx context.Context, blockerID, blockedID string) (bool, 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)
|
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)
|
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 获取关注列表(字符串参数版本)
|
// GetFollowingList 获取关注列表(字符串参数版本)
|
||||||
func (s *userServiceImpl) GetFollowingList(ctx context.Context, userID, page, pageSize string) ([]*model.User, error) {
|
func (s *userServiceImpl) GetFollowingList(ctx context.Context, userID, page, pageSize string) ([]*model.User, error) {
|
||||||
// 转换字符串参数为整数
|
// 转换字符串参数为整数
|
||||||
|
|||||||
Reference in New Issue
Block a user