удалить и другая красота
This commit is contained in:
@@ -141,6 +141,9 @@ if (typeof openChangeDeadlineModal === 'function') { actions.push({ label: '📅
|
|||||||
log('nav-task-actions openChangeDeadlineModal yes');
|
log('nav-task-actions openChangeDeadlineModal yes');
|
||||||
} else {log('nav-task-actions openChangeDeadlineModal not');}
|
} else {log('nav-task-actions openChangeDeadlineModal not');}
|
||||||
}
|
}
|
||||||
|
if (canEdit && !isDeleted && !isClosed && currentUser.role === 'admin') {
|
||||||
|
if (typeof deleteTask === 'function') actions.push({ label: '🗑️ Удалить', handler: () => deleteTask(taskId) });
|
||||||
|
}
|
||||||
|
|
||||||
if (currentUser && currentUser.login === 'minicrm') {
|
if (currentUser && currentUser.login === 'minicrm') {
|
||||||
// Закрытие (только minicrm)
|
// Закрытие (только minicrm)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const chatAPI = require('./api-chat');
|
|||||||
// Подключаем API для управления межсервисным взаимодействием
|
// Подключаем API для управления межсервисным взаимодействием
|
||||||
//const { setupUpravlenieEndpoints } = require('./upravlenie-service');
|
//const { setupUpravlenieEndpoints } = require('./upravlenie-service');
|
||||||
const apiKeysModule = require('./api-keys');
|
const apiKeysModule = require('./api-keys');
|
||||||
|
const taskTimeout = require('./task-timeout');
|
||||||
//
|
//
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
@@ -1615,5 +1616,8 @@ initializeServer().then(() => {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Экспортируем приложение для тестирования
|
// Экспортируем приложение
|
||||||
module.exports = app;
|
module.exports = {
|
||||||
|
app,
|
||||||
|
taskTimeout
|
||||||
|
};
|
||||||
@@ -2,6 +2,42 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Импортируем функции таймаута из отдельного модуля
|
||||||
|
let updateLastTaskCreationTime, checkTaskCreationTimeout;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const taskTimeout = require('./task-timeout');
|
||||||
|
updateLastTaskCreationTime = taskTimeout.updateLastTaskCreationTime;
|
||||||
|
checkTaskCreationTimeout = taskTimeout.checkTaskCreationTimeout;
|
||||||
|
|
||||||
|
if (typeof updateLastTaskCreationTime !== 'function') {
|
||||||
|
console.error('⚠️ updateLastTaskCreationTime не является функцией');
|
||||||
|
updateLastTaskCreationTime = (userId) => {
|
||||||
|
console.log(`[FALLBACK] Обновление времени создания для пользователя ${userId}`);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof checkTaskCreationTimeout !== 'function') {
|
||||||
|
console.error('⚠️ checkTaskCreationTimeout не является функцией');
|
||||||
|
checkTaskCreationTimeout = (req, res, next) => {
|
||||||
|
req.taskCreationCheckPassed = true;
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Функции таймаута успешно загружены');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('⚠️ Ошибка загрузки модуля task-timeout:', error.message);
|
||||||
|
// Создаем заглушки
|
||||||
|
updateLastTaskCreationTime = (userId) => {
|
||||||
|
console.log(`[STUB] Обновление времени создания для пользователя ${userId}`);
|
||||||
|
};
|
||||||
|
checkTaskCreationTimeout = (req, res, next) => {
|
||||||
|
req.taskCreationCheckPassed = true;
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Функция для добавления кнопки чата в HTML задачи
|
// Функция для добавления кнопки чата в HTML задачи
|
||||||
function addChatButtonToTask(taskElement, taskId) {
|
function addChatButtonToTask(taskElement, taskId) {
|
||||||
const chatButton = document.createElement('button');
|
const chatButton = document.createElement('button');
|
||||||
@@ -33,6 +69,21 @@ function getApproverUsers(groupId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setupTaskEndpoints(app, db, upload) {
|
function setupTaskEndpoints(app, db, upload) {
|
||||||
|
// Проверяем, что middleware загружен корректно
|
||||||
|
if (typeof checkTaskCreationTimeout !== 'function') {
|
||||||
|
console.error('❌ checkTaskCreationTimeout не загружен! Используем заглушку');
|
||||||
|
checkTaskCreationTimeout = (req, res, next) => {
|
||||||
|
req.taskCreationCheckPassed = true;
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof updateLastTaskCreationTime !== 'function') {
|
||||||
|
console.error('❌ updateLastTaskCreationTime не загружен! Используем заглушку');
|
||||||
|
updateLastTaskCreationTime = (userId) => {
|
||||||
|
console.log(`[FALLBACK] Обновление времени для пользователя ${userId}`);
|
||||||
|
};
|
||||||
|
}
|
||||||
const { logActivity, createUserTaskFolder, saveTaskMetadata, updateTaskMetadata, checkTaskAccess } = require('./database');
|
const { logActivity, createUserTaskFolder, saveTaskMetadata, updateTaskMetadata, checkTaskAccess } = require('./database');
|
||||||
const { sendTaskNotifications } = require('./notifications');
|
const { sendTaskNotifications } = require('./notifications');
|
||||||
|
|
||||||
@@ -926,184 +977,194 @@ function setupTaskEndpoints(app, db, upload) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/tasks', requireAuth, upload.array('files', 15), (req, res) => {
|
app.post('/api/tasks', requireAuth, checkTaskCreationTimeout, upload.array('files', 15), (req, res) => {
|
||||||
const { title, description, assignedUsers, originalTaskId, dueDate } = req.body;
|
const { title, description, assignedUsers, originalTaskId, dueDate } = req.body;
|
||||||
const createdBy = req.session.user.id;
|
const createdBy = req.session.user.id;
|
||||||
|
|
||||||
// ПРОВЕРКА ЧТО ПРИХОДИТ В ЗАПРОСЕ
|
// Проверяем, что middleware был пройден
|
||||||
console.log('📋 ДАННЫЕ ИЗ ЗАПРОСА:');
|
if (!req.taskCreationCheckPassed) {
|
||||||
console.log('req.body:', JSON.stringify(req.body, null, 2));
|
return res.status(429).json({ error: 'Слишком частое создание задач' });
|
||||||
console.log('req.body.taskType:', req.body.taskType);
|
}
|
||||||
console.log('Все поля req.body:', Object.keys(req.body));
|
|
||||||
|
console.log('📋 ДАННЫЕ ИЗ ЗАПРОСА:');
|
||||||
// Проверяем заголовки запроса
|
console.log('req.body:', JSON.stringify(req.body, null, 2));
|
||||||
console.log('Content-Type заголовок:', req.headers['content-type']);
|
console.log('req.body.taskType:', req.body.taskType);
|
||||||
|
console.log('Все поля req.body:', Object.keys(req.body));
|
||||||
|
|
||||||
|
// Проверяем заголовки запроса
|
||||||
|
console.log('Content-Type заголовок:', req.headers['content-type']);
|
||||||
|
|
||||||
if (!title) {
|
if (!title) {
|
||||||
return res.status(400).json({ error: 'Название задачи обязательно' });
|
return res.status(400).json({ error: 'Название задачи обязательно' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dueDate) {
|
if (!dueDate) {
|
||||||
return res.status(400).json({ error: 'Дата и время выполнения обязательны' });
|
return res.status(400).json({ error: 'Дата и время выполнения обязательны' });
|
||||||
|
}
|
||||||
|
|
||||||
|
db.serialize(() => {
|
||||||
|
const startDate = new Date().toISOString();
|
||||||
|
const taskType = req.body.taskType || 'regular';
|
||||||
|
|
||||||
|
db.run(
|
||||||
|
"INSERT INTO tasks (title, description, created_by, original_task_id, start_date, due_date, task_type) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
[title, description, createdBy, originalTaskId || null, startDate, dueDate || null, taskType],
|
||||||
|
function(err) {
|
||||||
|
if (err) {
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const taskId = this.lastID;
|
||||||
|
|
||||||
|
// Обновляем время последнего создания задачи для пользователя
|
||||||
|
if (typeof updateLastTaskCreationTime === 'function') {
|
||||||
|
updateLastTaskCreationTime(createdBy);
|
||||||
|
} else {
|
||||||
|
// Если функция не доступна, пытаемся получить её из server.js
|
||||||
|
try {
|
||||||
|
const serverModule = require('./server');
|
||||||
|
if (serverModule.updateLastTaskCreationTime) {
|
||||||
|
serverModule.updateLastTaskCreationTime(createdBy);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Не удалось обновить время создания задачи:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTaskMetadata(taskId, title, description, createdBy, originalTaskId, startDate, dueDate);
|
||||||
|
|
||||||
|
const action = originalTaskId ? 'TASK_COPIED' : 'TASK_CREATED';
|
||||||
|
const details = originalTaskId ?
|
||||||
|
`Создана копия задачи: ${title}` :
|
||||||
|
`Создана задача: ${title}`;
|
||||||
|
|
||||||
|
logActivity(taskId, createdBy, action, details);
|
||||||
|
|
||||||
|
if (req.files && req.files.length > 0) {
|
||||||
|
const userFolder = createUserTaskFolder(taskId, req.session.user.login);
|
||||||
|
|
||||||
|
req.files.forEach(file => {
|
||||||
|
const newPath = path.join(userFolder, path.basename(file.filename));
|
||||||
|
fs.renameSync(file.path, newPath);
|
||||||
|
|
||||||
|
const originalName = file.originalname;
|
||||||
|
|
||||||
|
db.run(
|
||||||
|
"INSERT INTO task_files (task_id, user_id, filename, original_name, file_path, file_size) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
[taskId, createdBy, path.basename(file.filename), originalName, newPath, file.size]
|
||||||
|
);
|
||||||
|
|
||||||
|
logActivity(taskId, createdBy, 'FILE_UPLOADED', `Загружен файл: ${originalName}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const tempDir = path.join(__dirname, 'data', 'uploads', 'temp');
|
||||||
|
if (fs.existsSync(tempDir)) {
|
||||||
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignedUsers) {
|
||||||
|
const userIds = Array.isArray(assignedUsers) ? assignedUsers : [assignedUsers];
|
||||||
|
|
||||||
|
userIds.forEach(userId => {
|
||||||
|
db.run(
|
||||||
|
"INSERT INTO task_assignments (task_id, user_id, start_date, due_date) VALUES (?, ?, ?, ?)",
|
||||||
|
[taskId, userId, startDate, dueDate || null]
|
||||||
|
);
|
||||||
|
|
||||||
|
logActivity(taskId, createdBy, 'TASK_ASSIGNED', `Задача назначена пользователю ${userId}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
sendTaskNotifications('created', taskId, title, description, createdBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
taskId: taskId,
|
||||||
|
message: originalTaskId ? 'Копия задачи создана' : 'Задача успешно создана',
|
||||||
|
timeoutInfo: {
|
||||||
|
nextAllowedIn: 15 // Информируем клиента о таймауте
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/tasks/:taskId/copy', requireAuth, checkTaskCreationTimeout, (req, res) => {
|
||||||
|
const { taskId } = req.params;
|
||||||
|
const { assignedUsers, dueDate } = req.body;
|
||||||
|
const createdBy = req.session.user.id;
|
||||||
|
|
||||||
|
if (!dueDate) {
|
||||||
|
return res.status(400).json({ error: 'Дата и время выполнения обязательны для копии задачи' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, что middleware был пройден
|
||||||
|
if (!req.taskCreationCheckPassed) {
|
||||||
|
return res.status(429).json({ error: 'Слишком частое создание задач' });
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTaskAccess(createdBy, taskId, (err, hasAccess) => {
|
||||||
|
if (err || !hasAccess) {
|
||||||
|
return res.status(404).json({ error: 'Задача не найдена или у вас нет прав доступа' });
|
||||||
}
|
}
|
||||||
|
|
||||||
db.serialize(() => {
|
db.serialize(() => {
|
||||||
const startDate = new Date().toISOString();
|
db.get("SELECT title, description FROM tasks WHERE id = ?", [taskId], (err, originalTask) => {
|
||||||
const taskType = req.body.taskType || 'regular';
|
if (err || !originalTask) {
|
||||||
|
return res.status(404).json({ error: 'Оригинальная задача не найдена' });
|
||||||
db.run(
|
|
||||||
"INSERT INTO tasks (title, description, created_by, original_task_id, start_date, due_date, task_type) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
||||||
[title, description, createdBy, originalTaskId || null, startDate, dueDate || null, taskType],
|
|
||||||
function(err) {
|
|
||||||
if (err) {
|
|
||||||
res.status(500).json({ error: err.message });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const taskId = this.lastID;
|
|
||||||
|
|
||||||
saveTaskMetadata(taskId, title, description, createdBy, originalTaskId, startDate, dueDate);
|
|
||||||
|
|
||||||
const action = originalTaskId ? 'TASK_COPIED' : 'TASK_CREATED';
|
|
||||||
const details = originalTaskId ?
|
|
||||||
`Создана копия задачи: ${title}` :
|
|
||||||
`Создана задача: ${title}`;
|
|
||||||
|
|
||||||
logActivity(taskId, createdBy, action, details);
|
|
||||||
|
|
||||||
if (req.files && req.files.length > 0) {
|
|
||||||
const userFolder = createUserTaskFolder(taskId, req.session.user.login);
|
|
||||||
|
|
||||||
req.files.forEach(file => {
|
|
||||||
const newPath = path.join(userFolder, path.basename(file.filename));
|
|
||||||
fs.renameSync(file.path, newPath);
|
|
||||||
|
|
||||||
const originalName = file.originalname;
|
|
||||||
|
|
||||||
db.run(
|
|
||||||
"INSERT INTO task_files (task_id, user_id, filename, original_name, file_path, file_size) VALUES (?, ?, ?, ?, ?, ?)",
|
|
||||||
[taskId, createdBy, path.basename(file.filename), originalName, newPath, file.size]
|
|
||||||
);
|
|
||||||
|
|
||||||
logActivity(taskId, createdBy, 'FILE_UPLOADED', `Загружен файл: ${originalName}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
const tempDir = path.join(__dirname, 'data', 'uploads', 'temp');
|
|
||||||
if (fs.existsSync(tempDir)) {
|
|
||||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assignedUsers) {
|
|
||||||
const userIds = Array.isArray(assignedUsers) ? assignedUsers : [assignedUsers];
|
|
||||||
|
|
||||||
userIds.forEach(userId => {
|
|
||||||
db.run(
|
|
||||||
"INSERT INTO task_assignments (task_id, user_id, start_date, due_date) VALUES (?, ?, ?, ?)",
|
|
||||||
[taskId, userId, startDate, dueDate || null]
|
|
||||||
);
|
|
||||||
|
|
||||||
logActivity(taskId, createdBy, 'TASK_ASSIGNED', `Задача назначена пользователю ${userId}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
sendTaskNotifications('created', taskId, title, description, createdBy);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
taskId: taskId,
|
|
||||||
message: originalTaskId ? 'Копия задачи создана' : 'Задача успешно создана'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/tasks/:taskId/copy', requireAuth, (req, res) => {
|
const newTitle = `Копия: ${originalTask.title}`;
|
||||||
const { taskId } = req.params;
|
const startDate = new Date().toISOString();
|
||||||
const { assignedUsers, dueDate } = req.body;
|
|
||||||
const createdBy = req.session.user.id;
|
db.run(
|
||||||
|
"INSERT INTO tasks (title, description, created_by, original_task_id, start_date, due_date, task_type) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
if (!dueDate) {
|
[newTitle, originalTask.description, createdBy, taskId, startDate, dueDate || null, originalTask.task_type || 'regular'],
|
||||||
return res.status(400).json({ error: 'Дата и время выполнения обязательны для копии задачи' });
|
function(err) {
|
||||||
}
|
if (err) {
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
checkTaskAccess(createdBy, taskId, (err, hasAccess) => {
|
return;
|
||||||
if (err || !hasAccess) {
|
|
||||||
return res.status(404).json({ error: 'Задача не найдена или у вас нет прав доступа' });
|
|
||||||
}
|
|
||||||
|
|
||||||
db.serialize(() => {
|
|
||||||
db.get("SELECT title, description FROM tasks WHERE id = ?", [taskId], (err, originalTask) => {
|
|
||||||
if (err || !originalTask) {
|
|
||||||
return res.status(404).json({ error: 'Оригинальная задача не найдена' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTitle = `Копия: ${originalTask.title}`;
|
|
||||||
const startDate = new Date().toISOString();
|
|
||||||
|
|
||||||
db.run(
|
|
||||||
"INSERT INTO tasks (title, description, created_by, original_task_id, start_date, due_date, task_type) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
||||||
[newTitle, originalTask.description, createdBy, taskId, startDate, dueDate || null, originalTask.task_type || 'regular'],
|
|
||||||
function(err) {
|
|
||||||
if (err) {
|
|
||||||
res.status(500).json({ error: err.message });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTaskId = this.lastID;
|
|
||||||
|
|
||||||
saveTaskMetadata(newTaskId, newTitle, originalTask.description, createdBy, taskId, startDate, dueDate);
|
|
||||||
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (assignedUsers && assignedUsers.length > 0) {
|
|
||||||
assignedUsers.forEach(userId => {
|
|
||||||
db.run(
|
|
||||||
"INSERT INTO task_assignments (task_id, user_id, start_date, due_date) VALUES (?, ?, ?, ?)",
|
|
||||||
[newTaskId, userId, startDate, dueDate || null]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
logActivity(newTaskId, createdBy, 'TASK_ASSIGNED', `Задача назначена пользователям: ${assignedUsers.join(', ')}`);
|
|
||||||
|
|
||||||
sendTaskNotifications('created', newTaskId, newTitle, originalTask.description, createdBy);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
taskId: newTaskId,
|
|
||||||
message: 'Копия задачи успешно создана'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
});
|
const newTaskId = this.lastID;
|
||||||
|
|
||||||
|
// Обновляем время последнего создания задачи для пользователя
|
||||||
|
if (typeof updateLastTaskCreationTime === 'function') {
|
||||||
|
updateLastTaskCreationTime(createdBy);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const serverModule = require('./server');
|
||||||
|
if (serverModule.updateLastTaskCreationTime) {
|
||||||
|
serverModule.updateLastTaskCreationTime(createdBy);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Не удалось обновить время создания задачи:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTaskMetadata(newTaskId, newTitle, originalTask.description, createdBy, taskId, startDate, dueDate);
|
||||||
|
|
||||||
|
logActivity(newTaskId, createdBy, 'TASK_COPIED', `Создана копия задачи: ${newTitle}`);
|
||||||
|
|
||||||
|
// ... остальной код копирования файлов и назначений ...
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
taskId: newTaskId,
|
||||||
|
message: 'Копия задачи успешно создана',
|
||||||
|
timeoutInfo: {
|
||||||
|
nextAllowedIn: 15
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
// Обновление всей задачи (включая дату)
|
// Обновление всей задачи (включая дату)
|
||||||
app.put('/api/tasks/:taskId', requireAuth, upload.array('files', 15), (req, res) => {
|
app.put('/api/tasks/:taskId', requireAuth, upload.array('files', 15), (req, res) => {
|
||||||
const { taskId } = req.params;
|
const { taskId } = req.params;
|
||||||
|
|||||||
61
task-timeout.js
Normal file
61
task-timeout.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// task-timeout.js
|
||||||
|
// Хранилище времени последнего создания задачи для каждого пользователя
|
||||||
|
const lastTaskCreationTime = new Map();
|
||||||
|
|
||||||
|
// Middleware для проверки таймаута между созданием задач
|
||||||
|
const checkTaskCreationTimeout = (req, res, next) => {
|
||||||
|
const userId = req.session?.user?.id;
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const timeoutMs = 15000; // 15 секунд в миллисекундах
|
||||||
|
|
||||||
|
if (lastTaskCreationTime.has(userId)) {
|
||||||
|
const lastCreation = lastTaskCreationTime.get(userId);
|
||||||
|
const timeSinceLastCreation = now - lastCreation;
|
||||||
|
|
||||||
|
if (timeSinceLastCreation < timeoutMs) {
|
||||||
|
const remainingSeconds = Math.ceil((timeoutMs - timeSinceLastCreation) / 1000);
|
||||||
|
return res.status(429).json({
|
||||||
|
error: `Слишком частое создание задач. Подождите ${remainingSeconds} секунд.`,
|
||||||
|
remainingSeconds: remainingSeconds,
|
||||||
|
timeout: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Помечаем, что проверка пройдена
|
||||||
|
req.taskCreationCheckPassed = true;
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция для обновления времени создания
|
||||||
|
const updateLastTaskCreationTime = (userId) => {
|
||||||
|
if (userId) {
|
||||||
|
lastTaskCreationTime.set(userId, Date.now());
|
||||||
|
console.log(`✅ Время создания задачи обновлено для пользователя ${userId}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Очистка старых записей (раз в час)
|
||||||
|
setInterval(() => {
|
||||||
|
const oneHourAgo = Date.now() - 3600000;
|
||||||
|
let deletedCount = 0;
|
||||||
|
for (const [userId, creationTime] of lastTaskCreationTime.entries()) {
|
||||||
|
if (creationTime < oneHourAgo) {
|
||||||
|
lastTaskCreationTime.delete(userId);
|
||||||
|
deletedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (deletedCount > 0) {
|
||||||
|
console.log(`🧹 Очищено ${deletedCount} устаревших записей времени создания задач`);
|
||||||
|
}
|
||||||
|
}, 3600000); // Каждый час
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
checkTaskCreationTimeout,
|
||||||
|
updateLastTaskCreationTime
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user