Files
crm.clientright.ru/restore_project_394091.php
Fedor 840acca51a feat(documents): дедупликация documents_meta и исправление field_label
- Исправлен N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js: использовать uploads_field_labels[0] вместо [grp]
- Создан SQL_CLAIMSAVE_FIXED_NEW_FLOW_DEDUP.sql с дедупликацией documents_meta
- Создан SQL_CLEANUP_DOCUMENTS_META_DUPLICATES.sql для очистки существующих дубликатов
- Создан полный уникальный индекс idx_document_texts_hash_unique на document_texts(file_hash)
- Добавлен SESSION_LOG_2025-11-28_documents_dedup.md с описанием всех изменений

Fixes:
- field_label теперь корректно отображает 'Переписка' вместо 'group-2'
- documents_meta не накапливает дубликаты при повторных сохранениях
- ON CONFLICT (file_hash) теперь работает для document_texts
2025-11-28 18:16:53 +03:00

200 lines
7.1 KiB
PHP
Raw Permalink 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.

<?php
/**
* Скрипт для восстановления файлов проекта 394091
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
set_time_limit(0);
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
$config = require '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/config.php';
$s3Bucket = $config['s3']['bucket'];
$projectId = 394091;
echo "=== ВОССТАНОВЛЕНИЕ ФАЙЛОВ ПРОЕКТА {$projectId} ===\n";
echo str_repeat("=", 80) . "\n\n";
// Параметры
$dryRun = isset($argv[1]) && $argv[1] === '--dry-run';
if ($dryRun) {
echo "⚠️ РЕЖИМ ПРОВЕРКИ (dry-run) - файлы не будут восстановлены\n\n";
}
try {
$s3Client = new \Aws\S3\S3Client([
'version' => 'latest',
'region' => $config['s3']['region'],
'endpoint' => $config['s3']['endpoint'],
'use_path_style_endpoint' => true,
'credentials' => [
'key' => $config['s3']['key'],
'secret' => $config['s3']['secret'],
],
'suppress_php_deprecation_warning' => true
]);
// Получаем документы проекта из БД
echo "Подключение к БД...\n";
$db = PearDatabase::getInstance();
echo "✅ БД подключена\n";
echo "Выполнение запроса...\n";
$result = $db->pquery("
SELECT n.notesid, n.filename, n.filelocationtype, n.s3_bucket, n.s3_key, n.filesize
FROM vtiger_notes n
INNER JOIN vtiger_senotesrel sn ON sn.notesid = n.notesid
WHERE sn.crmid = ?
ORDER BY n.notesid
", array($projectId));
echo "✅ Запрос выполнен\n";
$totalDocs = $db->num_rows($result);
echo "Найдено документов в БД: {$totalDocs}\n\n";
if ($totalDocs == 0) {
echo "Документы не найдены!\n";
exit(0);
}
$stats = [
'total_docs' => $totalDocs,
'existing' => 0,
'deleted' => 0,
'missing' => 0,
'restored' => 0,
'failed' => 0,
'errors' => []
];
// Проверяем каждый документ
while ($row = $db->fetch_array($result)) {
$s3Key = $row['s3_key'];
$docId = $row['notesid'];
$filename = $row['filename'];
echo "Документ ID: {$docId} | Файл: {$filename}\n";
if (empty($s3Key)) {
echo " ⚠️ Нет S3 ключа\n\n";
$stats['missing']++;
continue;
}
echo " S3 ключ: {$s3Key}\n";
// Проверяем существование файла
$exists = $s3Client->doesObjectExist($s3Bucket, $s3Key);
if ($exists) {
echo " ✅ Файл существует\n\n";
$stats['existing']++;
continue;
}
// Проверяем версии и delete markers
try {
$versions = $s3Client->listObjectVersions([
'Bucket' => $s3Bucket,
'Prefix' => $s3Key,
]);
$deleteMarker = null;
$fileVersion = null;
foreach ($versions['Versions'] ?? [] as $version) {
if (isset($version['IsDeleteMarker']) && $version['IsDeleteMarker']) {
$deleteMarker = $version;
} else {
$fileVersion = $version;
}
}
if ($deleteMarker) {
echo " ❌ Файл удален (delete marker от " . $deleteMarker['LastModified']->format('Y-m-d H:i:s') . ")\n";
if (!$dryRun) {
// Удаляем delete marker
try {
$s3Client->deleteObject([
'Bucket' => $s3Bucket,
'Key' => $s3Key,
'VersionId' => $deleteMarker['VersionId'],
]);
// Если есть версия файла, копируем её
if ($fileVersion) {
$s3Client->copyObject([
'Bucket' => $s3Bucket,
'Key' => $s3Key,
'CopySource' => "{$s3Bucket}/{$s3Key}?versionId={$fileVersion['VersionId']}",
]);
echo " ✅ Файл восстановлен из версии\n";
} else {
echo " ⚠️ Delete marker удален, но версия файла не найдена\n";
}
$stats['restored']++;
sleep(1); // Пауза между запросами
} catch (Exception $e) {
echo " ❌ Ошибка восстановления: " . $e->getMessage() . "\n";
$stats['failed']++;
$stats['errors'][] = "{$s3Key}: " . $e->getMessage();
}
} else {
echo " ⏸️ Будет восстановлен (dry-run)\n";
$stats['restored']++;
}
$stats['deleted']++;
} else {
echo " ⚠️ Файл отсутствует, но delete marker не найден\n";
$stats['missing']++;
}
} catch (Exception $e) {
echo " ❌ Ошибка проверки версий: " . $e->getMessage() . "\n";
$stats['failed']++;
$stats['errors'][] = "{$s3Key}: " . $e->getMessage();
}
echo "\n";
}
// Итоговая статистика
echo str_repeat("=", 80) . "\n";
echo "ИТОГОВАЯ СТАТИСТИКА:\n\n";
echo "Всего документов: {$stats['total_docs']}\n";
echo "Существующих файлов: {$stats['existing']}\n";
echo "Удаленных файлов (delete marker): {$stats['deleted']}\n";
echo "Отсутствующих файлов: {$stats['missing']}\n";
if (!$dryRun) {
echo "Восстановлено: {$stats['restored']}\n";
echo "Ошибок: {$stats['failed']}\n";
} else {
echo "Будет восстановлено: {$stats['restored']}\n";
}
if (!empty($stats['errors'])) {
echo "\nОшибки:\n";
foreach ($stats['errors'] as $error) {
echo " - {$error}\n";
}
}
echo "\n=== ГОТОВО ===\n";
} catch (Exception $e) {
echo "❌ Критическая ошибка: " . $e->getMessage() . "\n";
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
exit(1);
}