blair-cheatsheet/admin.js
2026-05-17 20:04:21 +02:00

153 lines
6.0 KiB
JavaScript

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;