feat(permissions): B8 — временные права (expires_at) с авто-снятием
Миграция 053: user_permissions.expires_at (NULL = бессрочно). Резолвер isEnabled
+ /me + /users/:id игнорируют просроченные оверрайды (наследуют роль); seedDefaults
чистит просроченные строки. setUserPermission принимает days → выдаёт право на
срок (datetime('now','+N days')). API отдаёт expiresAt. Клиент: setUserPermission(...,days).
В модалке прав пользователя — бейдж «до ДАТА» + кнопка «врем.» (выдать на N дней).
Тест: срок хранится/отдаётся, просроченное игнорируется и вычищается. Backend pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -274,4 +274,30 @@ describe('Permissions', () => {
|
||||
const badP = await inject('POST', `/api/permissions/class/${cid}/preset`, { preset: 'nope' }, adminToken);
|
||||
assert.equal(badP.status, 400);
|
||||
});
|
||||
|
||||
// ── B8: временные права (expires_at) ───────────────────────────────────────
|
||||
it('B8: временный оверрайд хранит срок, отдаётся, просроченный игнорируется и чистится', async () => {
|
||||
const r = await inject('POST', `/api/permissions/users/${studentUser.userId}`,
|
||||
{ permission: 'shop.purchase', enabled: false, days: 7 }, adminToken);
|
||||
assert.equal(r.status, 200);
|
||||
assert.equal(r.body.expires_in_days, 7);
|
||||
const row = db.prepare('SELECT enabled, expires_at FROM user_permissions WHERE user_id=? AND permission=?')
|
||||
.get(studentUser.userId, 'shop.purchase');
|
||||
assert.ok(row && row.enabled === 0 && row.expires_at, 'оверрайд с expires_at сохранён');
|
||||
|
||||
const view = await inject('GET', `/api/permissions/users/${studentUser.userId}`, null, adminToken);
|
||||
const sp = view.body.permissions.find(p => p.key === 'shop.purchase');
|
||||
assert.equal(sp.userVal, false, 'активный временный оверрайд виден');
|
||||
assert.ok(sp.expiresAt, 'expiresAt отдаётся в API');
|
||||
|
||||
// имитируем просрочку
|
||||
db.prepare("UPDATE user_permissions SET expires_at = datetime('now','-1 day') WHERE user_id=? AND permission=?")
|
||||
.run(studentUser.userId, 'shop.purchase');
|
||||
const view2 = await inject('GET', `/api/permissions/users/${studentUser.userId}`, null, adminToken);
|
||||
const sp2 = view2.body.permissions.find(p => p.key === 'shop.purchase');
|
||||
assert.equal(sp2.userVal, undefined, 'просроченный оверрайд не учитывается (наследует роль)');
|
||||
const left = db.prepare("SELECT COUNT(*) n FROM user_permissions WHERE user_id=? AND permission=?")
|
||||
.get(studentUser.userId, 'shop.purchase').n;
|
||||
assert.equal(left, 0, 'просроченная строка вычищена seedDefaults');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user