feat(sim-builder): фаза 7 — custom-sim на доске онлайн-урока (синхрон параметров классу, аннотации)

This commit is contained in:
Maxim Dolgolyov
2026-06-13 13:25:24 +03:00
parent 5c01a5c7ed
commit f26b522207
7 changed files with 192 additions and 26 deletions
+19 -2
View File
@@ -10,10 +10,27 @@ function simOpen(req, res) {
return res.status(403).json({ error: 'Нет доступа' });
const { simId, title } = req.body;
if (!simId || typeof simId !== 'string' || !/^[a-z0-9_-]{1,40}$/.test(simId))
if (!simId || typeof simId !== 'string')
return res.status(400).json({ error: 'Неверный simId' });
emitToSession(sessionId, { type: 'classroom_sim_open', sessionId, simId, title: (title || simId).slice(0, 80) });
// Конструктор симуляций (Фаза 7): custom-симуляция в формате 'custom:<dbid>'.
// На доску можно класть только СВОЮ симуляцию (владелец) ИЛИ published
// (доступную всем) — проверяем на сервере, draft чужого не пройдёт.
let resolvedTitle = title;
const custom = /^custom:(\d+)$/.exec(simId);
if (custom) {
const cid = Number(custom[1]);
const sim = db.prepare('SELECT id, owner_id, status, title FROM custom_sims WHERE id=?').get(cid);
if (!sim) return res.status(404).json({ error: 'Симуляция не найдена' });
if (sim.owner_id !== req.user.id && sim.status !== 'published' && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Нет доступа к симуляции' });
}
if (!resolvedTitle) resolvedTitle = sim.title || 'Симуляция';
} else if (!/^[a-z0-9_-]{1,40}$/.test(simId)) {
return res.status(400).json({ error: 'Неверный simId' });
}
emitToSession(sessionId, { type: 'classroom_sim_open', sessionId, simId, title: (resolvedTitle || simId).slice(0, 80) });
res.json({ ok: true });
}