sidecar: scoped labels + counts proxy (fixes cross-user label leak)

- New GET /api/sidecar/labels — proxies PP's labels, recalculates
  PhotoCount per user's BasePath via DB query
- New GET /api/sidecar/counts — returns user-scoped sidebar badges
  (all, review, archived, private, photos, videos, favorites)
- Fixed auth middleware to expose userUID and basePath on context
- Fixed ppClient.resolveSession — uses correct endpoint
  (GET /api/v1/session, not /api/v1/session/{token}) and correct
  JSON field names (UID, Name instead of UserUID, UserName)
- Frontend: listLabels now calls /api/sidecar/labels instead of /api/v1/labels
This commit is contained in:
2026-06-06 19:23:22 +02:00
parent 4c08eba27a
commit 8f97590d9f
6 changed files with 530 additions and 21 deletions

View File

@@ -672,8 +672,13 @@ export async function listLabels(): Promise<PpLabel[]> {
// them out and the tags page silently shows only ~40% of the user's
// real tag set. `count` bumped to 1000 so a moderately tagged library
// returns the full list in one round-trip.
const { data } = await http.get<PpLabel[]>('/labels', {
params: { count: 1000, order: 'count', all: true }
//
// Uses the sidecar proxy (/api/sidecar/labels) instead of PhotoPrism's
// /api/v1/labels so PhotoCount reflects only photos under the user's
// BasePath. The sidecar proxies the request through to PP then
// post-filters each label's count.
const { data } = await http.get<PpLabel[]>('/api/sidecar/labels', {
params: { count: 1000, order: 'count', all: true, perPage: 1000 }
});
return filterByUserPhotos(data, (l) => `label:${l.Slug}`);
}