import { Request, Response } from 'express'; import { z } from 'zod'; import personalEquipmentService from '../services/personalEquipment.service'; import logger from '../utils/logger'; const uuidString = z.string().regex( /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, 'Ungültige UUID', ); const isoDate = z.string().regex( /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/, 'Erwartet ISO-Datum im Format YYYY-MM-DD', ); const ZustandEnum = z.enum(['gut', 'beschaedigt', 'abgaengig', 'verloren']); const EigenschaftInput = z.object({ eigenschaft_id: z.number().int().positive().nullable().optional(), name: z.string().min(1).max(200), wert: z.string().max(500), }); const CreateSchema = z.object({ bezeichnung: z.string().min(1).max(200), kategorie: z.string().max(100).optional(), artikel_id: z.number().int().positive().optional(), user_id: uuidString.optional(), benutzer_name: z.string().max(200).optional(), groesse: z.string().max(50).optional(), seriennummer: z.string().max(100).optional(), inventarnummer: z.string().max(50).optional(), anschaffung_datum: isoDate.optional(), zustand: ZustandEnum.optional(), notizen: z.string().max(2000).optional(), eigenschaften: z.array(EigenschaftInput).optional(), }); const UpdateSchema = z.object({ bezeichnung: z.string().min(1).max(200).optional(), kategorie: z.string().max(100).nullable().optional(), artikel_id: z.number().int().positive().nullable().optional(), user_id: uuidString.nullable().optional(), benutzer_name: z.string().max(200).nullable().optional(), groesse: z.string().max(50).nullable().optional(), seriennummer: z.string().max(100).nullable().optional(), inventarnummer: z.string().max(50).nullable().optional(), anschaffung_datum: isoDate.nullable().optional(), zustand: ZustandEnum.optional(), notizen: z.string().max(2000).nullable().optional(), eigenschaften: z.array(EigenschaftInput).nullable().optional(), }); function isValidUUID(s: string): boolean { return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s); } class PersonalEquipmentController { async list(req: Request, res: Response): Promise { try { const filters: Record = {}; if (req.query.user_id) filters.userId = String(req.query.user_id); if (req.query.kategorie) filters.kategorie = String(req.query.kategorie); if (req.query.zustand) filters.zustand = String(req.query.zustand); const items = await personalEquipmentService.getAll(filters); res.status(200).json({ success: true, data: items }); } catch (error) { logger.error('personalEquipment.list error', { error }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' }); } } async getMy(req: Request, res: Response): Promise { try { const items = await personalEquipmentService.getByUserId(req.user!.id); res.status(200).json({ success: true, data: items }); } catch (error) { logger.error('personalEquipment.getMy error', { error }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' }); } } async getByUser(req: Request, res: Response): Promise { try { const { userId } = req.params as Record; if (!isValidUUID(userId)) { res.status(400).json({ success: false, message: 'Ungültige User-ID' }); return; } const items = await personalEquipmentService.getByUserId(userId); res.status(200).json({ success: true, data: items }); } catch (error) { logger.error('personalEquipment.getByUser error', { error }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' }); } } async getById(req: Request, res: Response): Promise { try { const { id } = req.params as Record; if (!isValidUUID(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; } const item = await personalEquipmentService.getById(id); if (!item) { res.status(404).json({ success: false, message: 'Nicht gefunden' }); return; } res.status(200).json({ success: true, data: item }); } catch (error) { logger.error('personalEquipment.getById error', { error }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' }); } } async create(req: Request, res: Response): Promise { try { const parsed = CreateSchema.safeParse(req.body); if (!parsed.success) { res.status(400).json({ success: false, message: 'Validierungsfehler', errors: parsed.error.flatten().fieldErrors }); return; } const item = await personalEquipmentService.create(parsed.data, req.user!.id); res.status(201).json({ success: true, data: item }); } catch (error) { logger.error('personalEquipment.create error', { error }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht erstellt werden' }); } } async update(req: Request, res: Response): Promise { try { const { id } = req.params as Record; if (!isValidUUID(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; } const parsed = UpdateSchema.safeParse(req.body); if (!parsed.success) { res.status(400).json({ success: false, message: 'Validierungsfehler', errors: parsed.error.flatten().fieldErrors }); return; } if (Object.keys(parsed.data).length === 0) { res.status(400).json({ success: false, message: 'Kein Feld zum Aktualisieren angegeben' }); return; } const item = await personalEquipmentService.update(id, parsed.data as any); if (!item) { res.status(404).json({ success: false, message: 'Nicht gefunden' }); return; } res.status(200).json({ success: true, data: item }); } catch (error: any) { if (error?.message === 'No fields to update') { res.status(400).json({ success: false, message: 'Kein Feld zum Aktualisieren angegeben' }); return; } logger.error('personalEquipment.update error', { error, id: req.params.id }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht aktualisiert werden' }); } } async delete(req: Request, res: Response): Promise { try { const { id } = req.params as Record; if (!isValidUUID(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; } const deleted = await personalEquipmentService.delete(id); if (!deleted) { res.status(404).json({ success: false, message: 'Nicht gefunden' }); return; } res.status(200).json({ success: true, message: 'Persönliche Ausrüstung gelöscht' }); } catch (error) { logger.error('personalEquipment.delete error', { error, id: req.params.id }); res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht gelöscht werden' }); } } } export default new PersonalEquipmentController();