spark-server/internal/module/moment/logic/visible.go
2026-09-18 17:51:42 +08:00

153 lines
3.3 KiB
Go

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
}