Files
Learn_System/backend/src/controllers/analyticsController.js
T
Maxim Dolgolyov be4d43105e LearnSpace: full-stack educational whiteboard platform
Node.js/Express backend + vanilla JS frontend.
Features: real-time collaborative whiteboard (SSE), multi-page support,
LaTeX formulas, shapes/connectors, coordinate systems, number lines,
compass, zoom/pan, Catmull-Rom pencil smoothing, ruler/protractor with
rotation & resize controls, minimap navigation overlay, auto-measurements,
multi-page thumbnails sidebar, PNG export, page templates.
Student/teacher workflows: classes, assignments, library, dashboard.
Mobile responsive. SQLite (better-sqlite3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 10:10:37 +03:00

81 lines
3.0 KiB
JavaScript

const db = require('../db/db');
function teacherOverview(req, res) {
const user = req.user;
const classId = req.query.classId ? Number(req.query.classId) : null;
const classes = user.role === 'admin'
? db.prepare('SELECT id, name FROM classes ORDER BY name').all()
: db.prepare('SELECT id, name FROM classes WHERE teacher_id = ? ORDER BY name').all(user.id);
if (!classId) return res.json({ classes, data: null });
if (user.role !== 'admin') {
const cls = db.prepare('SELECT id FROM classes WHERE id = ? AND teacher_id = ?').get(classId, user.id);
if (!cls) return res.status(403).json({ error: 'Forbidden' });
}
const overview = db.prepare(`
SELECT
COUNT(DISTINCT cm.user_id) AS students,
COUNT(DISTINCT CASE WHEN ts.status='completed' THEN ts.id END) AS sessions,
ROUND(AVG(CASE WHEN ts.status='completed' AND ts.total>0
THEN ts.score*100.0/ts.total END), 1) AS avgScore
FROM class_members cm
LEFT JOIN test_sessions ts ON ts.user_id = cm.user_id
WHERE cm.class_id = ?
`).get(classId);
const scoreByWeek = db.prepare(`
SELECT
strftime('%Y-W%W', ts.finished_at) AS week,
ROUND(AVG(ts.score*100.0/ts.total), 1) AS avg,
COUNT(*) AS sessions
FROM test_sessions ts
JOIN class_members cm ON cm.user_id = ts.user_id AND cm.class_id = ?
WHERE ts.status='completed' AND ts.total>0
AND ts.finished_at >= datetime('now','-56 days')
GROUP BY week ORDER BY week
`).all(classId);
const hardQuestions = db.prepare(`
SELECT q.id, q.text, q.difficulty,
COUNT(ua.id) AS attempts,
ROUND(SUM(CASE WHEN ua.is_correct=0 THEN 1.0 ELSE 0 END)*100/COUNT(ua.id),1) AS errorRate,
t.name AS topic
FROM user_answers ua
JOIN questions q ON q.id = ua.question_id
JOIN test_sessions ts ON ts.id = ua.session_id
JOIN class_members cm ON cm.user_id = ts.user_id AND cm.class_id = ?
LEFT JOIN topics t ON t.id = q.topic_id
WHERE ts.status='completed'
GROUP BY q.id HAVING attempts >= 3
ORDER BY errorRate DESC LIMIT 10
`).all(classId);
const heatmap = db.prepare(`
SELECT date(ts.started_at) AS day,
COUNT(DISTINCT ts.user_id) AS students,
COUNT(ts.id) AS sessions
FROM test_sessions ts
JOIN class_members cm ON cm.user_id = ts.user_id AND cm.class_id = ?
WHERE ts.started_at >= datetime('now','-90 days')
GROUP BY day ORDER BY day
`).all(classId);
const assignments = db.prepare(`
SELECT a.id, a.title, a.deadline,
COUNT(DISTINCT cm.user_id) AS total,
COUNT(DISTINCT CASE WHEN ass.session_id IS NOT NULL THEN ass.user_id END) AS done
FROM assignments a
JOIN class_members cm ON cm.class_id = a.class_id
LEFT JOIN assignment_sessions ass ON ass.assignment_id=a.id AND ass.user_id=cm.user_id
WHERE a.class_id = ?
GROUP BY a.id ORDER BY a.created_at DESC LIMIT 10
`).all(classId);
res.json({ classes, overview, scoreByWeek, hardQuestions, heatmap, assignments });
}
module.exports = { teacherOverview };