feat(permissions): C-2 — присвоение кастомной роли пользователю (users.custom_role)
Миграция 055: ADD COLUMN users.custom_role (безопасно, без пересборки users). Модель: users.role = функциональная база (встроенная, CHECK ок, драйвит ветки контроллеров и резолв прав), users.custom_role = имя кастомной роли. updateRole (PATCH /api/admin/users/:id/role) принимает кастомные роли → ставит base_roles[0] как базу + custom_role=имя; встроенная → custom_role=NULL; неизвестная → 400. authMiddleware/optionalAuth читают custom_role → req.user.customRole; requireRole расширяет до effectiveRoles(customRole||role). Тесты custom-roles 7/7; backend без регрессий. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
const { describe, it, before, after } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { db, cleanup } = require('./setup');
|
||||
const { db, getToken, inject, cleanup } = require('./setup');
|
||||
const auth = require('../src/middleware/auth');
|
||||
|
||||
after(() => cleanup());
|
||||
@@ -52,3 +52,35 @@ describe('custom roles — effectiveRoles (C-1)', () => {
|
||||
assert.equal(passes('student', ['teacher', 'admin']), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom roles — назначение пользователю (C-2)', () => {
|
||||
let adminToken;
|
||||
before(async () => {
|
||||
adminToken = (await getToken('admin')).token;
|
||||
db.prepare("INSERT OR IGNORE INTO roles (name,label,base_roles,is_builtin) VALUES ('methodist','Методист',?,0)")
|
||||
.run(JSON.stringify(['teacher']));
|
||||
});
|
||||
|
||||
it('PATCH role=кастомная → users.role=база, custom_role=имя', async () => {
|
||||
const u = await getToken('student');
|
||||
const r = await inject('PATCH', `/api/admin/users/${u.userId}/role`, { role: 'methodist' }, adminToken);
|
||||
assert.equal(r.status, 200, JSON.stringify(r.body));
|
||||
assert.equal(r.body.base, 'teacher');
|
||||
const row = db.prepare('SELECT role, custom_role FROM users WHERE id=?').get(u.userId);
|
||||
assert.equal(row.role, 'teacher', 'функциональная база = teacher');
|
||||
assert.equal(row.custom_role, 'methodist');
|
||||
|
||||
// обратно на встроенную → custom_role очищается
|
||||
const r2 = await inject('PATCH', `/api/admin/users/${u.userId}/role`, { role: 'student' }, adminToken);
|
||||
assert.equal(r2.status, 200);
|
||||
const row2 = db.prepare('SELECT role, custom_role FROM users WHERE id=?').get(u.userId);
|
||||
assert.equal(row2.role, 'student');
|
||||
assert.equal(row2.custom_role, null);
|
||||
});
|
||||
|
||||
it('PATCH с несуществующей ролью → 400', async () => {
|
||||
const u = await getToken('student');
|
||||
const bad = await inject('PATCH', `/api/admin/users/${u.userId}/role`, { role: 'ghostrole' }, adminToken);
|
||||
assert.equal(bad.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user