Timeline: curator event create/edit forms (#781) #832
@@ -1,3 +1,5 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
/**
|
||||
* Server-side permission predicates derived from the authenticated user in `locals`.
|
||||
*
|
||||
@@ -12,3 +14,13 @@ type PermissionLocals = {
|
||||
export function hasWriteAll(locals: PermissionLocals): boolean {
|
||||
return locals.user?.groups?.some((group) => group.permissions.includes('WRITE_ALL')) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a 403 unless the user holds WRITE_ALL. Anonymous users are rejected too
|
||||
* — `hasWriteAll` returns false for a null user, so a single check covers both
|
||||
* the unauthenticated and the under-privileged case. Server-side gate; the
|
||||
* frontend canWrite flag only hides entry-point buttons.
|
||||
*/
|
||||
export function requireWriteAll(locals: PermissionLocals): void {
|
||||
if (!hasWriteAll(locals)) throw error(403, 'Forbidden');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { error, fail, redirect } from '@sveltejs/kit';
|
||||
import { createApiClient, extractErrorCode } from '$lib/shared/api.server';
|
||||
import { getErrorMessage } from '$lib/shared/errors';
|
||||
import { hasWriteAll } from '$lib/shared/server/permissions';
|
||||
import { requireWriteAll } from '$lib/shared/server/permissions';
|
||||
import {
|
||||
parseEventForm,
|
||||
validateEventForm,
|
||||
@@ -20,12 +20,7 @@ export async function load({
|
||||
url: URL;
|
||||
fetch: typeof globalThis.fetch;
|
||||
}) {
|
||||
// Null-user guard first — avoids a TypeError on locals.user.groups for an
|
||||
// unauthenticated request that reaches the route.
|
||||
if (!locals.user) throw error(403, 'Forbidden');
|
||||
// WRITE_ALL check mirrors Permission.WRITE_ALL — server-side gate; frontend
|
||||
// canWrite flag is for hiding entry-point buttons only.
|
||||
if (!hasWriteAll(locals)) throw error(403, 'Forbidden');
|
||||
requireWriteAll(locals);
|
||||
|
||||
const api = createApiClient(fetch);
|
||||
const result = await api.GET('/api/timeline/events/{id}', {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { error, fail, redirect } from '@sveltejs/kit';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import { createApiClient, extractErrorCode } from '$lib/shared/api.server';
|
||||
import { getErrorMessage } from '$lib/shared/errors';
|
||||
import { hasWriteAll } from '$lib/shared/server/permissions';
|
||||
import { requireWriteAll } from '$lib/shared/server/permissions';
|
||||
import {
|
||||
parseEventForm,
|
||||
validateEventForm,
|
||||
@@ -20,12 +20,7 @@ export async function load({
|
||||
url: URL;
|
||||
fetch: typeof globalThis.fetch;
|
||||
}) {
|
||||
// Null-user guard first — avoids a TypeError on locals.user.groups for an
|
||||
// unauthenticated request that reaches the route.
|
||||
if (!locals.user) throw error(403, 'Forbidden');
|
||||
// WRITE_ALL check mirrors Permission.WRITE_ALL — server-side gate; frontend
|
||||
// canWrite flag is for hiding entry-point buttons only.
|
||||
if (!hasWriteAll(locals)) throw error(403, 'Forbidden');
|
||||
requireWriteAll(locals);
|
||||
|
||||
const api = createApiClient(fetch);
|
||||
const personId = url.searchParams.get('personId');
|
||||
|
||||
Reference in New Issue
Block a user