'use strict'; const db = require('../../db/db'); const { emitToSession, hasAccess } = require('./_shared'); function getPages(req, res) { const sessionId = Number(req.params.id); const session = db.prepare('SELECT * FROM classroom_sessions WHERE id=?').get(sessionId); if (!session) return res.status(404).json({ error: 'Не найдено' }); if (!hasAccess(session, req.user.id, req.user.role)) return res.status(403).json({ error: 'Нет доступа' }); const maxS = db.prepare('SELECT COALESCE(MAX(page_num),0) AS m FROM classroom_strokes WHERE session_id=?').get(sessionId).m; const maxP = db.prepare('SELECT COALESCE(MAX(page_num),0) AS m FROM classroom_pages WHERE session_id=?').get(sessionId).m; const total = Math.max(session.current_page, maxS, maxP, 1); const rows = db.prepare('SELECT page_num, template, name FROM classroom_pages WHERE session_id=?').all(sessionId); const map = {}; rows.forEach(r => { map[r.page_num] = r; }); const pages = []; for (let i = 1; i <= total; i++) { pages.push({ page_num: i, template: map[i]?.template || 'blank', name: map[i]?.name || null }); } res.json({ pages, currentPage: session.current_page }); } function addPage(req, res) { const sessionId = Number(req.params.id); const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); const maxFromStrokes = db.prepare('SELECT COALESCE(MAX(page_num), 1) AS m FROM classroom_strokes WHERE session_id=?').get(sessionId).m; const maxFromPages = db.prepare('SELECT COALESCE(MAX(page_num), 1) AS m FROM classroom_pages WHERE session_id=?').get(sessionId).m; const newPage = Math.max(session.current_page, maxFromStrokes, maxFromPages) + 1; const template = req.body?.template || 'blank'; db.prepare('INSERT OR IGNORE INTO classroom_pages (session_id, page_num, template) VALUES (?,?,?)').run(sessionId, newPage, template); db.prepare('UPDATE classroom_sessions SET current_page=? WHERE id=?').run(newPage, sessionId); emitToSession(sessionId, { type: 'classroom_page_added', sessionId, pageNum: newPage, template }); res.json({ pageNum: newPage, template }); } function changePage(req, res) { const sessionId = Number(req.params.id); const page_num = Number(req.body?.page_num); if (!Number.isInteger(page_num) || page_num < 1) return res.status(400).json({ error: 'page_num required (positive integer)' }); const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); db.prepare('UPDATE classroom_sessions SET current_page=? WHERE id=?').run(page_num, sessionId); emitToSession(sessionId, { type: 'classroom_page_changed', sessionId, pageNum: Number(page_num) }); res.json({ pageNum: Number(page_num) }); } function updatePageTemplate(req, res) { const sessionId = Number(req.params.id); const { template } = req.body; if (!template) return res.status(400).json({ error: 'template required' }); const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); db.prepare('INSERT OR IGNORE INTO classroom_pages (session_id, page_num, template) VALUES (?,?,?)').run(sessionId, session.current_page, template); db.prepare('UPDATE classroom_pages SET template=? WHERE session_id=? AND page_num=?').run(template, sessionId, session.current_page); emitToSession(sessionId, { type: 'classroom_template_changed', sessionId, pageNum: session.current_page, template }); res.json({ ok: true, template }); } function updateBoardTheme(req, res) { const sessionId = Number(req.params.id); const VALID_THEMES = new Set(['chalkboard', 'blackboard', 'corkboard', 'whiteboard']); const { theme } = req.body; if (!theme || !VALID_THEMES.has(theme)) return res.status(400).json({ error: 'invalid theme' }); const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); db.prepare('UPDATE classroom_sessions SET board_theme=? WHERE id=?').run(theme, sessionId); emitToSession(sessionId, { type: 'classroom_board_theme', sessionId, theme }); res.json({ ok: true, theme }); } function renamePage(req, res) { const sessionId = Number(req.params.id); const pageNum = Number(req.params.pageNum); const { name } = req.body; const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); db.prepare('INSERT OR IGNORE INTO classroom_pages (session_id, page_num, template) VALUES (?,?,?)').run(sessionId, pageNum, 'blank'); db.prepare('UPDATE classroom_pages SET name=? WHERE session_id=? AND page_num=?').run(name || null, sessionId, pageNum); emitToSession(sessionId, { type: 'classroom_page_renamed', sessionId, pageNum, name: name || null }); res.json({ ok: true, pageNum, name: name || null }); } function duplicatePage(req, res) { const sessionId = Number(req.params.id); const srcPage = Number(req.params.pageNum); const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); const srcRow = db.prepare('SELECT template, name FROM classroom_pages WHERE session_id=? AND page_num=?').get(sessionId, srcPage); const srcTpl = srcRow?.template || 'blank'; const newName = srcRow?.name ? srcRow.name + ' (копия)' : null; const maxS = db.prepare('SELECT COALESCE(MAX(page_num),0) AS m FROM classroom_strokes WHERE session_id=?').get(sessionId).m; const maxP = db.prepare('SELECT COALESCE(MAX(page_num),0) AS m FROM classroom_pages WHERE session_id=?').get(sessionId).m; const newPage = Math.max(session.current_page, maxS, maxP) + 1; db.prepare('INSERT OR IGNORE INTO classroom_pages (session_id, page_num, template, name) VALUES (?,?,?,?)').run(sessionId, newPage, srcTpl, newName); const strokes = db.prepare('SELECT tool, data, user_id FROM classroom_strokes WHERE session_id=? AND page_num=? ORDER BY seq').all(sessionId, srcPage); const ins = db.prepare('INSERT INTO classroom_strokes (session_id, page_num, tool, data, user_id, seq) VALUES (?,?,?,?,?,?)'); db.transaction(() => { strokes.forEach((s, i) => ins.run(sessionId, newPage, s.tool, s.data, s.user_id, i + 1)); })(); db.prepare('UPDATE classroom_sessions SET current_page=? WHERE id=?').run(newPage, sessionId); emitToSession(sessionId, { type: 'classroom_page_duplicated', sessionId, srcPage, newPage, template: srcTpl, name: newName }); res.json({ ok: true, newPage, template: srcTpl, name: newName }); } function deletePage(req, res) { const sessionId = Number(req.params.id); const pageNum = Number(req.params.pageNum); const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); if (!session) return res.status(404).json({ error: 'Сессия не активна' }); if (session.teacher_id !== req.user.id && req.user.role !== 'admin') return res.status(403).json({ error: 'Нет доступа' }); const maxS = db.prepare('SELECT COALESCE(MAX(page_num),0) AS m FROM classroom_strokes WHERE session_id=?').get(sessionId).m; const maxP = db.prepare('SELECT COALESCE(MAX(page_num),0) AS m FROM classroom_pages WHERE session_id=?').get(sessionId).m; const total = Math.max(session.current_page, maxS, maxP, 1); if (total <= 1) return res.status(400).json({ error: 'Нельзя удалить единственную страницу' }); db.transaction(() => { db.prepare('DELETE FROM classroom_strokes WHERE session_id=? AND page_num=?').run(sessionId, pageNum); db.prepare('DELETE FROM classroom_pages WHERE session_id=? AND page_num=?').run(sessionId, pageNum); db.prepare('UPDATE classroom_strokes SET page_num=page_num-1 WHERE session_id=? AND page_num>?').run(sessionId, pageNum); db.prepare('UPDATE classroom_pages SET page_num=page_num-1 WHERE session_id=? AND page_num>?').run(sessionId, pageNum); })(); let newCurrent = session.current_page; if (newCurrent > pageNum) newCurrent--; else if (newCurrent === pageNum) newCurrent = Math.max(1, pageNum - 1); db.prepare('UPDATE classroom_sessions SET current_page=? WHERE id=?').run(newCurrent, sessionId); emitToSession(sessionId, { type: 'classroom_page_deleted', sessionId, pageNum, newCurrent }); res.json({ ok: true, pageNum, newCurrent }); } module.exports = { getPages, addPage, changePage, updatePageTemplate, updateBoardTheme, renamePage, duplicatePage, deletePage, };