From 92e3ed50c5f051e65263104844033897e6f812b3 Mon Sep 17 00:00:00 2001 From: kalugin66 <150135283+kalugin1988@users.noreply.github.com> Date: Sun, 30 Nov 2025 14:11:05 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth.js | 36 ++++++++++--- server.js | 149 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 128 insertions(+), 57 deletions(-) diff --git a/auth.js b/auth.js index 2ed8ab8..059a893 100644 --- a/auth.js +++ b/auth.js @@ -91,6 +91,9 @@ class AuthService { const isValid = await bcrypt.compare(password, user.password); if (isValid) { + // Обновляем last_login + db.run("UPDATE users SET last_login = datetime('now') WHERE id = ?", [user.id]); + // Не возвращаем пароль const { password, ...userWithoutPassword } = user; resolve(userWithoutPassword); @@ -135,7 +138,7 @@ class AuthService { const allowedGroups = process.env.ALLOWED_GROUPS ? process.env.ALLOWED_GROUPS.split(',').map(g => g.trim()) : []; - const isAdmin = groups.some(group => + const isAdmin = groups && groups.some(group => allowedGroups.includes(group) ); @@ -151,11 +154,11 @@ class AuthService { const userData = { login: username, - name: full_name, + name: full_name || username, email: `${username}@school25.ru`, role: role, auth_type: 'ldap', - groups: JSON.stringify(groups), + groups: groups ? JSON.stringify(groups) : '[]', description: description || '', last_login: new Date().toISOString() }; @@ -164,14 +167,26 @@ class AuthService { // Обновляем существующего пользователя db.run( `UPDATE users SET - name = ?, email = ?, role = ?, groups = ?, description = ?, last_login = datetime('now') + name = ?, email = ?, role = ?, groups = ?, description = ?, last_login = datetime('now'), + updated_at = datetime('now') WHERE id = ?`, [userData.name, userData.email, userData.role, userData.groups, userData.description, existingUser.id], function(err) { if (err) { reject(err); } else { - resolve({ ...existingUser, ...userData }); + // Возвращаем полные данные пользователя + resolve({ + id: existingUser.id, + login: userData.login, + name: userData.name, + email: userData.email, + role: userData.role, + auth_type: userData.auth_type, + groups: userData.groups, + description: userData.description, + last_login: new Date().toISOString() + }); } } ); @@ -188,7 +203,14 @@ class AuthService { } else { resolve({ id: this.lastID, - ...userData + login: userData.login, + name: userData.name, + email: userData.email, + role: userData.role, + auth_type: userData.auth_type, + groups: userData.groups, + description: userData.description, + last_login: new Date().toISOString() }); } } @@ -216,7 +238,7 @@ class AuthService { getUserById(id) { return new Promise((resolve, reject) => { - db.get("SELECT id, login, name, email, role, auth_type, groups, description FROM users WHERE id = ?", [id], (err, user) => { + db.get("SELECT id, login, name, email, role, auth_type, groups, description, last_login FROM users WHERE id = ?", [id], (err, user) => { if (err) { reject(err); } else { diff --git a/server.js b/server.js index 0222df5..55cd590 100644 --- a/server.js +++ b/server.js @@ -21,10 +21,14 @@ app.use('/uploads', express.static(path.join(__dirname, 'data', 'uploads'))); // Сессии app.use(session({ - secret: process.env.SESSION_SECRET || 'fallback_secret', - resave: false, + secret: process.env.SESSION_SECRET || 'fallback_secret_change_in_production', + resave: true, // Изменено на true для лучшей поддержки LDAP saveUninitialized: false, - cookie: { secure: false, maxAge: 24 * 60 * 60 * 1000 } + cookie: { + secure: false, + maxAge: 24 * 60 * 60 * 1000, + httpOnly: true + } })); // Middleware для проверки аутентификации @@ -80,6 +84,7 @@ function checkIfOverdue(dueDate, status) { const due = new Date(dueDate); return due < now; } + // Функция для проверки просроченных задач function checkOverdueTasks() { const now = new Date().toISOString(); @@ -111,6 +116,7 @@ function checkOverdueTasks() { }); }); } + // ==================== МАРШРУТЫ АУТЕНТИФИКАЦИИ ==================== app.post('/api/login', async (req, res) => { @@ -123,25 +129,37 @@ app.post('/api/login', async (req, res) => { try { const user = await authService.authenticate(login, password); if (user) { - req.session.user = user; + // Подготавливаем данные пользователя для сессии + const sessionUser = { + id: user.id, + login: user.login, + name: user.name, + email: user.email, + role: user.role, + auth_type: user.auth_type, + groups: user.groups ? (typeof user.groups === 'string' ? JSON.parse(user.groups) : user.groups) : [] + }; + + // Сохраняем в сессию + req.session.user = sessionUser; - // Логируем успешный вход - console.log(`Успешная авторизация: ${user.name} (${user.login}) через ${user.auth_type}`); - if (user.groups) { - console.log(`Группы пользователя: ${user.groups}`); - } - - res.json({ - success: true, - user: { - id: user.id, - login: user.login, - name: user.name, - email: user.email, - role: user.role, - auth_type: user.auth_type, - groups: user.groups ? JSON.parse(user.groups) : [] + // Явно сохраняем сессию + req.session.save((err) => { + if (err) { + console.error('Ошибка сохранения сессии:', err); + return res.status(500).json({ error: 'Ошибка сохранения сессии' }); } + + // Логируем успешный вход + console.log(`Успешная авторизация: ${user.name} (${user.login}) через ${user.auth_type}`); + if (user.groups) { + console.log(`Группы пользователя: ${user.groups}`); + } + + res.json({ + success: true, + user: sessionUser + }); }); } else { console.log(`Неудачная попытка входа: ${login}`); @@ -154,13 +172,44 @@ app.post('/api/login', async (req, res) => { }); app.post('/api/logout', (req, res) => { - req.session.destroy(); - res.json({ success: true }); + req.session.destroy((err) => { + if (err) { + console.error('Ошибка при выходе:', err); + return res.status(500).json({ error: 'Ошибка при выходе' }); + } + res.json({ success: true }); + }); }); app.get('/api/user', (req, res) => { if (req.session.user) { - res.json({ user: req.session.user }); + // Обновляем данные пользователя из базы на случай изменений + authService.getUserById(req.session.user.id) + .then(user => { + if (user) { + const updatedUser = { + id: user.id, + login: user.login, + name: user.name, + email: user.email, + role: user.role, + auth_type: user.auth_type, + groups: user.groups ? (typeof user.groups === 'string' ? JSON.parse(user.groups) : user.groups) : [] + }; + + // Обновляем сессию + req.session.user = updatedUser; + res.json({ user: updatedUser }); + } else { + // Пользователь не найден в базе - разлогиниваем + req.session.destroy(); + res.status(401).json({ error: 'Пользователь не найден' }); + } + }) + .catch(err => { + console.error('Ошибка получения пользователя:', err); + res.status(500).json({ error: 'Ошибка сервера' }); + }); } else { res.status(401).json({ error: 'Не аутентифицирован' }); } @@ -435,29 +484,29 @@ app.post('/api/tasks/:taskId/copy', requireAuth, (req, res) => { logActivity(newTaskId, createdBy, 'TASK_COPIED', `Создана копия задачи: ${newTitle}`); - // Копируем файлы из оригинальной задачи - db.all("SELECT * FROM task_files WHERE task_id = ?", [taskId], (err, originalFiles) => { - if (!err && originalFiles && originalFiles.length > 0) { - originalFiles.forEach(originalFile => { - const originalFilePath = originalFile.file_path; - const newFilename = Date.now() + '-' + Math.round(Math.random() * 1E9) + path.extname(originalFile.original_name); - const userFolder = createUserTaskFolder(newTaskId, req.session.user.login); - const newFilePath = path.join(userFolder, newFilename); - - // Копируем файл - if (fs.existsSync(originalFilePath)) { - fs.copyFileSync(originalFilePath, newFilePath); - - db.run( - "INSERT INTO task_files (task_id, user_id, filename, original_name, file_path, file_size) VALUES (?, ?, ?, ?, ?, ?)", - [newTaskId, createdBy, newFilename, originalFile.original_name, newFilePath, originalFile.file_size] - ); - - logActivity(newTaskId, createdBy, 'FILE_COPIED', `Скопирован файл: ${originalFile.original_name}`); - } - }); - } - }); + // Копируем файлы из оригинальной задачи + db.all("SELECT * FROM task_files WHERE task_id = ?", [taskId], (err, originalFiles) => { + if (!err && originalFiles && originalFiles.length > 0) { + originalFiles.forEach(originalFile => { + const originalFilePath = originalFile.file_path; + const newFilename = Date.now() + '-' + Math.round(Math.random() * 1E9) + path.extname(originalFile.original_name); + const userFolder = createUserTaskFolder(newTaskId, req.session.user.login); + const newFilePath = path.join(userFolder, newFilename); + + // Копируем файл + if (fs.existsSync(originalFilePath)) { + fs.copyFileSync(originalFilePath, newFilePath); + + db.run( + "INSERT INTO task_files (task_id, user_id, filename, original_name, file_path, file_size) VALUES (?, ?, ?, ?, ?, ?)", + [newTaskId, createdBy, newFilename, originalFile.original_name, newFilePath, originalFile.file_size] + ); + + logActivity(newTaskId, createdBy, 'FILE_COPIED', `Скопирован файл: ${originalFile.original_name}`); + } + }); + } + }); // Назначаем пользователей if (assignedUsers && assignedUsers.length > 0) { @@ -740,9 +789,6 @@ app.post('/api/tasks/:taskId/reopen', requireAuth, (req, res) => { }); }); -// Остальные маршруты остаются без изменений... -// (Обновить сроки исполнителя, Удалить задачу, Восстановить задачу, Обновить статус, Файлы, Логи) - // Обновить сроки для конкретного исполнителя app.put('/api/tasks/:taskId/assignment/:userId', requireAuth, (req, res) => { const { taskId, userId } = req.params; @@ -756,7 +802,7 @@ app.put('/api/tasks/:taskId/assignment/:userId', requireAuth, (req, res) => { } if (req.session.user.role !== 'admin' && task.created_by !== currentUserId) { - return res.status(403).json({ error: 'У вас нет прав для редактирования сроков' }); + return res.status(403).json({ error: 'У вас нет прав для редактирования сроки' }); } db.run( @@ -1026,4 +1072,7 @@ app.listen(PORT, () => { console.log('- Логин: teacher, Пароль: teacher123'); console.log('LDAP авторизация доступна для пользователей школы'); console.log(`Разрешенные группы: ${process.env.ALLOWED_GROUPS}`); + + // Запускаем проверку просроченных задач каждую минуту + setInterval(checkOverdueTasks, 60000); }); \ No newline at end of file