const db = require('../db/db'); /* ── All known permissions ─────────────────────────────────────────────── */ const ALL_PERMISSIONS = [ /* ── Teacher ── */ { key: 'questions.manage', role: 'teacher', label: 'Управление вопросами', desc: 'Создавать, редактировать и копировать вопросы в банке', default: 0, }, { key: 'questions.delete', role: 'teacher', label: 'Удалять вопросы', desc: 'Удалять вопросы из банка (требует "Управление вопросами")', default: 0, }, { key: 'students.invite', role: 'teacher', label: 'Регистрировать учеников', desc: 'Создавать новые аккаунты учеников напрямую из панели', default: 0, }, { key: 'sessions.reset', role: 'teacher', label: 'Сброс попыток', desc: 'Сбрасывать прохождение теста ученика в своём классе', default: 1, }, { key: 'results.export', role: 'teacher', label: 'Экспорт результатов', desc: 'Выгружать результаты и оценки класса в CSV', default: 1, }, { key: 'classes.manage', role: 'teacher', label: 'Управление классами', desc: 'Создавать, редактировать и удалять свои классы', default: 1, }, { key: 'library.upload', role: 'teacher', label: 'Загрузка файлов', desc: 'Загружать файлы в библиотеку', default: 1, }, { key: 'library.folders', role: 'teacher', label: 'Управление папками', desc: 'Создавать папки и настраивать доступ к ним', default: 1, }, { key: 'schedule.manage', role: 'teacher', label: 'Дедлайны заданий', desc: 'Устанавливать дедлайны и временные окна для заданий', default: 1, }, { key: 'announcements.send', role: 'teacher', label: 'Объявления', desc: 'Публиковать объявления в своих классах', default: 1, }, { key: 'templates.manage', role: 'teacher', label: 'Управление шаблонами', desc: 'Создавать и использовать шаблоны курсов и уроков', default: 1, }, { key: 'templates.public', role: 'teacher', label: 'Публикация шаблонов', desc: 'Делать свои шаблоны публичными для всех учителей', default: 0, }, { key: 'courses.manage', role: 'teacher', label: 'Управление курсами', desc: 'Создавать и редактировать теоретические курсы и уроки', default: 1, }, { key: 'courses.interactive', role: 'teacher', label: 'Интерактивные блоки', desc: 'Добавлять интерактивные задания в уроки (сопоставление, пропуски, порядок)', default: 1, }, { key: 'shop.manage', role: 'teacher', label: 'Управление магазином', desc: 'Создавать и редактировать товары в магазине наград', default: 0, }, { key: 'gamification.manage', role: 'teacher', label: 'Управление геймификацией', desc: 'Начислять XP/монеты ученикам, управлять достижениями', default: 0, }, /* ── Student ── */ { key: 'tests.free', role: 'student', label: 'Свободные тесты', desc: 'Проходить тесты без задания (по предмету / случайно)', default: 1, }, { key: 'board.post', role: 'student', label: 'Реакции на доске', desc: 'Ставить реакции на задания на доске', default: 1, }, { key: 'profile.edit', role: 'student', label: 'Редактирование профиля', desc: 'Изменять своё имя и пароль', default: 1, }, { key: 'shop.purchase', role: 'student', label: 'Покупки в магазине', desc: 'Покупать предметы в магазине наград за монеты', default: 1, }, { key: 'gamification.challenges', role: 'student', label: 'Испытания недели', desc: 'Участвовать в еженедельных испытаниях и получать награды', default: 1, }, { key: 'theory.access', role: 'student', label: 'Доступ к теории', desc: 'Просматривать теоретические курсы и уроки', default: 1, }, { key: 'simulations.access', role: 'student', label: 'Доступ к симуляциям', desc: 'Открывать лабораторию с физическими, химическими и биологическими симуляциями', default: 1, }, { key: 'simulations.quiz', role: 'student', label: 'Задания в симуляциях', desc: 'Использовать режим "Задания" в симуляциях (квиз-режим)', default: 1, }, ]; /* ── Seed defaults once per startup ───────────────────────────────────── */ function seedDefaults() { const upsert = db.prepare( 'INSERT OR IGNORE INTO role_permissions (role, permission, enabled) VALUES (?, ?, ?)' ); const run = db.transaction(() => { for (const p of ALL_PERMISSIONS) upsert.run(p.role, p.key, p.default); }); run(); } /* ── GET /api/permissions ─────────────────────────────────────────────── */ function getPermissions(_req, res) { seedDefaults(); const rows = db.prepare('SELECT role, permission, enabled FROM role_permissions').all(); const map = { teacher: {}, student: {} }; for (const r of rows) { if (map[r.role]) map[r.role][r.permission] = r.enabled === 1; } res.json({ permissions: map, definitions: ALL_PERMISSIONS }); } /* ── POST /api/permissions { role, permission, enabled } ─────────────── */ function setPermission(req, res) { const { role, permission, enabled } = req.body; if (!['teacher', 'student'].includes(role)) return res.status(400).json({ error: 'Invalid role' }); if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === role)) return res.status(400).json({ error: 'Unknown permission' }); db.prepare( 'INSERT OR REPLACE INTO role_permissions (role, permission, enabled) VALUES (?, ?, ?)' ).run(role, permission, enabled ? 1 : 0); res.json({ ok: true }); } /* ── GET /api/permissions/me (any authenticated user) ───────────────── */ function getMyPermissions(req, res) { const uid = req.user.id; const role = req.user.role; if (role === 'admin') return res.json({ role, permissions: [] }); // admins bypass all seedDefaults(); const roleRows = db.prepare( 'SELECT permission, enabled FROM role_permissions WHERE role = ?' ).all(role); const roleMap = {}; for (const r of roleRows) roleMap[r.permission] = r.enabled === 1; const userRows = db.prepare( 'SELECT permission, enabled FROM user_permissions WHERE user_id = ?' ).all(uid); const userMap = {}; for (const r of userRows) userMap[r.permission] = r.enabled === 1; const defs = ALL_PERMISSIONS.filter(p => p.role === role); const result = defs.map(d => ({ key: d.key, effective: userMap[d.key] !== undefined ? userMap[d.key] : (roleMap[d.key] ?? !!d.default), })); res.json({ role, permissions: result }); } /* ── GET /api/permissions/users/:id ──────────────────────────────────── */ function getUserPermissions(req, res) { const uid = Number(req.params.id); const target = require('../db/db').prepare('SELECT id, role FROM users WHERE id = ?').get(uid); if (!target) return res.status(404).json({ error: 'User not found' }); seedDefaults(); // role-level values const roleRows = require('../db/db').prepare( 'SELECT permission, enabled FROM role_permissions WHERE role = ?' ).all(target.role); const roleMap = {}; for (const r of roleRows) roleMap[r.permission] = r.enabled === 1; // user-level overrides const userRows = require('../db/db').prepare( 'SELECT permission, enabled FROM user_permissions WHERE user_id = ?' ).all(uid); const userMap = {}; for (const r of userRows) userMap[r.permission] = r.enabled === 1; const defs = ALL_PERMISSIONS.filter(p => p.role === target.role); const result = defs.map(d => ({ key: d.key, label: d.label, desc: d.desc, roleVal: roleMap[d.key] ?? d.default, // effective role-level value userVal: userMap[d.key], // undefined = no override effective: userMap[d.key] !== undefined ? userMap[d.key] : (roleMap[d.key] ?? !!d.default), })); res.json({ role: target.role, permissions: result }); } /* ── POST /api/permissions/users/:id { permission, enabled } ─────────── */ function setUserPermission(req, res) { const uid = Number(req.params.id); const { permission, enabled } = req.body; const target = require('../db/db').prepare('SELECT role FROM users WHERE id = ?').get(uid); if (!target) return res.status(404).json({ error: 'User not found' }); if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === target.role)) return res.status(400).json({ error: 'Unknown permission for this role' }); require('../db/db').prepare( 'INSERT OR REPLACE INTO user_permissions (user_id, permission, enabled) VALUES (?, ?, ?)' ).run(uid, permission, enabled ? 1 : 0); res.json({ ok: true }); } /* ── DELETE /api/permissions/users/:id/reset (single or all) ─────────── */ function resetUserPermissions(req, res) { const uid = Number(req.params.id); const { permission } = req.body; // optional: reset one key if (permission) { require('../db/db').prepare( 'DELETE FROM user_permissions WHERE user_id = ? AND permission = ?' ).run(uid, permission); } else { require('../db/db').prepare('DELETE FROM user_permissions WHERE user_id = ?').run(uid); } res.json({ ok: true }); } module.exports = { getPermissions, setPermission, seedDefaults, ALL_PERMISSIONS, getMyPermissions, getUserPermissions, setUserPermission, resetUserPermissions };