Refactor training page and admin access control. Updated user role checks to include 'training_admin' for permissions, removed unnecessary admin checks from the training page, and added video deletion functionality with appropriate error handling. Improved UI for video management actions.
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m13s

This commit is contained in:
eewing
2026-03-18 08:12:47 -05:00
parent ab226470a1
commit 50d8fd326f
4 changed files with 75 additions and 16 deletions
+1 -1
View File
@@ -24,6 +24,6 @@ export function mapUserRecord(r: Record<string, unknown>): UserFromRecord {
tasgrid: bool(r, 'TasGrid', 'tasgrid'),
stackq: bool(r, 'Stackq', 'stackq'),
hrm: bool(r, 'HRM', 'hrm', 'Hrm'),
training_admin: bool(r, 'training_admin', 'TrainingAdmin', 'trainingAdmin')
training_admin: bool(r, 'training_admin', 'TrainingAdmin', 'trainingAdmin', 'Admin')
};
}
+37 -3
View File
@@ -46,12 +46,10 @@ export const load: PageServerLoad = async ({ locals }) => {
});
const canUpload = Boolean(user?.training_admin);
const isAdmin = Boolean((user as any)?.Admin);
return {
videos,
canUpload,
isAdmin
canUpload
};
};
@@ -109,6 +107,42 @@ export const actions: Actions = {
});
}
throw redirect(303, '/training');
},
delete: async ({ request, locals }) => {
const user = locals.user;
if (!user) {
throw redirect(303, '/login');
}
if (!user.training_admin) {
return fail(403, {
error: 'You do not have permission to delete training videos.'
});
}
const formData = await request.formData();
const id = String(formData.get('id') ?? '').trim();
if (!id) {
return fail(400, {
error: 'Missing video id.'
});
}
try {
await locals.pb.collection(VIDEO_COLLECTION).delete(id);
} catch (e) {
const message =
e && typeof e === 'object' && 'message' in e
? String((e as { message: string }).message)
: 'Could not delete video.';
return fail(500, {
error: message
});
}
throw redirect(303, '/training');
}
};
+18 -7
View File
@@ -20,12 +20,11 @@
};
} | null;
let { data, form }: { data: { videos: TrainingVideo[]; canUpload: boolean; isAdmin: boolean }; form: UploadFormState } =
let { data, form }: { data: { videos: TrainingVideo[]; canUpload: boolean }; form: UploadFormState } =
$props();
const videos = $derived(data.videos);
const canUpload = $derived(data.canUpload);
const isAdmin = $derived(data.isAdmin);
function formatDate(created: string) {
if (!created) return '';
@@ -88,11 +87,6 @@
<div class="flex flex-wrap items-center justify-between gap-3">
<h1 class="text-2xl font-semibold">Training</h1>
{#if isAdmin}
<a href="/training/admin">
<Button variant="outline" size="sm">Admin</Button>
</a>
{/if}
</div>
{#if canUpload}
@@ -162,9 +156,26 @@
<Card.Title class="truncate">{video.title}</Card.Title>
<Card.Description class="text-xs">{formatDate(video.created)}</Card.Description>
</div>
<div class="flex items-center gap-2">
<a href={`/training/${video.id}`} aria-label="Open training video">
<Button variant="outline" size="sm">Open</Button>
</a>
{#if canUpload}
<form method="POST">
<input type="hidden" name="id" value={video.id} />
<Button
type="submit"
name="intent"
value="delete"
variant="destructive"
size="icon"
aria-label="Delete training video"
>
</Button>
</form>
{/if}
</div>
</Card.Header>
<Card.Content class="flex flex-1 flex-col gap-3">
{#if video.videoUrl}
+16 -2
View File
@@ -21,7 +21,15 @@ export const load: PageServerLoad = async ({ locals }) => {
throw redirect(303, '/login');
}
if (!(user as any)?.Admin) {
console.log('training/admin load user', user);
const isAdmin = Boolean(
(user as any)?.Admin ||
(user as any)?.admin ||
(user as any)?.training_admin
);
if (!isAdmin) {
throw error(403, 'You do not have access to training admin.');
}
@@ -65,7 +73,13 @@ export const actions: Actions = {
throw redirect(303, '/login');
}
if (!(user as any)?.Admin) {
const isAdmin = Boolean(
(user as any)?.Admin ||
(user as any)?.admin ||
(user as any)?.training_admin
);
if (!isAdmin) {
return fail(403, {
error: 'You do not have permission to manage training videos.'
});