Files
Quizalarm/server/index.js
T

109 lines
3.8 KiB
JavaScript

const express = require('express');
const http = require('http');
const path = require('path');
const { getEnvConfig, readConfig, writeConfig } = require('./config');
const { listRows, batchCreateRows } = require('./baserow');
const { setupWebSocket, getSessions } = require('./live-session');
const app = express();
const server = http.createServer(app);
app.use(express.json({ limit: '5mb' }));
app.use(express.static(path.join(__dirname, '..', 'public')));
/* ---- Auth middleware ---- */
function requireAdmin(req, res, next) {
if (req.headers['x-admin-token'] !== getEnvConfig().adminPassword) {
return res.status(401).json({ error: 'Nicht autorisiert' });
}
next();
}
/* ============================================================ */
/* Public API */
/* ============================================================ */
app.get('/api/sets', (req, res) => {
const config = readConfig();
res.json(config.sets.map((s) => ({ id: s.id, name: s.name })));
});
app.get('/api/sets/:id/questions', async (req, res) => {
try {
const config = readConfig();
const set = config.sets.find((s) => s.id === req.params.id);
if (!set) return res.status(404).json({ error: 'Nicht gefunden' });
const rows = await listRows(set.tableId);
res.json(rows);
} catch (e) {
res.status(500).json({ error: e.message });
}
});
app.post('/api/results', async (req, res) => {
try {
const config = readConfig();
if (!config.answersTableId) return res.status(400).json({ error: 'Antworten-Tabelle nicht konfiguriert' });
await batchCreateRows(config.answersTableId, req.body.answers);
res.json({ success: true });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
app.get('/api/results/:name', async (req, res) => {
try {
const config = readConfig();
if (!config.answersTableId) return res.json([]);
const rows = await listRows(config.answersTableId, { Nutzername: req.params.name });
res.json(rows);
} catch (e) {
res.status(500).json({ error: e.message });
}
});
/* ============================================================ */
/* Admin API */
/* ============================================================ */
app.post('/api/admin/login', (req, res) => {
if (req.body.password === getEnvConfig().adminPassword) {
res.json({ success: true, token: getEnvConfig().adminPassword });
} else {
res.status(401).json({ error: 'Falsches Passwort' });
}
});
app.get('/api/admin/config', requireAdmin, (req, res) => res.json(readConfig()));
app.post('/api/admin/config', requireAdmin, (req, res) => {
try {
writeConfig(req.body);
res.json({ success: true });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
app.get('/api/admin/sessions', requireAdmin, (req, res) => res.json(getSessions()));
app.get('/api/admin/stats', requireAdmin, async (req, res) => {
try {
const config = readConfig();
if (!config.answersTableId) return res.json({ answers: [] });
const rows = await listRows(config.answersTableId);
res.json({ answers: rows });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
/* ---- SPA routes ---- */
app.get('/admin', (req, res) => res.sendFile(path.join(__dirname, '..', 'public', 'admin.html')));
app.get('/present', (req, res) => res.sendFile(path.join(__dirname, '..', 'public', 'present.html')));
app.get('*', (req, res) => res.sendFile(path.join(__dirname, '..', 'public', 'index.html')));
/* ---- Start ---- */
setupWebSocket(server);
const { port } = getEnvConfig();
server.listen(port, '0.0.0.0', () => console.log(`[quizalarm] Laeuft auf Port ${port}`));