From 307e30d932d321b9e3db81aaaf1ba7c1f32332e2 Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Sun, 26 Apr 2026 20:17:48 +0200 Subject: [PATCH] Implement batch transmission of unanswered questions and automated session cleanup --- public/js/app.js | 30 +++++++++++++++++++++++++++++- server/index.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index e682fdd..b7c195e 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -739,7 +739,19 @@ function WettkampfSelectPage({ navigate }) { setProgressDialog(null); }; - const startFresh = () => { + const startFresh = async () => { + setChecking(true); + try { + await api.post('/api/results/abandon', { + sessionId: progressDialog.sessionId, + setId: selectedSet.id, + nutzername: name.trim(), + expectedCount: selectedSet.wettkampfCount + }); + } catch (e) { + console.error('Abandon error:', e); + } + setChecking(false); navigate('wettkampf-quiz', { setId: selectedSet.id, setName: selectedSet.name, name: name.trim(), questionCount: selectedSet.wettkampfCount, @@ -1078,6 +1090,22 @@ function WettkampfQuizPage({ params, navigate }) { if (rowsToUpdate.length > 0) { await api.put('/api/results/finalize', { results: rowsToUpdate }); } + + const rowsToCreate = finalResults.filter((r) => !r.rowId); + if (rowsToCreate.length > 0) { + const batched = rowsToCreate.map((r) => ({ + Nutzername: params.name, + Frage_ID: r.questionId, + Fragenset: params.setName, + Antwort: '', + Richtig: false, + Punkte: 0, + Session_ID: sessionId.current, + Modus: 'Wettkampf', + Zeitstempel: new Date().toISOString(), + })); + await api.post('/api/results', { answers: batched }); + } } catch (e) { console.error('Finalize error:', e); } diff --git a/server/index.js b/server/index.js index 2165068..958bb68 100644 --- a/server/index.js +++ b/server/index.js @@ -280,7 +280,8 @@ app.get('/api/wettkampf-progress/:name/:setId', async (req, res) => { const richtig = a['Richtig']; return punkte === 0 && (richtig === false || richtig === 'false' || !richtig); }); - if (allUnscored && answers.length > 0) { + const isFullLength = set.wettkampfCount && answers.length >= set.wettkampfCount; + if (allUnscored && answers.length > 0 && !isFullLength) { const latest = answers.reduce((max, a) => { const ts = a['Zeitstempel'] || ''; return ts > max ? ts : max; @@ -324,6 +325,47 @@ app.post('/api/results', async (req, res) => { } }); +app.post('/api/results/abandon', async (req, res) => { + try { + const config = readConfig(); + if (!config.answersTableId) return res.status(400).json({ error: 'Nicht konfiguriert' }); + + const { sessionId, setId, nutzername, expectedCount } = req.body; + if (!sessionId || !setId || !nutzername) return res.status(400).json({ error: 'Fehlende Parameter' }); + + const set = config.sets.find((s) => s.id === setId); + if (!set) return res.status(404).json({ error: 'Set nicht gefunden' }); + + const allAnswers = await listRows(config.answersTableId, { Session_ID: sessionId, Nutzername: nutzername }); + const answeredIds = new Set(allAnswers.map(a => Number(a['Frage_ID']))); + const needed = expectedCount - allAnswers.length; + + if (needed > 0) { + const questions = await listRows(set.tableId); + const unpicked = questions.filter(q => !answeredIds.has(q.id)); + const shuffled = unpicked.sort(() => Math.random() - 0.5); + const selected = shuffled.slice(0, needed); + + const batched = selected.map(q => ({ + Nutzername: nutzername, + Frage_ID: q.id, + Fragenset: set.name, + Antwort: '', + Richtig: false, + Punkte: 0, + Session_ID: sessionId, + Modus: 'Wettkampf', + Zeitstempel: new Date().toISOString(), + })); + await batchCreateRows(config.answersTableId, batched); + } + res.json({ success: true }); + } catch(e) { + console.error('[api] Abandon error:', e.message); + res.status(500).json({ error: e.message }); + } +}); + app.get('/api/results/:name', async (req, res) => { try { const config = readConfig();