This commit is contained in:
2026-02-26 11:26:19 +05:00
parent 9d28e67388
commit 318cbc8e71
2 changed files with 193 additions and 143 deletions

View File

@@ -445,17 +445,15 @@ module.exports = function(app, db, upload) {
});
/**
* POST /api/client/tasks/:taskId/copy - Скопировать задачу в целевой сервис
* POST /api/client/tasks/:taskId/sync - Синхронизировать задачу с целевым сервисом
*/
router.post('/api/client/tasks/:taskId/copy', requireAuth, async (req, res) => {
router.post('/api/client/tasks/:taskId/sync', requireAuth, async (req, res) => {
const { taskId } = req.params;
const {
target_connection_id,
target_api_url,
target_api_key,
new_assignees,
due_date,
copy_files = true
sync_files = true
} = req.body;
const { connection_id } = req.query;
const userId = req.session.user.id;
@@ -505,46 +503,100 @@ module.exports = function(app, db, upload) {
}
const sourceTask = sourceResponse.data.task;
// 2. Создаем копию задачи в целевом сервисе
const newTaskTitle = `Копия: ${sourceTask.title}`;
const taskData = {
title: newTaskTitle,
description: sourceTask.description || '',
due_date: due_date || sourceTask.due_date,
task_type: sourceTask.task_type || 'regular'
};
if (new_assignees && new_assignees.length > 0) {
taskData.assignedUsers = new_assignees;
}
const createResponse = await axios.post(
`${baseUrl}/api/external/tasks/create`,
taskData,
{
headers: {
'X-API-Key': targetKey,
'Content-Type': 'application/json'
},
timeout: 15000
// 2. Проверяем, существует ли задача в целевой системе (поиск по ID)
let existingTask = null;
try {
const checkResponse = await axios.get(
`${baseUrl}/api/external/tasks/${taskId}`,
{
headers: {
'X-API-Key': targetKey
},
timeout: 5000
}
);
if (checkResponse.data && checkResponse.data.success) {
existingTask = checkResponse.data.task;
}
);
if (!createResponse.data || !createResponse.data.success) {
return res.status(500).json({
error: 'Не удалось создать задачу в целевом сервисе'
});
} catch (checkError) {
// Задача не найдена - это нормально, будем создавать новую
console.log('Задача не найдена в целевой системе, будет создана новая');
}
const newTaskId = createResponse.data.taskId;
let result;
const syncedFiles = [];
const warnings = [];
// 3. Копируем файлы, если нужно
const copiedFiles = [];
if (copy_files && sourceTask.files && sourceTask.files.length > 0) {
if (existingTask) {
// 3. Обновляем существующую задачу
const updateData = {
title: sourceTask.title,
description: sourceTask.description,
due_date: sourceTask.due_date,
task_type: sourceTask.task_type || 'regular'
};
const updateResponse = await axios.put(
`${baseUrl}/api/external/tasks/${taskId}`,
updateData,
{
headers: {
'X-API-Key': targetKey,
'Content-Type': 'application/json'
},
timeout: 15000
}
);
if (!updateResponse.data || !updateResponse.data.success) {
return res.status(500).json({
error: 'Не удалось обновить задачу в целевом сервисе'
});
}
result = {
taskId: taskId,
action: 'updated'
};
} else {
// 4. Создаем новую задачу (без префикса "Копия:")
const taskData = {
title: sourceTask.title,
description: sourceTask.description || '',
due_date: sourceTask.due_date,
task_type: sourceTask.task_type || 'regular'
};
const createResponse = await axios.post(
`${baseUrl}/api/external/tasks/create`,
taskData,
{
headers: {
'X-API-Key': targetKey,
'Content-Type': 'application/json'
},
timeout: 15000
}
);
if (!createResponse.data || !createResponse.data.success) {
return res.status(500).json({
error: 'Не удалось создать задачу в целевом сервисе'
});
}
result = {
taskId: createResponse.data.taskId,
action: 'created'
};
}
// 5. Синхронизируем файлы, если нужно
if (sync_files && sourceTask.files && sourceTask.files.length > 0) {
for (const file of sourceTask.files) {
try {
// Скачиваем файл из источника
const fileResponse = await axios({
method: 'GET',
url: `${sourceConnection.url}/api/external/tasks/${taskId}/files/${file.id}/download`,
@@ -555,6 +607,7 @@ module.exports = function(app, db, upload) {
timeout: 30000
});
// Загружаем в целевую систему
const formData = new FormData();
formData.append('files', Buffer.from(fileResponse.data), {
filename: file.filename || file.original_name || 'file',
@@ -562,7 +615,7 @@ module.exports = function(app, db, upload) {
});
const uploadResponse = await axios.post(
`${baseUrl}/api/external/tasks/${newTaskId}/files`,
`${baseUrl}/api/external/tasks/${result.taskId}/files`,
formData,
{
headers: {
@@ -575,44 +628,46 @@ module.exports = function(app, db, upload) {
}
);
copiedFiles.push({
syncedFiles.push({
original_name: file.filename || file.original_name,
success: uploadResponse.data && uploadResponse.data.success
});
} catch (fileError) {
console.error(`❌ Ошибка копирования файла:`, fileError.message);
copiedFiles.push({
console.error(`❌ Ошибка синхронизации файла:`, fileError.message);
syncedFiles.push({
original_name: file.filename || file.original_name,
success: false,
error: fileError.message
});
warnings.push(`Не удалось синхронизировать файл: ${file.filename || file.original_name}`);
}
}
}
const { logActivity } = require('./database');
if (logActivity) {
logActivity(0, userId, 'API_CLIENT_COPY_TASK',
`Скопирована задача ${taskId} из ${sourceConnection.url} в ${baseUrl}. Новый ID: ${newTaskId}`);
logActivity(0, userId, 'API_CLIENT_SYNC_TASK',
`${existingTask ? 'Обновлена' : 'Создана'} задача ${taskId} из ${sourceConnection.url} в ${baseUrl}. ${existingTask ? 'Обновление' : 'Новый ID: ' + result.taskId}`);
}
res.json({
success: true,
message: `Задача успешно скопирована${copiedFiles.length > 0 ? `, скопировано файлов: ${copiedFiles.filter(f => f.success).length}` : ''}`,
message: `Задача успешно ${existingTask ? 'обновлена' : 'создана'} в целевой системе`,
data: {
sync_type: result.action,
original_task_id: taskId,
new_task_id: newTaskId,
new_task_title: newTaskTitle,
target_task_id: result.taskId,
target_service: baseUrl,
copied_files: copiedFiles,
assignees: new_assignees || 'не изменены'
synced_files: syncedFiles,
assignees: sourceTask.assignments || [],
warnings: warnings
}
});
} catch (error) {
console.error('❌ Ошибка копирования задачи:', error.message);
console.error('❌ Ошибка синхронизации задачи:', error.message);
let errorMessage = 'Ошибка копирования задачи';
let errorMessage = 'Ошибка синхронизации задачи';
let statusCode = 500;
if (error.response) {
@@ -620,7 +675,7 @@ module.exports = function(app, db, upload) {
errorMessage = 'Неверный API ключ для целевого сервиса';
statusCode = 401;
} else if (error.response.status === 403) {
errorMessage = 'Нет прав для создания задачи в целевом сервисе';
errorMessage = 'Нет прав для создания/обновления задачи в целевом сервисе';
statusCode = 403;
} else if (error.response.status === 404) {
errorMessage = 'Исходная задача не найдена';