feat(permissions): A1 — зависимости между правами (requires) + план переработки
registry: поле requires (questions.delete→manage, templates.public→manage, courses.interactive→manage, simulations.quiz→access), проброшено в byRole. auth.requirePermission: вынесен isEnabled(); право = own AND все requires (дочернее не работает без родителя). /me и /users/🆔 effective с учётом requires + requires в ответе. UI permissions.js: каскад — дочернее с невыполненной зависимостью неактивно (тумблер заблокирован + «Требует: …»). Тест зависимости. План: plans/permissions-rework/PLAN.md. Backend 216 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -174,4 +174,21 @@ describe('Permissions', () => {
|
||||
}, adminToken);
|
||||
assert.equal(res.status, 400);
|
||||
});
|
||||
|
||||
// ── 10. A1: зависимости (requires) ─────────────────────────────────────────
|
||||
it('зависимость requires: simulations.quiz неэффективен при выключенном simulations.access', async () => {
|
||||
const off = await inject('POST', '/api/permissions',
|
||||
{ role: 'student', permission: 'simulations.access', enabled: false }, adminToken);
|
||||
assert.equal(off.status, 200);
|
||||
const view = await inject('GET', `/api/permissions/users/${studentUser.userId}`, null, adminToken);
|
||||
assert.equal(view.status, 200);
|
||||
const quiz = view.body.permissions.find(p => p.key === 'simulations.quiz');
|
||||
const acc = view.body.permissions.find(p => p.key === 'simulations.access');
|
||||
assert.equal(acc.effective, false, 'родитель simulations.access выключен');
|
||||
assert.equal(quiz.effective, false, 'дочернее simulations.quiz неэффективно из-за requires');
|
||||
assert.deepEqual(quiz.requires, ['simulations.access'], 'requires проброшен в API');
|
||||
// restore
|
||||
await inject('POST', '/api/permissions',
|
||||
{ role: 'student', permission: 'simulations.access', enabled: true }, adminToken);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user