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.
This commit is contained in:
@@ -24,6 +24,6 @@ export function mapUserRecord(r: Record<string, unknown>): UserFromRecord {
|
|||||||
tasgrid: bool(r, 'TasGrid', 'tasgrid'),
|
tasgrid: bool(r, 'TasGrid', 'tasgrid'),
|
||||||
stackq: bool(r, 'Stackq', 'stackq'),
|
stackq: bool(r, 'Stackq', 'stackq'),
|
||||||
hrm: bool(r, 'HRM', 'hrm', 'Hrm'),
|
hrm: bool(r, 'HRM', 'hrm', 'Hrm'),
|
||||||
training_admin: bool(r, 'training_admin', 'TrainingAdmin', 'trainingAdmin')
|
training_admin: bool(r, 'training_admin', 'TrainingAdmin', 'trainingAdmin', 'Admin')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,12 +46,10 @@ export const load: PageServerLoad = async ({ locals }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const canUpload = Boolean(user?.training_admin);
|
const canUpload = Boolean(user?.training_admin);
|
||||||
const isAdmin = Boolean((user as any)?.Admin);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
videos,
|
videos,
|
||||||
canUpload,
|
canUpload
|
||||||
isAdmin
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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');
|
throw redirect(303, '/training');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,12 +20,11 @@
|
|||||||
};
|
};
|
||||||
} | null;
|
} | null;
|
||||||
|
|
||||||
let { data, form }: { data: { videos: TrainingVideo[]; canUpload: boolean; isAdmin: boolean }; form: UploadFormState } =
|
let { data, form }: { data: { videos: TrainingVideo[]; canUpload: boolean }; form: UploadFormState } =
|
||||||
$props();
|
$props();
|
||||||
|
|
||||||
const videos = $derived(data.videos);
|
const videos = $derived(data.videos);
|
||||||
const canUpload = $derived(data.canUpload);
|
const canUpload = $derived(data.canUpload);
|
||||||
const isAdmin = $derived(data.isAdmin);
|
|
||||||
|
|
||||||
function formatDate(created: string) {
|
function formatDate(created: string) {
|
||||||
if (!created) return '';
|
if (!created) return '';
|
||||||
@@ -88,11 +87,6 @@
|
|||||||
|
|
||||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||||
<h1 class="text-2xl font-semibold">Training</h1>
|
<h1 class="text-2xl font-semibold">Training</h1>
|
||||||
{#if isAdmin}
|
|
||||||
<a href="/training/admin">
|
|
||||||
<Button variant="outline" size="sm">Admin</Button>
|
|
||||||
</a>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if canUpload}
|
{#if canUpload}
|
||||||
@@ -162,9 +156,26 @@
|
|||||||
<Card.Title class="truncate">{video.title}</Card.Title>
|
<Card.Title class="truncate">{video.title}</Card.Title>
|
||||||
<Card.Description class="text-xs">{formatDate(video.created)}</Card.Description>
|
<Card.Description class="text-xs">{formatDate(video.created)}</Card.Description>
|
||||||
</div>
|
</div>
|
||||||
<a href={`/training/${video.id}`} aria-label="Open training video">
|
<div class="flex items-center gap-2">
|
||||||
<Button variant="outline" size="sm">Open</Button>
|
<a href={`/training/${video.id}`} aria-label="Open training video">
|
||||||
</a>
|
<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.Header>
|
||||||
<Card.Content class="flex flex-1 flex-col gap-3">
|
<Card.Content class="flex flex-1 flex-col gap-3">
|
||||||
{#if video.videoUrl}
|
{#if video.videoUrl}
|
||||||
|
|||||||
@@ -21,7 +21,15 @@ export const load: PageServerLoad = async ({ locals }) => {
|
|||||||
throw redirect(303, '/login');
|
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.');
|
throw error(403, 'You do not have access to training admin.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +73,13 @@ export const actions: Actions = {
|
|||||||
throw redirect(303, '/login');
|
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, {
|
return fail(403, {
|
||||||
error: 'You do not have permission to manage training videos.'
|
error: 'You do not have permission to manage training videos.'
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user