package logic import ( "context" "time" "spark-server/internal/module/moment/entity" ) type visCtx struct { viewer int64 selfAlbum bool friends map[int64]bool blocked map[int64]bool hideHim map[int64]bool hideMe map[int64]bool settings map[int64]*entity.Settings audience map[int64][]int64 now time.Time } func (v *visCtx) canSee(p *entity.Post) bool { if p == nil || p.Status != entity.StatusNormal { return false } if p.UserID == v.viewer { return true } if !v.friends[p.UserID] || v.blocked[p.UserID] || v.hideHim[p.UserID] || v.hideMe[p.UserID] { return false } if !v.selfAlbum { days := entity.VisibleAll if s := v.settings[p.UserID]; s != nil { days = s.VisibleDays } if !withinDays(p.CreatedAtMS, days, v.now) { return false } } return visibilityOK(p, v.viewer, v.audience[p.ID]) } func visibilityOK(p *entity.Post, viewer int64, peers []int64) bool { switch p.Visibility { case entity.VisibilityFriends: 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 withinDays(createdMS int64, days entity.VisibleDays, now time.Time) bool { if days <= 0 || createdMS <= 0 { return true } return createdMS >= now.AddDate(0, 0, -int(days)).UnixMilli() } 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, selfAlbum bool) (*visCtx, error) { authors := uniqueAuthors(posts) v := &visCtx{ viewer: viewer, selfAlbum: selfAlbum, friends: map[int64]bool{}, blocked: map[int64]bool{}, hideHim: map[int64]bool{}, hideMe: map[int64]bool{}, now: time.Now(), } friendIDs, err := s.friends.ListFriendIDs(ctx, viewer) if err != nil { return nil, err } for _, id := range friendIDs { v.friends[id] = true } blocked, err := s.friends.ListBlockedPeerIDs(ctx, viewer) if err != nil { return nil, err } for _, id := range blocked { v.blocked[id] = true } if err := s.fillHides(ctx, viewer, v); err != nil { return nil, err } v.settings, err = s.repo.ListSettings(ctx, authors) if err != nil { return nil, err } needAud := make([]int64, 0) for _, p := range posts { if p != nil && p.Visibility.NeedsAudience() { needAud = append(needAud, p.ID) } } v.audience, err = s.repo.ListAudience(ctx, needAud) return v, err } func (s *Service) fillHides(ctx context.Context, viewer int64, v *visCtx) error { him, err := s.repo.HideHimIDs(ctx, viewer) if err != nil { return err } for _, id := range him { v.hideHim[id] = true } me, err := s.repo.HideMeFromIDs(ctx, viewer) if err != nil { return err } for _, id := range me { v.hideMe[id] = true } return nil } func uniqueAuthors(posts []*entity.Post) []int64 { seen := make(map[int64]struct{}) out := make([]int64, 0) for _, p := range posts { if p == nil || p.UserID <= 0 { continue } if _, ok := seen[p.UserID]; ok { continue } seen[p.UserID] = struct{}{} out = append(out, p.UserID) } return out } func idSet(ids []int64) map[int64]bool { out := make(map[int64]bool, len(ids)) for _, id := range ids { out[id] = true } return out }