31a51956b6
Импорт 40 нечётных вариантов (v01, v03, ..., v79) в банк вопросов: - 400 questions с allow_html=1, source_type='экзамен 9', year=2025 - 540 options (single-choice) + correct_text (short_answer) - 40 tests (по 1 на вариант), title="Экзамен 9 — Вариант N" - exam9_variant_tests маппинг для назначения Назначение варианта как ДЗ на /exam9 (для учителей/админов): - Кнопка «Назначить как ДЗ» под заголовком варианта (только если test_id есть) - Модалка выбора классов + опциональный deadline - POST /api/assignments/bulk с test_id из exam9_variant_tests Поддержка HTML/SVG в вопросах банка через флаг questions.allow_html: - Миграция 003: ALTER TABLE questions ADD COLUMN allow_html - sessionController: SELECT возвращают allow_html и image - test-run.html: рендер q.text и opt.text как HTML при allow_html=1 - test-result.html: то же для explanation и opt.text - KaTeX: добавлены $...$ и $$...$$ delimiters в обеих страницах Бонус-фикс: bulkSchema требовал class_id (single), контроллер ждёт class_ids (array). Существующий вызов из classes.html был сломан; исправлено вместе. Команда: node backend/scripts/import-exam9.js (--all для всех 80)
57 lines
2.7 KiB
JavaScript
57 lines
2.7 KiB
JavaScript
const router = require('express').Router();
|
|
const { authMiddleware, requireRole } = require('../middleware/auth');
|
|
const validate = require('../middleware/validate');
|
|
const ctrl = require('../controllers/assignmentController');
|
|
|
|
const MODES = ['exam', 'practice', 'repeat', 'ct'];
|
|
|
|
const createSchema = { body: {
|
|
title: { type: 'string', required: true, minLen: 1, maxLen: 200 },
|
|
subject_slug: { type: 'string', maxLen: 100 },
|
|
mode: { type: 'string', oneOf: MODES },
|
|
count: { type: 'number', min: 1, max: 200 },
|
|
deadline: { type: 'string', maxLen: 30 },
|
|
}};
|
|
|
|
const updateSchema = { body: {
|
|
title: { type: 'string', required: true, minLen: 1, maxLen: 200 },
|
|
subject_slug: { type: 'string', maxLen: 100 },
|
|
mode: { type: 'string', oneOf: MODES },
|
|
count: { type: 'number', min: 1, max: 200 },
|
|
deadline: { type: 'string', maxLen: 30 },
|
|
}};
|
|
|
|
const directSchema = { body: {
|
|
title: { type: 'string', required: true, minLen: 1, maxLen: 200 },
|
|
subject_slug: { type: 'string', maxLen: 100 },
|
|
mode: { type: 'string', oneOf: MODES },
|
|
count: { type: 'number', min: 1, max: 200 },
|
|
deadline: { type: 'string', maxLen: 30 },
|
|
student_email: { type: 'string', maxLen: 255 },
|
|
}};
|
|
|
|
const bulkSchema = { body: {
|
|
title: { type: 'string', required: true, minLen: 1, maxLen: 200 },
|
|
class_ids: { type: 'array', required: true },
|
|
mode: { type: 'string', oneOf: MODES },
|
|
count: { type: 'number', min: 1, max: 200 },
|
|
}};
|
|
|
|
router.use(authMiddleware);
|
|
|
|
router.get('/my', ctrl.myAssignments);
|
|
router.get('/teacher', requireRole('teacher','admin'), ctrl.teacherAssignments);
|
|
router.get('/templates', requireRole('teacher','admin'), ctrl.listTemplates);
|
|
router.post('/templates', requireRole('teacher','admin'), ctrl.saveTemplate);
|
|
router.delete('/templates/:id', requireRole('teacher','admin'), ctrl.deleteTemplate);
|
|
router.post('/bulk', requireRole('teacher','admin'), validate(bulkSchema), ctrl.bulkCreateAssignment);
|
|
router.post('/', requireRole('teacher','admin'), validate(directSchema), ctrl.createDirectAssignment);
|
|
router.post('/:id/start', ctrl.startAssignment);
|
|
router.get('/:id/results', requireRole('teacher','admin'), ctrl.assignmentResults);
|
|
router.get('/:id/question-stats', requireRole('teacher','admin'), ctrl.assignmentQuestionStats);
|
|
router.get('/:id/sessions/:session_id/review', requireRole('teacher','admin'), ctrl.assignmentSessionReview);
|
|
router.put('/:id', requireRole('teacher','admin'), validate(updateSchema), ctrl.updateAssignment);
|
|
router.delete('/:id', requireRole('teacher','admin'), ctrl.deleteAssignment);
|
|
|
|
module.exports = router;
|