Files
familienarchiv/frontend/src/routes/persons/+page.server.ts
Marcel 3a758393bf refactor(shared): extract hasWriteAll(locals) permission helper
The locals.user.groups.some(...WRITE_ALL) derivation was copy-pasted across
the persons directory, persons review and the two document loaders touched by
this PR. Extract a single tested hasWriteAll(locals) helper in
$lib/shared/server and reuse it, removing the ad-hoc casts.

Refs #667

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:14:00 +02:00

78 lines
2.4 KiB
TypeScript

import { error } from '@sveltejs/kit';
import { createApiClient } from '$lib/shared/api.server';
import { getErrorMessage } from '$lib/shared/errors';
import { hasWriteAll } from '$lib/shared/server/permissions';
const PAGE_SIZE = 50;
type PersonType = 'PERSON' | 'INSTITUTION' | 'GROUP';
function parseType(raw: string | null): PersonType | undefined {
return raw === 'PERSON' || raw === 'INSTITUTION' || raw === 'GROUP' ? raw : undefined;
}
export async function load({ url, fetch, locals }) {
const q = url.searchParams.get('q') || '';
const page = Math.max(0, Number.parseInt(url.searchParams.get('page') ?? '0', 10) || 0);
const review =
url.searchParams.get('review') === '1' || url.searchParams.get('review') === 'true';
const type = parseType(url.searchParams.get('type'));
const familyOnly = url.searchParams.get('familyOnly') === 'true';
const hasDocuments = url.searchParams.get('hasDocuments') === 'true';
const api = createApiClient(fetch);
const canWrite = hasWriteAll(locals);
const filters = {
q: q || undefined,
type,
familyOnly: familyOnly || undefined,
hasDocuments: hasDocuments || undefined,
review: review || undefined,
page,
size: PAGE_SIZE
};
// The "Zu prüfen (N)" link count is the totalElements of a provisional-only query. A size=1
// page keeps the extra request cheap — we only need the count, not the rows.
const [personsResult, statsResult, reviewCountResult] = await Promise.all([
api.GET('/api/persons', { params: { query: filters } }),
api.GET('/api/stats', {}),
canWrite
? api.GET('/api/persons', { params: { query: { provisional: true, review: true, size: 1 } } })
: Promise.resolve(null)
]);
if (!personsResult.response.ok) {
throw error(personsResult.response.status, getErrorMessage(undefined));
}
const result = personsResult.data!;
const stats = statsResult.response.ok
? {
totalPersons: statsResult.data!.totalPersons ?? 0,
totalDocuments: statsResult.data!.totalDocuments ?? 0
}
: { totalPersons: 0, totalDocuments: 0 };
const needsReviewCount =
reviewCountResult && reviewCountResult.response.ok
? (reviewCountResult.data!.totalElements ?? 0)
: 0;
return {
persons: result.items,
totalElements: result.totalElements,
totalPages: result.totalPages,
pageNumber: result.pageNumber,
pageSize: result.pageSize,
filters: { type, familyOnly, hasDocuments, review },
needsReviewCount,
stats,
q,
canWrite
};
}