All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 51s
- Nieuwe sectie "Exporteren per klas" in de bestaande Voortgang-tab: klas kiezen + "Exporteer als CSV" downloadt de volledige activiteitenlijst van die klas (leerling, widget, pogingen, goed, sterren, datum/tijd). - Bouwt voort op de bestaande route GET /progress/class/:id, die tot nu toe geen enkele frontend-consument had. - Server: nieuwe optionele ?limit=-queryparameter (begrensd op 5000) - de export vraagt expliciet meer dan de standaard activiteitenweergave (200) op, zodat een drukke klas niet stilzwijgend wordt afgekapt in het exportbestand. Zonder de parameter blijft het bestaande gedrag (200) ongewijzigd. - Eerste CSV-export in deze codebase: kleine lokale csvValue()/ downloadCsv()-helpers in admin.js (komma/quote/newline-escaping, BOM zodat Excel-NL accenten en komma-scheiding herkent) - bewust nog niet gedeeld/verplaatst naar core.js, want er is nu nog maar één gebruiker (de geplande wachtwoorden-export kan dit later hergebruiken). - Tests: test/progress-export.test.js (limit wordt doorgegeven, te hoge waarde wordt afgekapt op 5000, standaardgedrag zonder parameter blijft 200) + volledige testsuite (112/112). Ook live geverifieerd: klas kiezen zonder selectie toont een hint i.p.v. te crashen, een echte CSV-download met correcte escaping van komma's/aanhalingstekens in een leerlingnaam, en de vertaalde widget-namen in de kolommen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
56 lines
2.3 KiB
JavaScript
56 lines
2.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import Fastify from 'fastify';
|
|
import cookie from '@fastify/cookie';
|
|
import rateLimit from '@fastify/rate-limit';
|
|
import api from '../src/api.js';
|
|
|
|
function makeApp(user) {
|
|
const calls = [];
|
|
const query = async (sql, params = []) => {
|
|
calls.push({ sql, params });
|
|
if (sql.includes('FROM sessions s JOIN users u')) return { rows: [user] };
|
|
if (sql.includes('FROM user_roles')) return { rows: [] };
|
|
if (sql.startsWith('SELECT * FROM classes WHERE id')) return { rows: [{ id: 100, school_id: 2, name: 'Groep 4' }] };
|
|
if (sql.includes('FROM progress_events pe')) return { rows: [] };
|
|
return { rows: [] };
|
|
};
|
|
const pool = { query, async connect() { return { query, release() {} }; } };
|
|
return (async () => {
|
|
const app = Fastify({ trustProxy: 2 });
|
|
await app.register(cookie);
|
|
await app.register(rateLimit, { global: false });
|
|
app.decorate('pg', pool);
|
|
await app.register(api, { prefix: '/api' });
|
|
await app.ready();
|
|
return { app, calls };
|
|
})();
|
|
}
|
|
|
|
const cookies = { teach_session: 'x'.repeat(64) };
|
|
const admin = { id: 3, username: 'beheer', role: 'admin', school_id: 2, class_id: null, data: {}, data_rev: 0 };
|
|
|
|
function progressCall(calls) {
|
|
return calls.find(c => c.sql.includes('FROM progress_events pe'));
|
|
}
|
|
|
|
test('resultaten-export: ?limit= wordt doorgegeven aan de query', async () => {
|
|
const { app, calls } = await makeApp(admin);
|
|
const res = await app.inject({ method: 'GET', url: '/api/progress/class/100?limit=3000', cookies });
|
|
assert.equal(res.statusCode, 200, res.body);
|
|
assert.equal(progressCall(calls).params[1], 3000);
|
|
});
|
|
|
|
test('resultaten-export: een te hoge limit wordt afgekapt op het veilige maximum', async () => {
|
|
const { app, calls } = await makeApp(admin);
|
|
const res = await app.inject({ method: 'GET', url: '/api/progress/class/100?limit=999999', cookies });
|
|
assert.equal(res.statusCode, 200, res.body);
|
|
assert.equal(progressCall(calls).params[1], 5000);
|
|
});
|
|
|
|
test('resultaten-export: zonder limit-param blijft het standaardgedrag (200) behouden', async () => {
|
|
const { app, calls } = await makeApp(admin);
|
|
const res = await app.inject({ method: 'GET', url: '/api/progress/class/100', cookies });
|
|
assert.equal(res.statusCode, 200, res.body);
|
|
assert.equal(progressCall(calls).params[1], 200);
|
|
});
|