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
This commit is contained in:
203
analyze_deletions.php
Normal file
203
analyze_deletions.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
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'];
|
||||
|
||||
echo "Анализ удалений файлов из S3\n";
|
||||
echo str_repeat("=", 80) . "\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 "1. Анализ паттернов удалений по датам...\n";
|
||||
|
||||
$deletionsByDate = [];
|
||||
$deletionsByProject = [];
|
||||
$totalChecked = 0;
|
||||
$maxToCheck = 5000; // Ограничиваем для скорости
|
||||
|
||||
try {
|
||||
$isTruncated = true;
|
||||
$continuationToken = null;
|
||||
$pageCount = 0;
|
||||
$maxPages = 10;
|
||||
|
||||
while ($isTruncated && $pageCount < $maxPages && $totalChecked < $maxToCheck) {
|
||||
$params = [
|
||||
'Bucket' => $s3Bucket,
|
||||
'Prefix' => 'crm2/CRM_Active_Files/Documents/Project/',
|
||||
'MaxKeys' => 1000
|
||||
];
|
||||
|
||||
if ($continuationToken) {
|
||||
$params['ContinuationToken'] = $continuationToken;
|
||||
}
|
||||
|
||||
$versions = $s3Client->listObjectVersions($params);
|
||||
$pageCount++;
|
||||
|
||||
if (isset($versions['DeleteMarkers'])) {
|
||||
foreach ($versions['DeleteMarkers'] as $marker) {
|
||||
$totalChecked++;
|
||||
$key = $marker['Key'];
|
||||
$deleteDate = isset($marker['LastModified']) ? $marker['LastModified'] : null;
|
||||
|
||||
if ($deleteDate) {
|
||||
$dateKey = substr($deleteDate, 0, 10); // YYYY-MM-DD
|
||||
if (!isset($deletionsByDate[$dateKey])) {
|
||||
$deletionsByDate[$dateKey] = 0;
|
||||
}
|
||||
$deletionsByDate[$dateKey]++;
|
||||
}
|
||||
|
||||
// Извлекаем ID проекта из пути
|
||||
if (preg_match('/Project\/([^\/]+)_(\d+)\//', $key, $matches)) {
|
||||
$projectId = $matches[2];
|
||||
if (!isset($deletionsByProject[$projectId])) {
|
||||
$deletionsByProject[$projectId] = 0;
|
||||
}
|
||||
$deletionsByProject[$projectId]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$isTruncated = isset($versions['IsTruncated']) && $versions['IsTruncated'];
|
||||
$continuationToken = isset($versions['NextContinuationToken']) ? $versions['NextContinuationToken'] : null;
|
||||
|
||||
if (!$isTruncated) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
echo " Проверено delete markers: $totalChecked\n\n";
|
||||
|
||||
// Сортируем по датам
|
||||
krsort($deletionsByDate);
|
||||
|
||||
echo " Удаления по датам (топ 20):\n";
|
||||
$count = 0;
|
||||
foreach ($deletionsByDate as $date => $count) {
|
||||
if ($count > 0) {
|
||||
echo " $date: $count удалений\n";
|
||||
if (++$count >= 20) break;
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Сортируем проекты по количеству удалений
|
||||
arsort($deletionsByProject);
|
||||
|
||||
echo " Проекты с наибольшим количеством удалений (топ 10):\n";
|
||||
$count = 0;
|
||||
foreach ($deletionsByProject as $projectId => $deleteCount) {
|
||||
echo " Проект $projectId: $deleteCount удалений\n";
|
||||
if (++$count >= 10) break;
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
} catch (\Aws\Exception\AwsException $e) {
|
||||
echo " Ошибка: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
// Проверяем логи системы
|
||||
echo "2. Проверка логов на наличие записей об удалениях...\n";
|
||||
$logFiles = [
|
||||
'/var/log/nginx/error.log',
|
||||
'/var/log/apache2/error.log',
|
||||
'/var/www/fastuser/data/www/crm.clientright.ru/logs/debug.log',
|
||||
'/var/www/fastuser/data/www/crm.clientright.ru/logs/s3_debug.log',
|
||||
];
|
||||
|
||||
foreach ($logFiles as $logFile) {
|
||||
if (file_exists($logFile)) {
|
||||
echo " Проверка: $logFile\n";
|
||||
$lines = file($logFile);
|
||||
if ($lines) {
|
||||
$deleteLines = array_filter($lines, function($line) {
|
||||
return stripos($line, 'delete') !== false &&
|
||||
(stripos($line, 's3') !== false || stripos($line, 'file') !== false);
|
||||
});
|
||||
|
||||
if (!empty($deleteLines)) {
|
||||
echo " Найдено строк с упоминанием удалений: " . count($deleteLines) . "\n";
|
||||
echo " Последние 5 записей:\n";
|
||||
foreach (array_slice($deleteLines, -5) as $line) {
|
||||
echo " " . substr(trim($line), 0, 150) . "\n";
|
||||
}
|
||||
} else {
|
||||
echo " Записей об удалениях не найдено\n";
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем, есть ли скрипты крона, которые могут удалять файлы
|
||||
echo "3. Поиск скриптов, которые могут удалять файлы...\n";
|
||||
$cronFiles = [
|
||||
'/var/spool/cron/crontabs/root',
|
||||
'/etc/cron.d/',
|
||||
'/var/www/fastuser/data/www/crm.clientright.ru/cron/',
|
||||
];
|
||||
|
||||
foreach ($cronFiles as $cronPath) {
|
||||
if (file_exists($cronPath)) {
|
||||
echo " Проверка: $cronPath\n";
|
||||
if (is_dir($cronPath)) {
|
||||
$files = glob($cronPath . '*');
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
$content = file_get_contents($file);
|
||||
if (stripos($content, 'delete') !== false || stripos($content, 'remove') !== false) {
|
||||
echo " Найден файл: $file\n";
|
||||
echo " Содержит упоминания удаления\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$content = file_get_contents($cronPath);
|
||||
if (stripos($content, 'delete') !== false || stripos($content, 'remove') !== false) {
|
||||
echo " Файл содержит упоминания удаления\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Проверяем, может быть это связано с синхронизацией Nextcloud
|
||||
echo "4. Проверка связи с Nextcloud синхронизацией...\n";
|
||||
$nextcloudFiles = glob('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/*sync*.php');
|
||||
if (!empty($nextcloudFiles)) {
|
||||
echo " Найдено файлов синхронизации: " . count($nextcloudFiles) . "\n";
|
||||
foreach ($nextcloudFiles as $file) {
|
||||
$content = file_get_contents($file);
|
||||
if (stripos($content, 'delete') !== false) {
|
||||
echo " $file содержит код удаления\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo " Файлы синхронизации не найдены\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "ОШИБКА: " . $e->getMessage() . "\n";
|
||||
echo "Trace: " . $e->getTraceAsString() . "\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user