import { randomUUID } from 'crypto'; import db from '../../db.js'; import { badRequest, UUID } from '../../lib/http.js'; import { mapMachine } from '../../lib/mappers.js'; const ALLOWED_LIST_STATUS = new Set([ '', 'PRUEFEN', 'VERSCHROTTET', 'SN_GEAENDERT', 'IN_BEARBEITUNG', 'UPDATE_RAUS', ]); function normalizeListStatus(v) { if (v == null || v === '') return ''; const s = String(v).trim(); return ALLOWED_LIST_STATUS.has(s) ? s : null; } /** @returns {{ ok: true, json: string | null } | { ok: false, message: string }} */ function parseExtrasField(extras) { if (extras === null || extras === '') { return { ok: true, json: null }; } if (typeof extras === 'object' && extras !== null) { try { return { ok: true, json: JSON.stringify(extras) }; } catch { return { ok: false, message: 'extras ist kein gültiges JSON-Objekt.' }; } } if (typeof extras === 'string') { try { JSON.parse(extras); return { ok: true, json: extras }; } catch { return { ok: false, message: 'extras ist kein gültiger JSON-String.' }; } } return { ok: false, message: 'extras hat ein ungültiges Format.' }; } export function registerMachineRoutes(api) { api.get('/machines', (_req, res) => { const rows = db .prepare('SELECT * FROM machines ORDER BY seriennummer ASC') .all(); res.json(rows.map(mapMachine)); }); api.post('/machines', (req, res) => { const b = req.body || {}; const { name, typ, seriennummer, standort, listStatus } = b; if (!name || !typ || !seriennummer || !standort) { return badRequest(res, 'Pflichtfelder fehlen.'); } const ls = normalizeListStatus(listStatus); if (ls === null) return badRequest(res, 'Ungültiger Listen-Status.'); let extrasJson = null; if (Object.prototype.hasOwnProperty.call(b, 'extras')) { const p = parseExtrasField(b.extras); if (!p.ok) return badRequest(res, p.message); extrasJson = p.json; } const id = randomUUID(); const row = db .prepare( `INSERT INTO machines (id, name, typ, seriennummer, standort, list_status, extras, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now')) RETURNING *`, ) .get(id, name, typ, seriennummer, standort, ls, extrasJson); res.status(201).json(mapMachine(row)); }); api.get('/machines/:id', (req, res) => { const { id } = req.params; if (!UUID.test(id)) return res.status(404).json({ message: 'Nicht gefunden' }); const row = db.prepare('SELECT * FROM machines WHERE id = ?').get(id); if (!row) return res.status(404).json({ message: 'Nicht gefunden' }); res.json(mapMachine(row)); }); api.put('/machines/:id', (req, res) => { const { id } = req.params; if (!UUID.test(id)) return res.status(404).json({ message: 'Nicht gefunden' }); const cur = db.prepare('SELECT * FROM machines WHERE id = ?').get(id); if (!cur) return res.status(404).json({ message: 'Nicht gefunden' }); const b = req.body || {}; const next = { name: b.name ?? cur.name, typ: b.typ ?? cur.typ, seriennummer: b.seriennummer ?? cur.seriennummer, standort: b.standort ?? cur.standort, }; let listStatusVal = cur.list_status ?? ''; if (Object.prototype.hasOwnProperty.call(b, 'listStatus')) { const ls = normalizeListStatus(b.listStatus); if (ls === null) return badRequest(res, 'Ungültiger Listen-Status.'); listStatusVal = ls; } let extrasJson = cur.extras; if (Object.prototype.hasOwnProperty.call(b, 'extras')) { const p = parseExtrasField(b.extras); if (!p.ok) return badRequest(res, p.message); extrasJson = p.json; } const row = db .prepare( `UPDATE machines SET name = ?, typ = ?, seriennummer = ?, standort = ?, list_status = ?, extras = ?, updated_at = datetime('now') WHERE id = ? RETURNING *`, ) .get( next.name, next.typ, next.seriennummer, next.standort, listStatusVal, extrasJson, id, ); res.json(mapMachine(row)); }); api.delete('/machines/:id', (req, res) => { const { id } = req.params; if (!UUID.test(id)) return res.status(404).json({ message: 'Nicht gefunden' }); const cur = db.prepare('SELECT * FROM machines WHERE id = ?').get(id); if (!cur) return res.status(404).json({ message: 'Nicht gefunden' }); const tc = db .prepare('SELECT COUNT(*) AS c FROM tickets WHERE machine_id = ?') .get(id); if (tc.c > 0) { return res.status(409).json({ message: 'Maschine kann nicht gelöscht werden: Es existieren noch zugeordnete Tickets.', }); } const row = db .prepare('DELETE FROM machines WHERE id = ? RETURNING *') .get(id); res.json(mapMachine(row)); }); }