203 lines
8.0 KiB
JavaScript
203 lines
8.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;
|
|
|
|
// ── 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' });
|
|
}
|
|
});
|