feat(lessons): «Быстрый урок» — одиночный урок без ручного создания курса

Учитель жмёт «Быстрый урок» в каталоге (theory.html) → урок создаётся в скрытом личном
курсе-контейнере и сразу открывается редактор. Возни с курсом нет.

- Миграция 059: courses.is_personal (ADD COLUMN).
- POST /api/lessons/quick (teacher/admin): get-or-create личный контейнер (is_personal=1,
  один на учителя, опубликован) + создаёт урок, возвращает lessonId.
- Каталог курсов скрывает личные контейнеры от всех, кроме владельца (courseController.list).
- Свои быстрые уроки учитель видит как курс «Мои материалы» (открыв его в каталоге).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-03 20:42:14 +03:00
parent 7e640e4207
commit 6be8a505eb
5 changed files with 63 additions and 1 deletions
@@ -45,6 +45,10 @@ function list(req, res) {
let where = role === 'student' ? 'WHERE c.is_published = 1' : 'WHERE 1=1';
const args = [];
if (subject) { where += ' AND c.subject_slug = ?'; args.push(subject); }
// Personal "container" courses (quick lessons) are hidden from the catalog;
// their owner still sees their own.
if (role === 'student') { where += ' AND c.is_personal = 0'; }
else { where += ' AND (c.is_personal = 0 OR c.created_by = ?)'; args.push(uid); }
const rows = db.prepare(`
SELECT c.*,
+25 -1
View File
@@ -302,4 +302,28 @@ function deleteComment(req, res) {
res.json({ ok: true });
}
module.exports = { get, create, update, remove, saveBlocks, markComplete, saveNote, listComments, addComment, deleteComment };
/* ── POST /api/lessons/quick ──────────────────────────────────────────────
Create a standalone "quick lesson" without manually building a course:
reuse (or lazily create) the teacher's hidden personal container course,
add one lesson to it, and return its id for the editor. */
function quickLesson(req, res) {
const uid = req.user.id;
let container = db.prepare(
'SELECT id FROM courses WHERE created_by = ? AND is_personal = 1 ORDER BY id LIMIT 1'
).get(uid);
if (!container) {
const r = db.prepare(`
INSERT INTO courses (subject_slug, title, description, cover_emoji, order_index, is_published, is_personal, created_by)
VALUES ('personal', 'Мои материалы', 'Отдельные уроки без курса', '', 0, 1, 1, ?)
`).run(uid);
container = { id: Number(r.lastInsertRowid) };
}
const title = (req.body && req.body.title && String(req.body.title).trim()) || 'Новый урок';
const n = db.prepare('SELECT COUNT(*) AS c FROM lessons WHERE course_id = ?').get(container.id).c;
const r2 = db.prepare(
'INSERT INTO lessons (course_id, title, order_index) VALUES (?, ?, ?)'
).run(container.id, title, n);
res.status(201).json({ lessonId: Number(r2.lastInsertRowid), courseId: container.id });
}
module.exports = { get, create, update, remove, saveBlocks, markComplete, saveNote, listComments, addComment, deleteComment, quickLesson };