diff --git a/backend/src/routes/lab.js b/backend/src/routes/lab.js index 9dfba4f..d3649d8 100644 --- a/backend/src/routes/lab.js +++ b/backend/src/routes/lab.js @@ -69,8 +69,11 @@ router.get('/sims', (_req, res) => { res.json({ module_disabled: readModuleDisabled(), sims }); }); -/* ── admin mutations ───────────────────────────────────────────────────── */ -router.use(requireRole('admin')); +/* ── admin mutations ─────────────────────────────────────────────────────── + ВАЖНО: НЕ используем blanket `router.use(requireRole('admin'))` — он применялся + бы и к ниже определённым READ-роутам Фазы 5 (/related, /links), которые должны + быть доступны любому авторизованному пользователю. Каждая мутация защищена + INLINE requireRole('admin') (так же видит route-auth линтер). */ /* PATCH /api/lab/sims/:id body: { enabled?, featured?, tags?, subject?, grade?, title?, cat? } */ router.patch('/sims/:id', requireRole('admin'), (req, res) => { @@ -125,7 +128,7 @@ router.patch('/sims/:id', requireRole('admin'), (req, res) => { }); /* POST /api/lab/sims/reorder body: { order: [id, id, ...] } */ -router.post('/sims/reorder', (req, res) => { +router.post('/sims/reorder', requireRole('admin'), (req, res) => { const order = (req.body && req.body.order) || []; if (!Array.isArray(order) || !order.length) { return res.status(400).json({ error: 'order должен быть непустым массивом id' }); diff --git a/backend/tests/lab-links.test.js b/backend/tests/lab-links.test.js index 39e281c..42459f5 100644 --- a/backend/tests/lab-links.test.js +++ b/backend/tests/lab-links.test.js @@ -42,15 +42,11 @@ describe('/api/lab curriculum links', () => { before(async () => { adminToken = (await getToken('admin')).token; studentToken = (await getToken('student')).token; - // Seed a textbook + topic to link against. - db.prepare(`INSERT INTO textbooks (slug, title, subject, grade, is_active) - VALUES ('phys-test', 'Физика тест', 'physics', 9, 1) - ON CONFLICT(slug) DO NOTHING`).run(); + // Seed a textbook + topic to link against (schema-robust — fills NOT NULL cols). tbSlug = 'phys-test'; - const subj = db.prepare(`INSERT INTO subjects (name) VALUES ('LinkTest Subj')`).run(); - const tp = db.prepare(`INSERT INTO topics (subject_id, name) VALUES (?, 'Колебания тест')`) - .run(subj.lastInsertRowid); - topicId = tp.lastInsertRowid; + seedRow('textbooks', { slug: tbSlug, title: 'Физика тест', subject: 'physics', grade: 9, is_active: 1 }); + const subjId = seedRow('subjects', { name: 'LinkTest Subj', slug: 'linktest-subj' }); + topicId = seedRow('topics', { subject_id: subjId, name: 'Колебания тест', slug: 'kolebaniya-test' }); }); it('GET /related requires auth (401)', async () => {