// group-management.js const express = require('express'); const router = express.Router(); function setupGroupManagement(app, db) { // Middleware для проверки администратора function requireAdmin(req, res, next) { if (!req.session.user || req.session.user.role !== 'admin') { return res.status(403).json({ error: 'Недостаточно прав' }); } next(); } // API для получения всех групп router.get('/api/groups', requireAdmin, (req, res) => { db.all(` SELECT g.*, COUNT(DISTINCT ugm.user_id) as member_count FROM user_groups g LEFT JOIN user_group_memberships ugm ON g.id = ugm.group_id GROUP BY g.id ORDER BY g.name `, [], (err, groups) => { if (err) { console.error('❌ Ошибка получения групп:', err); return res.status(500).json({ error: 'Ошибка получения групп' }); } res.json(groups || []); }); }); // API для получения одной группы с участниками router.get('/api/groups/:groupId', requireAdmin, (req, res) => { const { groupId } = req.params; db.get(` SELECT g.*, COUNT(DISTINCT ugm.user_id) as member_count FROM user_groups g LEFT JOIN user_group_memberships ugm ON g.id = ugm.group_id WHERE g.id = ? GROUP BY g.id `, [groupId], (err, group) => { if (err || !group) { return res.status(404).json({ error: 'Группа не найдена' }); } // Получаем участников группы db.all(` SELECT u.id, u.login, u.name, u.email, u.role FROM users u JOIN user_group_memberships ugm ON u.id = ugm.user_id WHERE ugm.group_id = ? ORDER BY u.name `, [groupId], (err, members) => { if (err) { console.error('❌ Ошибка получения участников:', err); return res.status(500).json({ error: 'Ошибка получения участников' }); } res.json({ ...group, members: members || [] }); }); }); }); // API для создания новой группы router.post('/api/groups', requireAdmin, (req, res) => { const { name, description, color, can_approve_documents } = req.body; if (!name) { return res.status(400).json({ error: 'Название группы обязательно' }); } db.run(` INSERT INTO user_groups (name, description, color, can_approve_documents) VALUES (?, ?, ?, ?) `, [ name.trim(), description || '', color || '#3498db', can_approve_documents ? 1 : 0 ], function(err) { if (err) { console.error('❌ Ошибка создания группы:', err); return res.status(500).json({ error: 'Ошибка создания группы', details: err.message.includes('UNIQUE') ? 'Группа с таким названием уже существует' : err.message }); } res.json({ success: true, groupId: this.lastID, message: 'Группа создана успешно' }); }); }); // API для обновления группы router.put('/api/groups/:groupId', requireAdmin, (req, res) => { const { groupId } = req.params; const { name, description, color, can_approve_documents } = req.body; if (!name) { return res.status(400).json({ error: 'Название группы обязательно' }); } db.run(` UPDATE user_groups SET name = ?, description = ?, color = ?, can_approve_documents = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? `, [ name.trim(), description || '', color || '#3498db', can_approve_documents ? 1 : 0, groupId ], function(err) { if (err) { console.error('❌ Ошибка обновления группы:', err); return res.status(500).json({ error: 'Ошибка обновления группы', details: err.message.includes('UNIQUE') ? 'Группа с таким названием уже существует' : err.message }); } if (this.changes === 0) { return res.status(404).json({ error: 'Группа не найдена' }); } res.json({ success: true, message: 'Группа обновлена успешно' }); }); }); // API для удаления группы router.delete('/api/groups/:groupId', requireAdmin, (req, res) => { const { groupId } = req.params; db.run(`DELETE FROM user_groups WHERE id = ?`, [groupId], function(err) { if (err) { console.error('❌ Ошибка удаления группы:', err); return res.status(500).json({ error: 'Ошибка удаления группы' }); } if (this.changes === 0) { return res.status(404).json({ error: 'Группа не найдена' }); } res.json({ success: true, message: 'Группа удалена успешно' }); }); }); // API для добавления пользователя в группу router.post('/api/groups/:groupId/members', requireAdmin, (req, res) => { const { groupId } = req.params; const { userId } = req.body; if (!userId) { return res.status(400).json({ error: 'ID пользователя обязательно' }); } // Проверяем существование группы и пользователя db.get(`SELECT id FROM user_groups WHERE id = ?`, [groupId], (err, group) => { if (err || !group) { return res.status(404).json({ error: 'Группа не найдена' }); } db.get(`SELECT id FROM users WHERE id = ?`, [userId], (err, user) => { if (err || !user) { return res.status(404).json({ error: 'Пользователь не найден' }); } db.run(` INSERT OR IGNORE INTO user_group_memberships (user_id, group_id) VALUES (?, ?) `, [userId, groupId], function(err) { if (err) { console.error('❌ Ошибка добавления пользователя в группу:', err); return res.status(500).json({ error: 'Ошибка добавления пользователя в группу' }); } res.json({ success: true, message: 'Пользователь добавлен в группу' }); }); }); }); }); // API для удаления пользователя из группы router.delete('/api/groups/:groupId/members/:userId', requireAdmin, (req, res) => { const { groupId, userId } = req.params; db.run(` DELETE FROM user_group_memberships WHERE user_id = ? AND group_id = ? `, [userId, groupId], function(err) { if (err) { console.error('❌ Ошибка удаления пользователя из группы:', err); return res.status(500).json({ error: 'Ошибка удаления пользователя из группы' }); } if (this.changes === 0) { return res.status(404).json({ error: 'Пользователь не найден в группе' }); } res.json({ success: true, message: 'Пользователь удален из группы' }); }); }); // API для получения всех пользователей с их группами router.get('/api/users-with-groups', requireAdmin, (req, res) => { db.all(` SELECT u.id, u.login, u.name, u.email, u.role, GROUP_CONCAT(DISTINCT g.name) as group_names, GROUP_CONCAT(DISTINCT g.id) as group_ids FROM users u LEFT JOIN user_group_memberships ugm ON u.id = ugm.user_id LEFT JOIN user_groups g ON ugm.group_id = g.id WHERE u.role IN ('admin', 'teacher') GROUP BY u.id ORDER BY u.name `, [], (err, users) => { if (err) { console.error('❌ Ошибка получения пользователей с группами:', err); return res.status(500).json({ error: 'Ошибка получения данных' }); } // Преобразуем строки в массивы const formattedUsers = users.map(user => ({ ...user, group_names: user.group_names ? user.group_names.split(',') : [], group_ids: user.group_ids ? user.group_ids.split(',').map(id => parseInt(id)) : [] })); res.json(formattedUsers); }); }); // API для получения доступных групп для пользователя router.get('/api/users/:userId/available-groups', requireAdmin, (req, res) => { const { userId } = req.params; db.all(` SELECT g.*, CASE WHEN ugm.user_id IS NOT NULL THEN 1 ELSE 0 END as is_member FROM user_groups g LEFT JOIN user_group_memberships ugm ON g.id = ugm.group_id AND ugm.user_id = ? ORDER BY g.name `, [userId], (err, groups) => { if (err) { console.error('❌ Ошибка получения групп:', err); return res.status(500).json({ error: 'Ошибка получения данных' }); } res.json(groups || []); }); }); // API для массового обновления групп пользователя router.put('/api/users/:userId/groups', requireAdmin, (req, res) => { const { userId } = req.params; const { groupIds } = req.body; // массив ID групп if (!Array.isArray(groupIds)) { return res.status(400).json({ error: 'groupIds должен быть массивом' }); } // Проверяем существование пользователя db.get(`SELECT id FROM users WHERE id = ?`, [userId], (err, user) => { if (err || !user) { return res.status(404).json({ error: 'Пользователь не найден' }); } db.serialize(() => { // Удаляем все текущие группы пользователя db.run(`DELETE FROM user_group_memberships WHERE user_id = ?`, [userId], (err) => { if (err) { console.error('❌ Ошибка удаления старых групп:', err); return res.status(500).json({ error: 'Ошибка обновления групп' }); } // Добавляем новые группы if (groupIds.length > 0) { const placeholders = groupIds.map(() => '(?, ?)').join(','); const values = groupIds.reduce((acc, groupId) => { acc.push(userId, groupId); return acc; }, []); db.run(` INSERT INTO user_group_memberships (user_id, group_id) VALUES ${placeholders} `, values, (err) => { if (err) { console.error('❌ Ошибка добавления новых групп:', err); return res.status(500).json({ error: 'Ошибка обновления групп' }); } res.json({ success: true, message: 'Группы пользователя обновлены' }); }); } else { res.json({ success: true, message: 'Группы пользователя обновлены' }); } }); }); }); }); // API для получения пользователей, которые могут согласовывать документы router.get('/api/approvers', requireAdmin, (req, res) => { db.all(` SELECT DISTINCT u.id, u.login, u.name, u.email, u.role, g.name as group_name, g.color as group_color FROM users u JOIN user_group_memberships ugm ON u.id = ugm.user_id JOIN user_groups g ON ugm.group_id = g.id WHERE g.can_approve_documents = 1 ORDER BY u.name `, [], (err, approvers) => { if (err) { console.error('❌ Ошибка получения согласующих:', err); return res.status(500).json({ error: 'Ошибка получения данных' }); } res.json(approvers || []); }); }); // API для получения групп, которые могут согласовывать документы router.get('/api/approver-groups', (req, res) => { const isAdmin = req.session.user && req.session.user.role === 'admin'; db.all(` SELECT g.*, COUNT(DISTINCT ugm.user_id) as member_count FROM user_groups g LEFT JOIN user_group_memberships ugm ON g.id = ugm.group_id WHERE g.can_approve_documents = 1 GROUP BY g.id ORDER BY g.name `, [], (err, groups) => { if (err) { console.error('❌ Ошибка получения групп согласующих:', err); return res.status(500).json({ error: 'Ошибка получения данных' }); } // Для обычных пользователей скрываем ID пользователей в группах if (!isAdmin) { groups = groups.map(group => ({ ...group, members: undefined })); } res.json(groups || []); }); }); return router; } module.exports = { setupGroupManagement };