const express = require('express'); const router = express.Router(); const { db } = require('./database'); const requireAdmin = (req, res, next) => { if (!req.session.user) { return res.status(401).json({ error: 'Требуется аутентификация' }); } if (req.session.user.role !== 'admin') { return res.status(403).json({ error: 'Недостаточно прав' }); } next(); }; router.get('/admin/users', requireAdmin, (req, res) => { const search = req.query.search || ''; let query = ` SELECT id, login, name, email, role, auth_type, groups, description, created_at, last_login, updated_at FROM users WHERE 1=1 `; const params = []; if (search) { query += ` AND (login LIKE ? OR name LIKE ? OR email LIKE ?)`; const searchPattern = `%${search}%`; params.push(searchPattern, searchPattern, searchPattern); } query += " ORDER BY name"; db.all(query, params, (err, users) => { if (err) { res.status(500).json({ error: err.message }); return; } res.json(users); }); }); router.get('/admin/users/:id', requireAdmin, (req, res) => { const { id } = req.params; db.get("SELECT id, login, name, email, role, auth_type, groups, description FROM users WHERE id = ?", [id], (err, user) => { if (err) { res.status(500).json({ error: err.message }); return; } if (!user) { res.status(404).json({ error: 'Пользователь не найден' }); return; } res.json(user); }); }); router.put('/admin/users/:id', requireAdmin, (req, res) => { const { id } = req.params; const { login, name, email, role, auth_type, groups, description } = req.body; if (!login || !name || !email) { return res.status(400).json({ error: 'Логин, имя и email обязательны' }); } if (req.session.user.id === parseInt(id) && role !== 'admin') { return res.status(400).json({ error: 'Нельзя снять права администратора с самого себя' }); } db.get("SELECT id FROM users WHERE (login = ? OR email = ?) AND id != ?", [login, email, id], (err, existingUser) => { if (err) { res.status(500).json({ error: err.message }); return; } if (existingUser) { return res.status(400).json({ error: 'Пользователь с таким логином или email уже существует' }); } db.run( `UPDATE users SET login = ?, name = ?, email = ?, role = ?, auth_type = ?, groups = ?, description = ?, updated_at = datetime('now') WHERE id = ?`, [ login, name, email, role || 'teacher', auth_type || 'local', groups || '[]', description || '', id ], function(err) { if (err) { res.status(500).json({ error: err.message }); return; } if (this.changes === 0) { return res.status(404).json({ error: 'Пользователь не найден' }); } res.json({ success: true, message: 'Пользователь обновлен' }); } ); } ); }); router.delete('/admin/users/:id', requireAdmin, (req, res) => { const { id } = req.params; if (req.session.user.id === parseInt(id)) { return res.status(400).json({ error: 'Нельзя удалить самого себя' }); } db.get("SELECT COUNT(*) as task_count FROM tasks WHERE created_by = ?", [id], (err, result) => { if (err) { res.status(500).json({ error: err.message }); return; } if (result.task_count > 0) { return res.status(400).json({ error: 'Нельзя удалить пользователя, который создавал задачи. Сначала удалите или переназначьте его задачи.' }); } db.run("DELETE FROM users WHERE id = ?", [id], function(err) { if (err) { res.status(500).json({ error: err.message }); return; } if (this.changes === 0) { return res.status(404).json({ error: 'Пользователь не найден' }); } res.json({ success: true, message: 'Пользователь удален' }); }); }); }); router.get('/admin/stats', requireAdmin, (req, res) => { const stats = {}; const queries = [ // Общая статистика по задачам `SELECT COUNT(*) as total_tasks FROM tasks`, `SELECT COUNT(*) as active_tasks FROM tasks WHERE status = 'active' AND closed_at IS NULL`, `SELECT COUNT(*) as closed_tasks FROM tasks WHERE closed_at IS NOT NULL`, `SELECT COUNT(*) as deleted_tasks FROM tasks WHERE status = 'deleted'`, `SELECT COUNT(DISTINCT created_by) as unique_creators FROM tasks`, // Статистика по статусам назначений `SELECT COUNT(*) as total_assignments FROM task_assignments`, `SELECT COUNT(*) as assigned_count FROM task_assignments WHERE status = 'assigned'`, `SELECT COUNT(*) as in_progress_count FROM task_assignments WHERE status = 'in_progress'`, `SELECT COUNT(*) as completed_count FROM task_assignments WHERE status = 'completed'`, `SELECT COUNT(*) as overdue_count FROM task_assignments WHERE status = 'overdue'`, `SELECT COUNT(*) as rework_count FROM task_assignments WHERE status = 'rework'`, // Статистика по пользователям `SELECT COUNT(*) as total_users FROM users`, `SELECT COUNT(*) as admin_users FROM users WHERE role = 'admin'`, `SELECT COUNT(*) as teacher_users FROM users WHERE role = 'teacher'`, `SELECT COUNT(*) as ldap_users FROM users WHERE auth_type = 'ldap'`, `SELECT COUNT(*) as local_users FROM users WHERE auth_type = 'local'`, // Статистика по файлам `SELECT COUNT(*) as total_files FROM task_files`, `SELECT COALESCE(SUM(file_size), 0) as total_files_size FROM task_files`, // Последние созданные задачи `SELECT t.id, t.title, t.created_at, u.name as creator_name FROM tasks t LEFT JOIN users u ON t.created_by = u.id WHERE t.status = 'active' ORDER BY t.created_at DESC LIMIT 5` ]; const queryPromises = queries.map((query, index) => { return new Promise((resolve, reject) => { db.all(query, [], (err, rows) => { if (err) { reject(err); } else { resolve({ index, rows }); } }); }); }); Promise.all(queryPromises) .then(results => { const [ totalTasks, activeTasks, closedTasks, deletedTasks, uniqueCreators, totalAssignments, assignedCount, inProgressCount, completedCount, overdueCount, reworkCount, totalUsers, adminUsers, teacherUsers, ldapUsers, localUsers, totalFiles, totalFilesSize, recentTasks ] = results; stats.totalTasks = totalTasks.rows[0].total_tasks; stats.activeTasks = activeTasks.rows[0].active_tasks; stats.closedTasks = closedTasks.rows[0].closed_tasks; stats.deletedTasks = deletedTasks.rows[0].deleted_tasks; stats.uniqueCreators = uniqueCreators.rows[0].unique_creators; stats.totalAssignments = totalAssignments.rows[0].total_assignments; stats.assignedCount = assignedCount.rows[0].assigned_count; stats.inProgressCount = inProgressCount.rows[0].in_progress_count; stats.completedCount = completedCount.rows[0].completed_count; stats.overdueCount = overdueCount.rows[0].overdue_count; stats.reworkCount = reworkCount.rows[0].rework_count; stats.totalUsers = totalUsers.rows[0].total_users; stats.adminUsers = adminUsers.rows[0].admin_users; stats.teacherUsers = teacherUsers.rows[0].teacher_users; stats.ldapUsers = ldapUsers.rows[0].ldap_users; stats.localUsers = localUsers.rows[0].local_users; stats.totalFiles = totalFiles.rows[0].total_files; stats.totalFilesSize = totalFilesSize.rows[0].total_files_size; stats.recentTasks = recentTasks.rows; res.json(stats); }) .catch(err => { res.status(500).json({ error: err.message }); }); }); module.exports = router;