refactor(vis): H4.5 step 1 — LibraryService.VisibleLibrarySet, the canonical resolver; media endpoints migrated

One core for "which libraries can this user see": family-lens default-
allow stays where it always was (the GetUserVisibleLibraries SQL);
the core adds the shared set+ids shaping that four endpoints each
hand-rolled. Media's visibleLibrarySet is now a thin identity adapter
(JWT user object -> resolved id) and the download-permission gate uses
the set instead of a manual membership loop.

Semantic diff (H4.5 step 1, in the plan): zero family-lens divergence
found across all six sites — the rule lives in one query; the variation
was shape-level (identity adapter, set-vs-ids, UUID idiom).
This commit is contained in:
John O'Keefe committed 2026-10-17 17:30:11 -04:00
1 parent 29a546229d
commit 1d12a64915
2 files changed
+30 -22

No files matched your search

+25
View File
@@ -4,6 +4,7 @@ import (
"bookhoard/internal/database"
"context"
"fmt"
"github.com/google/uuid"
"log"
"os"
"path/filepath"
@@ -174,6 +175,30 @@ func (s *LibraryService) SetLibraryVisibility(ctx context.Context, userID, libra
}
// 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
// GetUserVisibleLibraries SQL (COALESCE(lv.is_visible, true) —
// 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)
if err != nil {
return nil, nil, fmt.Errorf("failed to check library access: %w", err)
}
set := make(map[string]bool, len(rows))
ids := make([]pgtype.UUID, 0, len(rows))
for _, lib := range rows {
if !lib.ID.Valid {
continue
}
set[uuid.UUID(lib.ID.Bytes).String()] = true
ids = append(ids, lib.ID)
}
return set, ids, nil
}
func (s *LibraryService) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]database.GetUserVisibleLibrariesRow, error) {
return s.db.GetUserVisibleLibraries(ctx, userID)
}