const express = require('express'); const fs = require('fs'); const bcrypt = require('bcryptjs'); const multer = require('multer'); const db = require('../db'); const { authenticate, requireAdmin } = require('../middleware/auth'); const router = express.Router(); const DB_PATH = process.env.DB_PATH || '/data/dickendock.db'; const upload = multer({ dest: '/tmp/' }); // GET /api/admin/backup router.get('/backup', authenticate, requireAdmin, (req, res) => { if (!fs.existsSync(DB_PATH)) return res.status(404).json({ error: 'DB nicht gefunden' }); const date = new Date().toISOString().split('T')[0]; res.download(DB_PATH, `dickendock-backup-${date}.db`); }); // POST /api/admin/restore router.post('/restore', authenticate, requireAdmin, upload.single('database'), (req, res) => { if (!req.file) return res.status(400).json({ error: 'Keine Datei erhalten' }); try { if (fs.existsSync(DB_PATH)) fs.copyFileSync(DB_PATH, DB_PATH + '.bak'); fs.copyFileSync(req.file.path, DB_PATH); fs.unlinkSync(req.file.path); res.json({ success: true }); } catch (e) { res.status(500).json({ error: e.message }); } }); // GET /api/admin/users – alle Benutzer mit Statistiken router.get('/users', authenticate, requireAdmin, (req, res) => { const users = db.prepare("SELECT id, username, role, created_at FROM users ORDER BY role DESC, username").all(); const stats = users.map(u => { const archiv = db.prepare('SELECT COUNT(*) c FROM calculations WHERE user_id=?').get(u.id).c; const bestellung = db.prepare('SELECT COUNT(*) c FROM orders WHERE user_id=?').get(u.id).c; const todos = db.prepare('SELECT COUNT(*) c FROM todos WHERE user_id=?').get(u.id).c; const links = db.prepare('SELECT COUNT(*) c FROM quick_links WHERE user_id=?').get(u.id).c; const files = db.prepare('SELECT COUNT(*) c FROM files WHERE user_id=?').get(u.id).c; const noteLen = (db.prepare('SELECT content FROM notes WHERE user_id=?').get(u.id)?.content || '').length; // iCals are stored in localStorage per user - not in DB, so we can't count them server-side const icals = 0; return { ...u, archiv, bestellung, todos, links, files, icals, noteLen }; }); res.json(stats); }); // POST /api/admin/users – neuen Benutzer anlegen router.post('/users', authenticate, requireAdmin, (req, res) => { const { username, password, role = 'user' } = req.body; if (!username?.trim() || username.trim().length < 3) return res.status(400).json({ error: 'Benutzername mind. 3 Zeichen' }); if (!password || password.length < 8) return res.status(400).json({ error: 'Passwort mind. 8 Zeichen' }); if (!['user','admin'].includes(role)) return res.status(400).json({ error: 'Ungültige Rolle' }); const exists = db.prepare('SELECT id FROM users WHERE username=?').get(username.trim()); if (exists) return res.status(400).json({ error: 'Benutzername bereits vergeben' }); const r = db.prepare('INSERT INTO users (username, password_hash, role) VALUES (?,?,?)') .run(username.trim(), bcrypt.hashSync(password, 12), role); res.json({ id: r.lastInsertRowid, username: username.trim(), role }); }); // DELETE /api/admin/users/:id – Benutzer löschen router.delete('/users/:id', authenticate, requireAdmin, (req, res) => { const id = parseInt(req.params.id); if (id === req.user.id) return res.status(400).json({ error: 'Du kannst dich nicht selbst löschen' }); const user = db.prepare('SELECT * FROM users WHERE id=?').get(id); if (!user) return res.status(404).json({ error: 'Benutzer nicht gefunden' }); // Sicherstellen dass mindestens ein Admin bleibt if (user.role === 'admin') { const adminCount = db.prepare("SELECT COUNT(*) c FROM users WHERE role='admin'").get().c; if (adminCount <= 1) return res.status(400).json({ error: 'Mindestens ein Administrator muss verbleiben' }); } // Cascade: alle Daten des Users löschen db.prepare('DELETE FROM calculations WHERE user_id=?').run(id); db.prepare('DELETE FROM orders WHERE user_id=?').run(id); db.prepare('DELETE FROM todos WHERE user_id=?').run(id); db.prepare('DELETE FROM quick_links WHERE user_id=?').run(id); db.prepare('DELETE FROM notes WHERE user_id=?').run(id); db.prepare('DELETE FROM users WHERE id=?').run(id); res.json({ success: true }); }); // PUT /api/admin/users/:id/reset-password – Passwort zurücksetzen router.put('/users/:id/reset-password', authenticate, requireAdmin, (req, res) => { const { newPassword } = req.body; if (!newPassword || newPassword.length < 8) return res.status(400).json({ error: 'Mind. 8 Zeichen' }); const user = db.prepare('SELECT * FROM users WHERE id=?').get(req.params.id); if (!user) return res.status(404).json({ error: 'Nicht gefunden' }); db.prepare('UPDATE users SET password_hash=? WHERE id=?').run(bcrypt.hashSync(newPassword, 12), req.params.id); res.json({ success: true }); }); module.exports = router;