161 lines
5.3 KiB
TypeScript
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;
|