refactor(vis): H4.5 steps 4-5 — statistics and the three reader gates on the canonical resolver; core goes package-level
VisibleLibrarySet becomes a package-level function taking the queries (db-only services like statistics reach it without new wiring); the LibraryService method stays as the ergonomic entry point. Statistics' ids-shaper and the reader pages' three hand-rolled membership loops (empty-rows fallback then linear scans) now delegate; the gates keep their 403-on-invisible semantics (>null set membership, never silent pass). Census addendum from this pass: two OPDS sites call GetUserVisibleLibraries directly but consume FULL ROWS (per-library folder enumeration) — a third legitimate pattern alongside set/ids and resolveLibrary's active-selection; documented, untouched. The library LIST endpoint and its SSR data helper are row consumers too, by design.
This commit is contained in:
1 parent
8dbaa8f810
commit
454938c31f
3 files changed
+27
-39
No files matched your search
@@ -174,7 +174,8 @@ func (s *LibraryService) SetLibraryVisibility(ctx context.Context, userID, libra
|
||||
return &visibility, nil
|
||||
}
|
||||
|
||||
// GetUserVisibleLibraries retrieves all libraries visible to a user
|
||||
// GetUserVisibleLibraries retrieves all libraries visible to a user.
|
||||
|
||||
// VisibleLibrarySet is THE canonical library-visibility resolver (H4.5):
|
||||
// every endpoint that asks "which libraries can this user see" funnels
|
||||
// here. The family-lens rule itself lives in the
|
||||
@@ -182,8 +183,8 @@ func (s *LibraryService) SetLibraryVisibility(ctx context.Context, userID, libra
|
||||
// default-allow: an admin hides a library, everyone else still sees it).
|
||||
// Callers adapt their own identity source (JWT user object, device
|
||||
// token, SSR session); this core takes the resolved user id.
|
||||
func (s *LibraryService) VisibleLibrarySet(ctx context.Context, userID pgtype.UUID) (map[string]bool, []pgtype.UUID, error) {
|
||||
rows, err := s.GetUserVisibleLibraries(ctx, userID)
|
||||
func VisibleLibrarySet(ctx context.Context, db *database.Queries, userID pgtype.UUID) (map[string]bool, []pgtype.UUID, error) {
|
||||
rows, err := db.GetUserVisibleLibraries(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to check library access: %w", err)
|
||||
}
|
||||
@@ -199,6 +200,12 @@ func (s *LibraryService) VisibleLibrarySet(ctx context.Context, userID pgtype.UU
|
||||
return set, ids, nil
|
||||
}
|
||||
|
||||
// VisibleLibrarySet is the LibraryService entry point for the
|
||||
// package-level core (see the core's doc).
|
||||
func (s *LibraryService) VisibleLibrarySet(ctx context.Context, userID pgtype.UUID) (map[string]bool, []pgtype.UUID, error) {
|
||||
return VisibleLibrarySet(ctx, s.db, userID)
|
||||
}
|
||||
|
||||
func (s *LibraryService) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]database.GetUserVisibleLibrariesRow, error) {
|
||||
return s.db.GetUserVisibleLibraries(ctx, userID)
|
||||
}
|
||||
|
||||
@@ -188,18 +188,10 @@ type SessionSummary struct {
|
||||
|
||||
// userVisibleLibraryIDs loads the family-lens set for this user (empty →
|
||||
// no visible-library filter, i.e. everything is visible by default).
|
||||
// userVisibleLibraryIDs delegates to the canonical resolver (H4.5).
|
||||
func (s *StatisticsService) userVisibleLibraryIDs(ctx context.Context, userID pgtype.UUID) ([]pgtype.UUID, error) {
|
||||
rows, err := s.db.GetUserVisibleLibraries(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check library access: %w", err)
|
||||
}
|
||||
ids := make([]pgtype.UUID, 0, len(rows))
|
||||
for _, lib := range rows {
|
||||
if lib.ID.Valid {
|
||||
ids = append(ids, lib.ID)
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
_, ids, err := VisibleLibrarySet(ctx, s.db, userID)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// ErrLibraryNotVisible is returned by LibraryUsage when the caller asked
|
||||
|
||||
Reference in new issue
Block a user