112 lines
3.5 KiB
JavaScript
112 lines
3.5 KiB
JavaScript
|
|
const express = require('express');
|
||
|
|
const { sha256, safeEqual } = require('../utils/hash');
|
||
|
|
const storage = require('../utils/storage');
|
||
|
|
const { requireAdmin } = require('../auth');
|
||
|
|
const { generateBookPdf } = require('../pdf');
|
||
|
|
|
||
|
|
const router = express.Router();
|
||
|
|
|
||
|
|
const ADMIN_PASSWORD_HASH = (process.env.ADMIN_PASSWORD_HASH || '').trim().toLowerCase();
|
||
|
|
|
||
|
|
// --- Admin Login ---
|
||
|
|
router.post('/login', (req, res) => {
|
||
|
|
const { password } = req.body || {};
|
||
|
|
if (!password || !ADMIN_PASSWORD_HASH) {
|
||
|
|
return res.status(400).json({ error: 'Passwort erforderlich.' });
|
||
|
|
}
|
||
|
|
const hash = sha256(password);
|
||
|
|
if (!safeEqual(hash, ADMIN_PASSWORD_HASH)) {
|
||
|
|
return res.status(401).json({ error: 'Falsches Passwort.' });
|
||
|
|
}
|
||
|
|
req.session.role = 'admin';
|
||
|
|
req.session.friendId = null;
|
||
|
|
return res.json({ ok: true });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/logout', (req, res) => {
|
||
|
|
req.session = null;
|
||
|
|
res.json({ ok: true });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/session', (req, res) => {
|
||
|
|
if (req.session && req.session.role) {
|
||
|
|
return res.json({ role: req.session.role, friendId: req.session.friendId || null });
|
||
|
|
}
|
||
|
|
res.json({ role: null });
|
||
|
|
});
|
||
|
|
|
||
|
|
// --- Freunde-Verwaltung (nur Admin) ---
|
||
|
|
router.get('/friends', requireAdmin, (req, res) => {
|
||
|
|
const friends = storage.getAllFriendsMeta().map((f) => ({
|
||
|
|
id: f.id,
|
||
|
|
folderName: f.folderName,
|
||
|
|
name: f.name,
|
||
|
|
createdAt: f.createdAt,
|
||
|
|
profileImage: f.profileImage,
|
||
|
|
shareEnabled: !!(f.share && f.share.enabled),
|
||
|
|
blockCount: (f.blocks || []).length,
|
||
|
|
}));
|
||
|
|
res.json({ friends });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/friends', requireAdmin, (req, res) => {
|
||
|
|
const { name } = req.body || {};
|
||
|
|
if (!name || !String(name).trim()) {
|
||
|
|
return res.status(400).json({ error: 'Name erforderlich.' });
|
||
|
|
}
|
||
|
|
const meta = storage.createFriend(String(name).trim());
|
||
|
|
res.json({ friend: meta });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.delete('/friends/:id', requireAdmin, (req, res) => {
|
||
|
|
const folder = storage.findFolderById(req.params.id);
|
||
|
|
if (!folder) return res.status(404).json({ error: 'Nicht gefunden.' });
|
||
|
|
storage.deleteFriend(folder);
|
||
|
|
res.json({ ok: true });
|
||
|
|
});
|
||
|
|
|
||
|
|
// Freigabe (Share-Link) verwalten
|
||
|
|
router.post('/friends/:id/share', requireAdmin, (req, res) => {
|
||
|
|
const folder = storage.findFolderById(req.params.id);
|
||
|
|
if (!folder) return res.status(404).json({ error: 'Nicht gefunden.' });
|
||
|
|
const meta = storage.readMeta(folder);
|
||
|
|
const { enabled, password } = req.body || {};
|
||
|
|
|
||
|
|
if (enabled === false) {
|
||
|
|
meta.share.enabled = false;
|
||
|
|
storage.writeMeta(folder, meta);
|
||
|
|
return res.json({ friend: meta });
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!password || String(password).length < 4) {
|
||
|
|
return res.status(400).json({ error: 'Bitte ein Passwort mit mindestens 4 Zeichen vergeben.' });
|
||
|
|
}
|
||
|
|
meta.share.enabled = true;
|
||
|
|
meta.share.passwordHash = sha256(password);
|
||
|
|
storage.writeMeta(folder, meta);
|
||
|
|
res.json({ friend: meta });
|
||
|
|
});
|
||
|
|
|
||
|
|
// --- Freundesbuch-Ansicht (aggregiert, nur Admin) ---
|
||
|
|
router.get('/book', requireAdmin, (req, res) => {
|
||
|
|
const friends = storage.getAllFriendsMeta().map((f) => ({
|
||
|
|
...f,
|
||
|
|
share: { enabled: !!(f.share && f.share.enabled) }, // Passwort-Hash nie an den Client senden
|
||
|
|
}));
|
||
|
|
res.json({ friends });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/book/pdf', requireAdmin, async (req, res) => {
|
||
|
|
try {
|
||
|
|
const pdfBuffer = await generateBookPdf();
|
||
|
|
res.setHeader('Content-Type', 'application/pdf');
|
||
|
|
res.setHeader('Content-Disposition', 'attachment; filename="freundesbuch.pdf"');
|
||
|
|
res.send(pdfBuffer);
|
||
|
|
} catch (err) {
|
||
|
|
console.error('PDF-Export fehlgeschlagen:', err);
|
||
|
|
res.status(500).json({ error: 'PDF-Export fehlgeschlagen.' });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
module.exports = router;
|