128 lines
4.2 KiB
TypeScript
128 lines
4.2 KiB
TypeScript
import { randomUUID } from 'node:crypto';
|
|
import { error, fail } from '@sveltejs/kit';
|
|
import type { Actions, PageServerLoad } from './$types';
|
|
import { requireUser } from '#lib/server/auth.js';
|
|
import {
|
|
completeCurrent,
|
|
getLiveView,
|
|
goBack,
|
|
issuePresentationAccess,
|
|
moveOpenUsage,
|
|
presentUsage,
|
|
skipCurrent,
|
|
startOrResumeLive
|
|
} from '#lib/server/live.js';
|
|
import { listShows } from '#lib/server/shows.js';
|
|
|
|
function text(data: FormData, name: string) {
|
|
return String(data.get(name) || '');
|
|
}
|
|
|
|
function actionError(cause: unknown) {
|
|
const code = cause instanceof Error ? cause.message : '';
|
|
if (code === 'CONFLICT')
|
|
return {
|
|
status: 409,
|
|
error: 'Der Live-Stand wurde bereits geändert. Die Ansicht wurde erneuert.'
|
|
};
|
|
if (code === 'NO_CURRENT') return { status: 409, error: 'Es ist kein aktuelles Piece aktiv.' };
|
|
if (code === 'NO_PREVIOUS') return { status: 409, error: 'Es gibt kein vorheriges Piece.' };
|
|
if (code === 'LIVE_ORDER_LOCKED')
|
|
return {
|
|
status: 409,
|
|
error: 'Nur offene Pieces hinter dem aktuellen Stand können sortiert werden.'
|
|
};
|
|
if (code === 'SHOW_COMPLETED')
|
|
return { status: 409, error: 'Abgeschlossene Sendungen können nicht live gesteuert werden.' };
|
|
if (code === 'NOT_FOUND')
|
|
return { status: 404, error: 'Sendung oder Piece wurde nicht gefunden.' };
|
|
if (code.startsWith('INVALID_')) return { status: 400, error: 'Die Live-Aktion ist ungültig.' };
|
|
return { status: 500, error: 'Die Live-Aktion konnte nicht gespeichert werden.' };
|
|
}
|
|
|
|
function attempt(intent: string, operation: () => unknown) {
|
|
try {
|
|
return { intent, success: true, result: operation() };
|
|
} catch (cause) {
|
|
const problem = actionError(cause);
|
|
return fail(problem.status, { intent, ...problem });
|
|
}
|
|
}
|
|
|
|
export const load: PageServerLoad = ({ locals, url }) => {
|
|
requireUser(locals.user);
|
|
const showId = url.searchParams.get('show') || listShows()[0]?.id;
|
|
if (!showId) error(404, 'Keine Sendung vorhanden');
|
|
try {
|
|
return { live: getLiveView(showId), commandId: randomUUID() };
|
|
} catch (cause) {
|
|
if (cause instanceof Error && cause.message === 'NOT_FOUND')
|
|
error(404, 'Sendung nicht gefunden');
|
|
throw cause;
|
|
}
|
|
};
|
|
|
|
export const actions = {
|
|
start: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
return attempt('start', () =>
|
|
startOrResumeLive(text(data, 'showId'), text(data, 'commandId'), Number(data.get('revision')))
|
|
);
|
|
},
|
|
complete: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
return attempt('complete', () =>
|
|
completeCurrent(text(data, 'showId'), text(data, 'commandId'), Number(data.get('revision')))
|
|
);
|
|
},
|
|
skip: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
return attempt('skip', () =>
|
|
skipCurrent(text(data, 'showId'), text(data, 'commandId'), Number(data.get('revision')))
|
|
);
|
|
},
|
|
back: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
return attempt('back', () =>
|
|
goBack(text(data, 'showId'), text(data, 'commandId'), Number(data.get('revision')))
|
|
);
|
|
},
|
|
present: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
return attempt('present', () =>
|
|
presentUsage(
|
|
text(data, 'showId'),
|
|
text(data, 'usageId') || null,
|
|
text(data, 'commandId'),
|
|
Number(data.get('revision'))
|
|
)
|
|
);
|
|
},
|
|
moveUsage: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
return attempt('moveUsage', () =>
|
|
moveOpenUsage(text(data, 'showId'), text(data, 'usageId'), Number(data.get('showRevision')), {
|
|
sectionId: text(data, 'sectionId') || null,
|
|
position: Number(data.get('position'))
|
|
})
|
|
);
|
|
},
|
|
createOutput: async ({ locals, request }) => {
|
|
requireUser(locals.user);
|
|
const data = await request.formData();
|
|
try {
|
|
const token = issuePresentationAccess(text(data, 'showId'));
|
|
return { intent: 'createOutput', success: true, outputUrl: `/heinzlive/${token}` };
|
|
} catch (cause) {
|
|
const problem = actionError(cause);
|
|
return fail(problem.status, { intent: 'createOutput', ...problem });
|
|
}
|
|
}
|
|
} satisfies Actions;
|