Verbeter anatomie en plaatsing van avataraccessoires (v0.4.46-beta) #1

Open
bes-r wants to merge 192 commits from bes-r/avatar-realism into main AGit
4 changed files with 37 additions and 8 deletions
Showing only changes of commit 4a31dc9351 - Show all commits

View file

@ -1 +1 @@
0.3.99-beta 0.4.0-beta

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
/* version shown until /api/version resolves (or if the fetch fails, e.g. offline). /* 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. */ 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(){ (function(){
const tag = document.getElementById("verTag"); const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION; tag.textContent = "v"+VERSION;

View file

@ -375,12 +375,20 @@ export default async function api(app) {
}); });
app.delete('/admin/classes/:id', async (req, reply) => { app.delete('/admin/classes/:id', async (req, reply) => {
need(req, reply, PERMISSIONS['classes.manage']); need(req, reply, PERMISSIONS['classes.manage']);
const r = await pool.query('SELECT * FROM classes WHERE id = $1', [req.params.id]); // Zelfde reden als bij het verwijderen van een gebruiker: alles in één
if (!r.rows[0]) return fail(reply, 404, 'klas onbekend'); // try/catch, zodat een mislukking de echte oorzaak teruggeeft i.p.v. terug
if (!req.user.allRoles.includes('super') && Number(r.rows[0].school_id) !== Number(req.user.school_id)) // te vallen op de kale "serverfout" van de generieke handler.
return fail(reply, 403, 'geen rechten'); try {
await pool.query('DELETE FROM classes WHERE id = $1', [req.params.id]); const r = await pool.query('SELECT * FROM classes WHERE id = $1', [req.params.id]);
return { ok: true }; 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 // groepsleiding aan klas koppelen/loskoppelen
// Elke staf-rol (groepsleiding, schoolbeheerder, systeemmanager) kan aan // Elke staf-rol (groepsleiding, schoolbeheerder, systeemmanager) kan aan

View file

@ -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(); 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 () => { 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 { 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 }); const res = await app.inject({ method: 'DELETE', url: '/api/admin/users/9', cookies });