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 }