Files
sendewerk/src/routes/fundus/+page.server.ts
T

161 lines
5.3 KiB
TypeScript

import { fail, redirect } from '@sveltejs/kit';
import type { Actions, PageServerLoad } from './$types';
import { requireUser } from '#lib/server/auth.js';
import {
createPiece,
deletePieceTemplate,
duplicatePiece,
getPiece,
listPieceTemplates,
savePiece,
setPieceArchived,
setPieceDeleted,
setPieceFavorite,
uploadPieceImage,
type EditablePieceStatus,
type PieceEditor
} from '#lib/server/content.js';
import { fundusSearch, loadFundusWorkspace } from '#lib/server/fundus-workspace.js';
export const load: PageServerLoad = ({ locals, url }) => {
requireUser(locals.user);
const workspace = loadFundusWorkspace(url);
const selectedId = url.searchParams.get('selected') ?? workspace.pieces[0]?.id ?? '';
return {
...workspace,
selectedPiece: workspace.pieces.some((piece) => piece.id === selectedId)
? getPiece(selectedId)
: null,
templates: listPieceTemplates()
};
};
function preservedInput(piece: PieceEditor, data: FormData) {
return {
...piece,
title: String(data.get('title') || ''),
summary: String(data.get('summary') || ''),
status: String(data.get('status') || piece.status) as EditablePieceStatus,
formatId: String(data.get('formatId') || '') || null,
durationSeconds: Math.round(Number(data.get('durationMinutes')) * 60),
intro: String(data.get('intro') || ''),
moderationNotes: String(data.get('moderationNotes') || ''),
topicIds: piece.topicIds,
categoryIds: piece.categoryIds,
sources: piece.sources,
tools: piece.tools.map((tool) => ({
toolId: tool.toolId,
workUrl: tool.workUrl,
note: tool.note
}))
};
}
function actionError(cause: unknown) {
const code = cause instanceof Error ? cause.message : '';
if (code === 'CONFLICT') return 'Das Piece wurde inzwischen geändert. Bitte Seite neu laden.';
if (code === 'NOT_FOUND') return 'Das Piece wurde nicht gefunden.';
return 'Die Aktion konnte nicht ausgeführt werden.';
}
export const actions = {
create: async ({ locals, request, url }) => {
requireUser(locals.user);
const data = await request.formData();
let id: string;
try {
id = createPiece(String(data.get('template') || 'blank'));
} catch (cause) {
return fail(400, { intent: 'create', error: actionError(cause) });
}
redirect(303, `/fundus/${id}${fundusSearch(url)}`);
},
deleteTemplate: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
try {
deletePieceTemplate(String(data.get('templateId') || ''), Number(data.get('revision')));
return { intent: 'deleteTemplate', success: 'Vorlage gelöscht.' };
} catch (cause) {
return fail(409, { intent: 'deleteTemplate', error: actionError(cause) });
}
},
duplicate: async ({ locals, request, url }) => {
requireUser(locals.user);
const data = await request.formData();
let id: string;
try {
id = await duplicatePiece(String(data.get('pieceId') || ''));
} catch (cause) {
return fail(400, { intent: 'duplicate', error: actionError(cause) });
}
redirect(303, `/fundus/${id}${fundusSearch(url)}`);
},
archive: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
try {
setPieceArchived(String(data.get('pieceId') || ''), Number(data.get('revision')), true);
return { intent: 'archive', success: 'Piece archiviert.' };
} catch (cause) {
return fail(409, { intent: 'archive', error: actionError(cause) });
}
},
favorite: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
try {
setPieceFavorite(String(data.get('pieceId') || ''), data.get('favorite') === '1');
return { intent: 'favorite', success: 'Favorit aktualisiert.' };
} catch (cause) {
return fail(404, { intent: 'favorite', error: actionError(cause) });
}
},
delete: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
try {
setPieceDeleted(String(data.get('pieceId') || ''), Number(data.get('revision')), true);
return {
intent: 'delete',
success: 'Piece gelöscht. Bestehende Streamfassungen bleiben erhalten.'
};
} catch (cause) {
return fail(409, { intent: 'delete', error: actionError(cause) });
}
},
quickSave: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
const id = String(data.get('pieceId') || '');
const piece = getPiece(id);
if (!piece || piece.status === 'archived')
return fail(404, { intent: 'quickSave', error: 'Das Piece wurde nicht gefunden.' });
try {
const saved = savePiece(id, Number(data.get('revision')), preservedInput(piece, data));
return { intent: 'quickSave', success: 'Schnelländerungen gespeichert.', ...saved };
} catch (cause) {
return fail(409, { intent: 'quickSave', error: actionError(cause) });
}
},
quickUpload: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
const image = data.get('image');
if (!(image instanceof File))
return fail(400, { intent: 'quickUpload', error: 'Bitte ein Bild auswählen.' });
try {
await uploadPieceImage(
String(data.get('pieceId') || ''),
Number(data.get('revision')),
image,
String(data.get('altText') || ''),
false
);
return { intent: 'quickUpload', success: 'Bild hochgeladen.' };
} catch (cause) {
return fail(400, { intent: 'quickUpload', error: actionError(cause) });
}
}
} satisfies Actions;