HTTP-Endpunkte und Anwendungsaufbau
Eingaben werden mit zod validiert, jede aendernde Aktion schreibt ins Audit-Log. Beim ersten Start entsteht ein Administrator samt Startwerten fuer die Produkterkennung; solange ein Erstpasswort gilt, bleiben schreibende Wege bis auf den Passwortwechsel gesperrt. Nicht-API-Pfade fallen auf die SPA zurueck, damit Deep-Links funktionieren.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { z } from 'zod';
|
||||
import { CreditKind } from '@prisma/client';
|
||||
import { requireAdmin, requireEditor } from '../auth/guard.js';
|
||||
import {
|
||||
bookAdjustment,
|
||||
bookCcPackage,
|
||||
bookKulanz,
|
||||
bookRedesignPackage,
|
||||
reverseGroup,
|
||||
} from '../services/credits.js';
|
||||
import { contextOf, idParam, optionalNote, parseWith } from './helpers.js';
|
||||
|
||||
const noteBody = z.object({ note: optionalNote });
|
||||
|
||||
export async function creditRoutes(app: FastifyInstance): Promise<void> {
|
||||
app.post('/api/players/:id/credits/cc-package', { preHandler: requireEditor }, async (request) => {
|
||||
const { id } = parseWith(idParam, request.params);
|
||||
const body = parseWith(noteBody, request.body ?? {});
|
||||
return bookCcPackage(id, contextOf(request), { note: body.note });
|
||||
});
|
||||
|
||||
app.post(
|
||||
'/api/players/:id/credits/redesign-package',
|
||||
{ preHandler: requireEditor },
|
||||
async (request) => {
|
||||
const { id } = parseWith(idParam, request.params);
|
||||
const body = parseWith(noteBody, request.body ?? {});
|
||||
return bookRedesignPackage(id, contextOf(request), { note: body.note });
|
||||
},
|
||||
);
|
||||
|
||||
app.post('/api/players/:id/credits/kulanz', { preHandler: requireEditor }, async (request) => {
|
||||
const { id } = parseWith(idParam, request.params);
|
||||
const body = parseWith(noteBody, request.body ?? {});
|
||||
return bookKulanz(id, contextOf(request), { note: body.note });
|
||||
});
|
||||
|
||||
app.post('/api/players/:id/credits/adjustment', { preHandler: requireAdmin }, async (request) => {
|
||||
const { id } = parseWith(idParam, request.params);
|
||||
const body = parseWith(
|
||||
z.object({
|
||||
kind: z.nativeEnum(CreditKind),
|
||||
amount: z.number().int().refine((v) => v !== 0, 'Betrag darf nicht 0 sein'),
|
||||
note: z.string().trim().min(1, 'Eine Begruendung ist Pflicht').max(500),
|
||||
}),
|
||||
request.body,
|
||||
);
|
||||
return bookAdjustment(id, body.kind, body.amount, body.note, contextOf(request));
|
||||
});
|
||||
|
||||
app.post('/api/credits/:id/reverse', { preHandler: requireEditor }, async (request) => {
|
||||
const { id } = parseWith(idParam, request.params);
|
||||
const body = parseWith(
|
||||
z.object({ reason: z.string().trim().min(1, 'Eine Begruendung ist Pflicht').max(500) }),
|
||||
request.body,
|
||||
);
|
||||
return reverseGroup(id, body.reason, contextOf(request));
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user