diff --git a/VERSION b/VERSION index ea9806d..578dca3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.99-beta +0.4.0-beta diff --git a/public/js/core.js b/public/js/core.js index 4e8898d..bef9988 100644 --- a/public/js/core.js +++ b/public/js/core.js @@ -2,7 +2,7 @@ "use strict"; /* version — shown until /api/version resolves (or if the fetch fails, e.g. offline). Kept in sync by hand with the VERSION file at the repo root on every release. */ -const VERSION = "0.3.99-beta"; +const VERSION = "0.4.0-beta"; (function(){ const tag = document.getElementById("verTag"); tag.textContent = "v"+VERSION; diff --git a/src/api.js b/src/api.js index eb291fb..260fac8 100644 --- a/src/api.js +++ b/src/api.js @@ -375,12 +375,20 @@ export default async function api(app) { }); app.delete('/admin/classes/:id', async (req, reply) => { need(req, reply, PERMISSIONS['classes.manage']); - const r = await pool.query('SELECT * FROM classes WHERE id = $1', [req.params.id]); - if (!r.rows[0]) return fail(reply, 404, 'klas onbekend'); - if (!req.user.allRoles.includes('super') && Number(r.rows[0].school_id) !== Number(req.user.school_id)) - return fail(reply, 403, 'geen rechten'); - await pool.query('DELETE FROM classes WHERE id = $1', [req.params.id]); - return { ok: true }; + // Zelfde reden als bij het verwijderen van een gebruiker: alles in één + // try/catch, zodat een mislukking de echte oorzaak teruggeeft i.p.v. terug + // te vallen op de kale "serverfout" van de generieke handler. + try { + const r = await pool.query('SELECT * FROM classes WHERE id = $1', [req.params.id]); + if (!r.rows[0]) return fail(reply, 404, 'klas onbekend'); + if (!req.user.allRoles.includes('super') && Number(r.rows[0].school_id) !== Number(req.user.school_id)) + return fail(reply, 403, 'geen rechten'); + await pool.query('DELETE FROM classes WHERE id = $1', [req.params.id]); + return { ok: true }; + } catch (e) { + req.log.error({ err: e }, 'verwijderen klas mislukt'); + return fail(reply, 409, `verwijderen mislukt: ${e.detail || e.message}`); + } }); // groepsleiding aan klas koppelen/loskoppelen // Elke staf-rol (groepsleiding, schoolbeheerder, systeemmanager) kan aan diff --git a/test/schools.test.js b/test/schools.test.js index 45a7a06..6d10283 100644 --- a/test/schools.test.js +++ b/test/schools.test.js @@ -197,6 +197,27 @@ test('systeemmanager verplaatst een klas naar een andere school; losmaken kan ni await app.close(); await app2.close(); await app3.close(); }); +test('klas verwijderen werkt en meldt bij een fout de echte reden i.p.v. kale serverfout', async () => { + const { app, calls } = await makeApp(superUser, null); + const res = await app.inject({ method: 'DELETE', url: '/api/admin/classes/100', cookies }); + assert.equal(res.statusCode, 200, res.body); + assert.ok(calls.some((c) => c.sql === 'DELETE FROM classes WHERE id = $1')); + + const { app: app2 } = await makeApp(superUser, null); + const pool2 = app2.pg; + const orig = pool2.query.bind(pool2); + pool2.query = async (sql, params) => { + if (sql === 'DELETE FROM classes WHERE id = $1') { + const e = new Error('boom'); e.detail = 'Key is still referenced from table "iets".'; throw e; + } + return orig(sql, params); + }; + const res2 = await app2.inject({ method: 'DELETE', url: '/api/admin/classes/100', cookies }); + assert.equal(res2.statusCode, 409, res2.body); + assert.match(res2.json().error, /still referenced/); + await app.close(); await app2.close(); +}); + test('gebruiker verwijderen ruimt eerst alle afhankelijke rijen op (geen serverfout)', async () => { const { app, calls } = await makeApp(superUser, { id: 9, role: 'teacher', school_id: 2, username: 'juf' }); const res = await app.inject({ method: 'DELETE', url: '/api/admin/users/9', cookies });