spark-server/internal/module/square/logic/visible.go
DESKTOP-L8OUL9F\gfl0034 715ace7ac6 feat(square): 广场 Bot/RSS 发布与媒体校验
支持广场机器人发帖与媒体类型检查,并补充相关迁移与 i18n。
2026-09-24 23:07:06 +08:00

88 lines
1.8 KiB
Go

package logic
import (
"context"
"time"
"spark-server/internal/module/square/entity"
)
type visCtx struct {
viewer int64
blocked map[int64]bool
audience map[int64][]int64
}
func (v *visCtx) canSee(p *entity.Post) bool {
if p == nil || p.Status != entity.StatusNormal || p.AuditStatus != entity.AuditApproved {
return false
}
if p.Expired(time.Now().UnixMilli()) {
return false
}
if p.UserID != v.viewer && v.blocked[p.UserID] {
return false
}
return visibilityOK(p, v.viewer, v.audience[p.ID])
}
func visibilityOK(p *entity.Post, viewer int64, peers []int64) bool {
if p.UserID == viewer {
return true
}
switch p.Visibility {
case entity.VisibilityPublic:
return true
case entity.VisibilityPrivate:
return false
case entity.VisibilityInclude:
return containsID(peers, viewer)
case entity.VisibilityExclude:
return !containsID(peers, viewer)
default:
return false
}
}
func containsID(ids []int64, want int64) bool {
for _, id := range ids {
if id == want {
return true
}
}
return false
}
func (s *Service) visFor(ctx context.Context, viewer int64, posts []*entity.Post) (*visCtx, error) {
v := &visCtx{viewer: viewer, blocked: map[int64]bool{}, audience: map[int64][]int64{}}
seen := map[int64]struct{}{}
for _, p := range posts {
if p == nil || p.UserID == viewer {
continue
}
if _, ok := seen[p.UserID]; ok {
continue
}
seen[p.UserID] = struct{}{}
blocked, err := s.friends.BlockedEither(ctx, viewer, p.UserID)
if err != nil {
return nil, err
}
if blocked {
v.blocked[p.UserID] = true
}
}
needAud := make([]int64, 0)
for _, p := range posts {
if p != nil && p.Visibility.NeedsAudience() {
needAud = append(needAud, p.ID)
}
}
aud, err := s.repo.ListAudience(ctx, needAud)
if err != nil {
return nil, err
}
v.audience = aud
return v, nil
}