feat(access): Фаза 1a — видимость симуляций по классам (добавочная модель)

Миграция 051: расширяет content_access.content_type на 'course'/'sim' (пересборка
таблицы — SQLite не умеет ALTER CHECK) + мост «открыть все включённые симуляции
всем существующим классам» → текущее поведение не меняется. GET /api/lab/sims
теперь фильтрует список для НЕпривилегированных по allowedRefs(uid,'sim'); admin/
teacher видят все. Ролевой simulations.access остаётся «модуль вкл.» (добавочно).
Тесты: lab-access (4/4, allowlist+класс+личное), lab-sims переведён на admin для
проверки полного каталога (видимость ученика — в lab-access). /api/lab в харнессе.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-03 13:19:29 +03:00
parent 16d0f91622
commit 9a145e5d62
5 changed files with 115 additions and 9 deletions
+6 -7
View File
@@ -6,10 +6,7 @@
*/
const { describe, it, before, after } = require('node:test');
const assert = require('node:assert/strict');
const { app, db, inject, getToken, cleanup } = require('./setup');
// Mount /api/lab on the shared test app (setup builds its own app without it).
app.use('/api/lab', require('../src/routes/lab'));
const { db, inject, getToken, cleanup } = require('./setup');
after(() => cleanup());
@@ -26,8 +23,10 @@ describe('/api/lab/sims', () => {
assert.equal(res.status, 401, `got ${res.status}`);
});
it('GET /api/lab/sims returns seeded catalog (40 sims) for a student', async () => {
const res = await inject('GET', '/api/lab/sims', null, studentToken);
/* Полный каталог проверяем под админом (privileged видит все). Видимость
по классам для ученика — в lab-access.test.js (allowlist). */
it('GET /api/lab/sims returns seeded catalog (40 sims) for admin', async () => {
const res = await inject('GET', '/api/lab/sims', null, adminToken);
assert.equal(res.status, 200, `got ${res.status}`);
assert.equal(res.body.module_disabled, false);
assert.ok(Array.isArray(res.body.sims), 'sims is array');
@@ -40,7 +39,7 @@ describe('/api/lab/sims', () => {
});
it('catalog is ordered by sort_order (graph first, angrybirds last)', async () => {
const res = await inject('GET', '/api/lab/sims', null, studentToken);
const res = await inject('GET', '/api/lab/sims', null, adminToken);
assert.equal(res.body.sims[0].id, 'graph');
assert.equal(res.body.sims[res.body.sims.length - 1].id, 'angrybirds');
});