feat(permissions): C-3 — пер-ролевые права кастомных ролей (резолвер + конфиг)
Миграция 056: снят CHECK с role_permissions.role (пересборка) → можно хранить набор прав произвольной кастомной роли. isEnabled(uid,permRole,baseRole,key): user override → role_permissions[customRole] → фолбэк role_permissions[base] → дефолт реестра(base). requirePermission передаёт permRole=customRole||role. getMyPermissions/getUserPermissions: roleMap = база + наложение кастомной роли. Тест C-3: права кастомной роли перекрывают базу, фолбэк на базу. custom-roles 8/8, permissions 17/17, backend без регрессий. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,11 +60,14 @@ function getMyPermissions(req, res) {
|
||||
if (role === 'admin') return res.json({ role, permissions: [] }); // admins bypass all
|
||||
|
||||
seedDefaults();
|
||||
const roleRows = db.prepare(
|
||||
'SELECT permission, enabled FROM role_permissions WHERE role = ?'
|
||||
).all(role);
|
||||
// База роли + наложение кастомной роли (если назначена): role_permissions[base]
|
||||
// перекрываются role_permissions[customRole].
|
||||
const customRole = req.user.customRole || null;
|
||||
const roleMap = {};
|
||||
for (const r of roleRows) roleMap[r.permission] = r.enabled === 1;
|
||||
for (const r of db.prepare('SELECT permission, enabled FROM role_permissions WHERE role = ?').all(role)) roleMap[r.permission] = r.enabled === 1;
|
||||
if (customRole && customRole !== role) {
|
||||
for (const r of db.prepare('SELECT permission, enabled FROM role_permissions WHERE role = ?').all(customRole)) roleMap[r.permission] = r.enabled === 1;
|
||||
}
|
||||
|
||||
const userRows = db.prepare(
|
||||
"SELECT permission, enabled FROM user_permissions WHERE user_id = ? AND (expires_at IS NULL OR expires_at > datetime('now'))"
|
||||
@@ -85,16 +88,16 @@ function getMyPermissions(req, res) {
|
||||
/* ── GET /api/permissions/users/:id ──────────────────────────────────── */
|
||||
function getUserPermissions(req, res) {
|
||||
const uid = Number(req.params.id);
|
||||
const target = db.prepare('SELECT id, role FROM users WHERE id = ?').get(uid);
|
||||
const target = db.prepare('SELECT id, role, custom_role FROM users WHERE id = ?').get(uid);
|
||||
if (!target) return res.status(404).json({ error: 'User not found' });
|
||||
|
||||
seedDefaults();
|
||||
// role-level values
|
||||
const roleRows = db.prepare(
|
||||
'SELECT permission, enabled FROM role_permissions WHERE role = ?'
|
||||
).all(target.role);
|
||||
// role-level values: база роли + наложение кастомной роли (если назначена)
|
||||
const roleMap = {};
|
||||
for (const r of roleRows) roleMap[r.permission] = r.enabled === 1;
|
||||
for (const r of db.prepare('SELECT permission, enabled FROM role_permissions WHERE role = ?').all(target.role)) roleMap[r.permission] = r.enabled === 1;
|
||||
if (target.custom_role && target.custom_role !== target.role) {
|
||||
for (const r of db.prepare('SELECT permission, enabled FROM role_permissions WHERE role = ?').all(target.custom_role)) roleMap[r.permission] = r.enabled === 1;
|
||||
}
|
||||
|
||||
// user-level overrides (просроченные временные не учитываем)
|
||||
const userRows = db.prepare(
|
||||
|
||||
Reference in New Issue
Block a user