refactor: split classroomController.js into 7 domain files (phase 2 of 2)
1618-line monolith split into: classroom/_shared.js — GUEST_EVENTS, emitToSession, hasAccess, canDraw classroom/sessions.js — lifecycle + guest tokens (12 functions) classroom/strokes.js — CRUD + cursor + preview (7 functions) classroom/pages.js — page CRUD + theme (8 functions) classroom/chat.js — messages, reactions, attachments, export (7 functions) classroom/permissions.js — draw, hand, mute, screen, attendance (11 functions) classroom/sim.js — simulation relay (5 functions) classroom/admin.js — history, notes, templates, admin views (14 functions) classroomController.js is now a 9-line re-export facade. routes/classroom.js unchanged. All 65 exports verified. Tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
'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 } = req.body;
|
||||
if (!page_num) return res.status(400).json({ error: 'page_num 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('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('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 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, seq) VALUES (?,?,?,?,?)');
|
||||
db.transaction(() => { strokes.forEach((s, i) => ins.run(sessionId, newPage, s.tool, s.data, 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,
|
||||
};
|
||||
Reference in New Issue
Block a user