feat(permissions): B6 — массовая выдача права классу (личный оверрайд всем ученикам)
POST /api/permissions/class/:id/bulk { permission, enabled } (admin, явный
requireRole) — выставляет user_permissions всем ученикам класса (1/0/null=сброс),
точечный token_version bump каждому. Валидация: только студенческие ключи.
Клиент LS.setClassPermission. В админке «Доступ · роли» — блок «Массово по
классу»: выбор класса → у каждого права «включить/выключить всем / сбросить».
Тест: оверрайд всем + сброс + отклонение teacher-ключа. Backend 221 pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -218,4 +218,32 @@ describe('Permissions', () => {
|
||||
const denied = await inject('GET', '/api/permissions/log', null, fresh.token);
|
||||
assert.equal(denied.status, 403, 'не-админу недоступно');
|
||||
});
|
||||
|
||||
// ── B6: массово по классу ──────────────────────────────────────────────────
|
||||
it('B6: массовое право классу — личный оверрайд всем ученикам + сброс + валидация', async () => {
|
||||
const cr = await inject('POST', '/api/classes', { name: 'PermBulk Class' }, adminToken);
|
||||
assert.ok(cr.status < 300, JSON.stringify(cr.body));
|
||||
const cid = db.prepare('SELECT id FROM classes WHERE name = ?').get('PermBulk Class').id;
|
||||
await inject('POST', `/api/classes/${cid}/members`, { user_id: studentUser.userId }, adminToken);
|
||||
|
||||
const off = await inject('POST', `/api/permissions/class/${cid}/bulk`,
|
||||
{ permission: 'shop.purchase', enabled: false }, adminToken);
|
||||
assert.equal(off.status, 200);
|
||||
assert.ok(off.body.affected >= 1, 'затронут хотя бы один ученик');
|
||||
const row = db.prepare('SELECT enabled FROM user_permissions WHERE user_id = ? AND permission = ?')
|
||||
.get(studentUser.userId, 'shop.purchase');
|
||||
assert.ok(row && row.enabled === 0, 'личный оверрайд выключен у ученика класса');
|
||||
|
||||
// сброс (наследование роли)
|
||||
await inject('POST', `/api/permissions/class/${cid}/bulk`,
|
||||
{ permission: 'shop.purchase', enabled: null }, adminToken);
|
||||
const gone = db.prepare('SELECT 1 FROM user_permissions WHERE user_id = ? AND permission = ?')
|
||||
.get(studentUser.userId, 'shop.purchase');
|
||||
assert.ok(!gone, 'оверрайд снят');
|
||||
|
||||
// teacher-право для массовой студенческой операции отклоняется
|
||||
const bad = await inject('POST', `/api/permissions/class/${cid}/bulk`,
|
||||
{ permission: 'questions.manage', enabled: true }, adminToken);
|
||||
assert.equal(bad.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user