package logic import ( "context" "spark-server/internal/module/square/entity" "spark-server/internal/pkg/errs" ) // FeedQuery is list filter/sort for a plaza channel. type FeedQuery struct { Cursor int64 Limit int Category entity.Category Lat float64 Lng float64 } func (s *Service) Feed(ctx context.Context, viewerID int64, channel entity.Channel, q FeedQuery) (*ListResult, error) { if !s.ready() || viewerID <= 0 { return nil, errs.ErrUnauthorized } channel = normalizeChannel(channel) if !channel.Valid() { return nil, errs.ErrInvalidArgument } if !q.Category.Valid() { return nil, errs.ErrInvalidArgument } limit := entity.ClampLimit(q.Limit) picked := make([]*entity.Post, 0, limit) scan := q.Cursor for range entity.OverfetchRounds { batch, err := s.repo.ListPublicFeed(ctx, channel, entity.FeedListQuery{ Cursor: scan, Limit: entity.Overfetch, Category: q.Category, Lat: q.Lat, Lng: q.Lng, }) if err != nil { return nil, err } if len(batch) == 0 { break } vis, err := s.visFor(ctx, viewerID, batch) if err != nil { return nil, err } for _, p := range batch { scan = p.ID if !vis.canSee(p) { continue } picked = append(picked, p) if len(picked) >= limit { break } } if len(picked) >= limit || len(batch) < entity.Overfetch { break } } return s.listResult(ctx, viewerID, picked, limit, false) } func (s *Service) listResult(ctx context.Context, viewer int64, posts []*entity.Post, limit int, full bool) (*ListResult, error) { views, err := s.attachViews(ctx, viewer, posts, full) if err != nil { return nil, err } next := int64(0) if len(posts) > 0 { next = posts[len(posts)-1].ID } hasMore := len(posts) >= limit && limit > 0 return &ListResult{Items: views, NextCursor: next, HasMore: hasMore}, nil } // CategoryItem is one filter tab for clients. type CategoryItem struct { Value entity.Category `json:"value"` Kind string `json:"kind"` // feed | tag LabelKey string `json:"-"` } // Categories returns filter tabs (feed modes + tags) shared by every channel. func (s *Service) Categories() []CategoryItem { out := make([]CategoryItem, 0, len(entity.Categories())) for _, c := range entity.Categories() { kind := "feed" if c.IsTag() { kind = "tag" } out = append(out, CategoryItem{Value: c, Kind: kind}) } return out }