153 lines
3.3 KiB
Go
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
|
|
}
|