🚀 CRM Files Migration & Real-time Features
✨ Features: - Migrated ALL files to new S3 structure (Projects, Contacts, Accounts, HelpDesk, Invoice, etc.) - Added Nextcloud folder buttons to ALL modules - Fixed Nextcloud editor integration - WebSocket server for real-time updates - Redis Pub/Sub integration - File path manager for organized storage - Redis caching for performance (Functions.php) 📁 New Structure: Documents/Project/ProjectName_ID/file_docID.ext Documents/Contacts/FirstName_LastName_ID/file_docID.ext Documents/Accounts/AccountName_ID/file_docID.ext 🔧 Technical: - FilePathManager for standardized paths - S3StorageService integration - WebSocket server (Node.js + Docker) - Redis cache for getBasicModuleInfo() - Predis library for Redis connectivity 📝 Scripts: - Migration scripts for all modules - Test pages for WebSocket/SSE/Polling - Documentation (MIGRATION_*.md, REDIS_*.md) 🎯 Result: 15,000+ files migrated successfully!
This commit is contained in:
204
crm_extensions/file_storage/migrate_all_remaining_projects.php
Normal file
204
crm_extensions/file_storage/migrate_all_remaining_projects.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/**
|
||||
* Миграция ВСЕХ оставшихся файлов проектов (независимо от статуса)
|
||||
* Перемещает файлы из Documents/documentID/ в Documents/Project/projectName_projectID/
|
||||
*/
|
||||
|
||||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
|
||||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
|
||||
|
||||
// Загружаем переменные окружения
|
||||
$envFile = '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env';
|
||||
if (file_exists($envFile)) {
|
||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos($line, '=') !== false && strpos($line, '#') !== 0) {
|
||||
list($key, $value) = explode('=', $line, 2);
|
||||
$_ENV[trim($key)] = trim($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use Aws\S3\S3Client;
|
||||
use Aws\Exception\AwsException;
|
||||
|
||||
echo "🚀 Миграция ВСЕХ оставшихся файлов проектов...\n\n";
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
try {
|
||||
$s3Client = new S3Client([
|
||||
'version' => 'latest',
|
||||
'region' => 'ru-1',
|
||||
'endpoint' => 'https://s3.twcstorage.ru',
|
||||
'credentials' => [
|
||||
'key' => $_ENV['S3_ACCESS_KEY'],
|
||||
'secret' => $_ENV['S3_SECRET_KEY'],
|
||||
],
|
||||
'use_path_style_endpoint' => true,
|
||||
]);
|
||||
|
||||
$pdo = new PDO("mysql:host={$dbconfig['db_server']};dbname={$dbconfig['db_name']};charset=utf8mb4", $dbconfig['db_username'], $dbconfig['db_password']);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->exec("SET NAMES utf8mb4");
|
||||
|
||||
echo "✅ Подключения установлены\n\n";
|
||||
|
||||
// Находим ВСЕ файлы проектов в старой структуре (без фильтра по статусу!)
|
||||
$sql = "
|
||||
SELECT
|
||||
n.notesid,
|
||||
n.title,
|
||||
n.s3_key,
|
||||
n.filename,
|
||||
p.projectid,
|
||||
p.projectname,
|
||||
p.projectstatus
|
||||
FROM vtiger_notes n
|
||||
INNER JOIN vtiger_senotesrel sr ON n.notesid = sr.notesid
|
||||
INNER JOIN vtiger_project p ON sr.crmid = p.projectid
|
||||
WHERE n.filelocationtype = 'E'
|
||||
AND n.s3_key IS NOT NULL
|
||||
AND n.s3_key NOT LIKE '%/Project/%'
|
||||
ORDER BY p.projectid, n.notesid
|
||||
";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
$files = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo "📊 Найдено файлов проектов для миграции: " . count($files) . "\n\n";
|
||||
|
||||
if (empty($files)) {
|
||||
echo "✅ Все файлы проектов уже мигрированы!\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$bucket = $_ENV['S3_BUCKET'];
|
||||
$migratedCount = 0;
|
||||
$errorCount = 0;
|
||||
$currentProjectId = null;
|
||||
$projectCount = 0;
|
||||
|
||||
foreach ($files as $file) {
|
||||
$notesId = $file['notesid'];
|
||||
$title = $file['title'];
|
||||
$currentS3Key = $file['s3_key'];
|
||||
$projectId = $file['projectid'];
|
||||
$projectName = $file['projectname'];
|
||||
$projectStatus = $file['projectstatus'];
|
||||
|
||||
// Считаем проекты
|
||||
if ($currentProjectId !== $projectId) {
|
||||
$currentProjectId = $projectId;
|
||||
$projectCount++;
|
||||
|
||||
// Выводим прогресс каждые 10 проектов
|
||||
if ($projectCount % 10 == 0) {
|
||||
echo "\n📊 Обработано проектов: {$projectCount}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Компактный вывод
|
||||
if ($migratedCount % 50 == 0 && $migratedCount > 0) {
|
||||
echo "📊 Мигрировано файлов: {$migratedCount}, ошибок: {$errorCount}\n";
|
||||
}
|
||||
|
||||
try {
|
||||
// Правильная нормализация имени проекта (СОХРАНЯЕМ КИРИЛЛИЦУ!)
|
||||
$normalizedName = preg_replace('/[\/\\:*?"<>|№]/u', '_', $projectName);
|
||||
$normalizedName = preg_replace('/\s+/', '_', trim($normalizedName));
|
||||
$normalizedName = preg_replace('/_+/', '_', $normalizedName);
|
||||
$normalizedName = trim($normalizedName, '_');
|
||||
|
||||
if (empty($normalizedName)) {
|
||||
$normalizedName = "project_{$projectId}";
|
||||
}
|
||||
|
||||
// Правильная нормализация имени файла (СОХРАНЯЕМ КИРИЛЛИЦУ!)
|
||||
$normalizedTitle = preg_replace('/[\/\\:*?"<>|№]/u', '_', $title);
|
||||
$normalizedTitle = preg_replace('/\s+/', '_', trim($normalizedTitle));
|
||||
$normalizedTitle = preg_replace('/_+/', '_', $normalizedTitle);
|
||||
$normalizedTitle = trim($normalizedTitle, '_');
|
||||
|
||||
if (empty($normalizedTitle)) {
|
||||
$normalizedTitle = "file_{$notesId}";
|
||||
}
|
||||
|
||||
// Получаем расширение файла из РЕАЛЬНОГО s3_key
|
||||
$extension = pathinfo($currentS3Key, PATHINFO_EXTENSION);
|
||||
if (empty($extension)) {
|
||||
$extension = 'pdf';
|
||||
}
|
||||
|
||||
// Формируем новый путь
|
||||
$targetS3Key = "crm2/CRM_Active_Files/Documents/Project/{$normalizedName}_{$projectId}/{$normalizedTitle}_{$notesId}.{$extension}";
|
||||
|
||||
// Проверяем существование текущего файла в S3
|
||||
$currentS3Key = ltrim($currentS3Key, '/');
|
||||
|
||||
try {
|
||||
$s3Client->headObject([
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $currentS3Key
|
||||
]);
|
||||
|
||||
// Копируем файл в новое место
|
||||
$s3Client->copyObject([
|
||||
'Bucket' => $bucket,
|
||||
'CopySource' => $bucket . '/' . $currentS3Key,
|
||||
'Key' => $targetS3Key
|
||||
]);
|
||||
|
||||
// Проверяем что новый файл существует
|
||||
$s3Client->headObject([
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $targetS3Key
|
||||
]);
|
||||
|
||||
// Удаляем старый файл
|
||||
$s3Client->deleteObject([
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $currentS3Key
|
||||
]);
|
||||
|
||||
// Обновляем записи в БД
|
||||
$newFilename = 'https://s3.twcstorage.ru/' . $bucket . '/' . $targetS3Key;
|
||||
|
||||
$updateSql = "UPDATE vtiger_notes SET s3_key = ?, filename = ? WHERE notesid = ?";
|
||||
$updateStmt = $pdo->prepare($updateSql);
|
||||
$updateStmt->execute([$targetS3Key, $newFilename, $notesId]);
|
||||
|
||||
$migratedCount++;
|
||||
|
||||
} catch (AwsException $e) {
|
||||
if ($e->getAwsErrorCode() === 'NotFound') {
|
||||
// Файл не найден в S3 - пропускаем молча
|
||||
} else {
|
||||
echo "❌ S3 ошибка для файла {$notesId}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
$errorCount++;
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "❌ Ошибка для файла {$notesId}: " . $e->getMessage() . "\n";
|
||||
$errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n\n🎉 МИГРАЦИЯ ЗАВЕРШЕНА!\n";
|
||||
echo "📊 Статистика:\n";
|
||||
echo " • Проектов обработано: {$projectCount}\n";
|
||||
echo " • Файлов мигрировано: {$migratedCount}\n";
|
||||
echo " • Ошибок: {$errorCount}\n";
|
||||
echo " • Всего файлов: " . count($files) . "\n";
|
||||
|
||||
if ($errorCount > 0) {
|
||||
echo "\n⚠️ Ошибки: файлы отсутствуют в S3 или проблемы с доступом\n";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "❌ КРИТИЧЕСКАЯ ОШИБКА: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user