'use strict'; /** * Фаза 1 (добавочная модель): видимость симуляций по классам через content_access. * Ролевой simulations.access решает «включён ли модуль» (тут не проверяется — * это делает фронт/действия); GET /api/lab/sims фильтрует список так, что ученик * видит только разрешённые его классу/лично симуляции, а admin/teacher — все. */ const { describe, it, before, after } = require('node:test'); const assert = require('node:assert/strict'); const { db, getToken, inject, cleanup } = require('./setup'); after(() => cleanup()); describe('lab sim access (per-class)', () => { let teacher, student, classId, simA, simB; before(async () => { teacher = await getToken('teacher'); student = await getToken('student'); const sims = db.prepare('SELECT id FROM lab_sims WHERE enabled = 1 ORDER BY id LIMIT 2').all(); assert.ok(sims.length >= 2, 'в seed есть хотя бы 2 симуляции'); simA = sims[0].id; simB = sims[1].id; const r = await inject('POST', '/api/classes', { name: 'LabAcc Class' }, teacher.token); assert.ok(r.status < 300, JSON.stringify(r.body)); classId = db.prepare('SELECT id FROM classes WHERE name = ?').get('LabAcc Class').id; await inject('POST', `/api/classes/${classId}/members`, { user_id: student.userId }, teacher.token); }); const ids = (body) => (body.sims || []).map(s => s.id); const rule = (ref, scope, target) => db.prepare(`INSERT OR IGNORE INTO content_access (content_type,content_ref,scope,target_id,allow) VALUES ('sim',?,?,?,1)`).run(ref, scope, target); it('ученик без правил не видит симуляций (allowlist)', async () => { const r = await inject('GET', '/api/lab/sims', null, student.token); assert.equal(r.status, 200); assert.equal(ids(r.body).length, 0); }); it('teacher видит все симуляции (privileged, без фильтра)', async () => { const r = await inject('GET', '/api/lab/sims', null, teacher.token); assert.ok(ids(r.body).length >= 2); }); it('симуляция, открытая классу, видна ученику (и только она)', async () => { rule(simA, 'class', classId); const got = ids((await inject('GET', '/api/lab/sims', null, student.token)).body); assert.ok(got.includes(simA), 'видит открытую'); assert.ok(!got.includes(simB), 'не видит неоткрытую'); }); it('личное правило ученика добавляет симуляцию', async () => { rule(simB, 'student', student.userId); const got = ids((await inject('GET', '/api/lab/sims', null, student.token)).body); assert.ok(got.includes(simA) && got.includes(simB)); }); });