const express = require('express'); const router = express.Router(); const db = require('../db'); const { requireAdmin } = require('../middleware/auth'); // Alle Admin-Routen erfordern Admin-Zugriff router.use(requireAdmin); // ── Stats ───────────────────────────────────────────── router.get('/stats', async (req, res) => { try { const [[{ ghosts }]] = await db.execute('SELECT COUNT(*) as ghosts FROM ghosts'); const [[{ total }]] = await db.execute('SELECT COUNT(*) as total FROM submissions'); const [[{ pending }]] = await db.execute("SELECT COUNT(*) as pending FROM submissions WHERE status='pending'"); const [[{ approved }]]= await db.execute("SELECT COUNT(*) as approved FROM submissions WHERE status='approved'"); const [[{ rejected }]]= await db.execute("SELECT COUNT(*) as rejected FROM submissions WHERE status='rejected'"); res.json({ ghosts, total, pending, approved, rejected }); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } }); // ── Ghosts CRUD ─────────────────────────────────────── // Geist erstellen router.post('/ghosts', async (req, res) => { const { id, name, evidence, sanity, hunt, sanity_special, tip, description, tells } = req.body; if (!id || !name || !Array.isArray(evidence) || evidence.length !== 3) { return res.status(400).json({ error: 'Ungültige Daten (id, name, genau 3 evidence erforderlich)' }); } try { await db.query( `INSERT INTO ghosts (id, name, evidence, sanity, hunt, sanity_special, tip, description, tells, updated_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, name, JSON.stringify(evidence), sanity||50, hunt||'mid', sanity_special||'', tip||'', description||'', JSON.stringify(tells||[]), req.user.username] ); res.json({ ok: true }); } catch (e) { if (e.code === 'ER_DUP_ENTRY') return res.status(409).json({ error: 'ID bereits vorhanden' }); console.error(e); res.status(500).json({ error: 'DB-Fehler' }); } }); // Geist bearbeiten router.put('/ghosts/:id', async (req, res) => { const { name, evidence, sanity, hunt, sanity_special, tip, description, tells } = req.body; if (!name || !Array.isArray(evidence) || evidence.length !== 3) { return res.status(400).json({ error: 'Ungültige Daten' }); } try { const result = await db.query( `UPDATE ghosts SET name=?, evidence=?, sanity=?, hunt=?, sanity_special=?, tip=?, description=?, tells=?, updated_by=? WHERE id=?`, [name, JSON.stringify(evidence), sanity||50, hunt||'mid', sanity_special||'', tip||'', description||'', JSON.stringify(tells||[]), req.user.username, req.params.id] ); if (result.affectedRows === 0) return res.status(404).json({ error: 'Geist nicht gefunden' }); res.json({ ok: true }); } catch (e) { console.error(e); res.status(500).json({ error: 'DB-Fehler' }); } }); // Geist löschen router.delete('/ghosts/:id', async (req, res) => { try { const result = await db.query('DELETE FROM ghosts WHERE id=?', [req.params.id]); if (result.affectedRows === 0) return res.status(404).json({ error: 'Geist nicht gefunden' }); res.json({ ok: true }); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } }); // ── Submissions ─────────────────────────────────────── // Alle Submissions laden (mit Filter) router.get('/submissions', async (req, res) => { const { status } = req.query; try { const rows = status ? await db.query('SELECT * FROM submissions WHERE status=? ORDER BY created_at DESC', [status]) : await db.query('SELECT * FROM submissions ORDER BY created_at DESC'); res.json(rows); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } }); // Submission reviewen (approve/reject) router.patch('/submissions/:id', async (req, res) => { const { status, admin_note } = req.body; if (!['approved','rejected'].includes(status)) return res.status(400).json({ error: 'Status muss approved oder rejected sein' }); try { await db.query( `UPDATE submissions SET status=?, admin_note=?, reviewed_at=NOW(), reviewed_by=? WHERE id=?`, [status, admin_note||'', req.user.username, req.params.id] ); res.json({ ok: true }); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } }); // ── Admin Whitelist ─────────────────────────────────── // Whitelist laden router.get('/whitelist', async (req, res) => { try { const rows = await db.query('SELECT * FROM admin_whitelist ORDER BY added_at ASC'); res.json(rows); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } }); // Admin hinzufügen router.post('/whitelist', async (req, res) => { const { discord_id, discord_username } = req.body; if (!discord_id || discord_id.length < 10) return res.status(400).json({ error: 'Ungültige Discord ID' }); try { await db.query( 'INSERT INTO admin_whitelist (discord_id, discord_username, added_by) VALUES (?,?,?)', [discord_id.trim(), discord_username||discord_id, req.user.username] ); res.json({ ok: true }); } catch (e) { if (e.code === 'ER_DUP_ENTRY') return res.status(409).json({ error: 'Bereits in der Whitelist' }); res.status(500).json({ error: 'DB-Fehler' }); } }); // Admin entfernen (kann sich nicht selbst entfernen) router.delete('/whitelist/:discord_id', async (req, res) => { if (req.params.discord_id === req.user.id) { return res.status(400).json({ error: 'Du kannst dich nicht selbst aus der Whitelist entfernen' }); } try { await db.query('DELETE FROM admin_whitelist WHERE discord_id=?', [req.params.discord_id]); res.json({ ok: true }); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } }); module.exports = router; // ── Credits CRUD (admin only) ───────────────────────── // Erstellen router.post('/credits', async (req, res) => { const { id, name, type, role, avatar, emoji, description, discord, website, roblox, sort_order } = req.body; if (!id || !name) return res.status(400).json({ error: 'id und name erforderlich' }); try { await db.query( `INSERT INTO credits (id, name, type, role, avatar, emoji, description, discord, website, roblox, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, name, type||'credit', role||'', avatar||'', emoji||'👤', description||'', discord||'', website||'', roblox||'', sort_order||0] ); res.json({ ok: true }); } catch (e) { if (e.code === 'ER_DUP_ENTRY') return res.status(409).json({ error: 'ID bereits vorhanden' }); console.error(e); res.status(500).json({ error: 'DB-Fehler' }); } }); // Bearbeiten router.put('/credits/:id', async (req, res) => { const { name, type, role, avatar, emoji, description, discord, website, roblox, sort_order } = req.body; if (!name) return res.status(400).json({ error: 'name erforderlich' }); try { const result = await db.query( `UPDATE credits SET name=?, type=?, role=?, avatar=?, emoji=?, description=?, discord=?, website=?, roblox=?, sort_order=? WHERE id=?`, [name, type||'credit', role||'', avatar||'', emoji||'👤', description||'', discord||'', website||'', roblox||'', sort_order||0, req.params.id] ); if (result.affectedRows === 0) return res.status(404).json({ error: 'Nicht gefunden' }); res.json({ ok: true }); } catch (e) { console.error(e); res.status(500).json({ error: 'DB-Fehler' }); } }); // Löschen router.delete('/credits/:id', async (req, res) => { try { await db.query('DELETE FROM credits WHERE id=?', [req.params.id]); res.json({ ok: true }); } catch (e) { res.status(500).json({ error: 'DB-Fehler' }); } });