Files
minicrm/admin-server.js
2025-12-14 14:22:26 +05:00

251 lines
9.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;