🚀 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:
Fedor
2025-10-24 19:59:28 +03:00
parent 3fb2ad5f60
commit 9245768987
1062 changed files with 161778 additions and 16212 deletions

View File

@@ -7,20 +7,26 @@
* - Загрузка файлов в S3 с retry механизмом
* - Получение presigned URLs для скачивания
* - Логирование ошибок
* - Поддержка универсальной структуры путей через FilePathManager
*
* @author AI Assistant
* @date 2025-09-20
* @date 2025-10-22 (updated)
*/
require_once __DIR__ . '/../../crm_extensions/file_storage/S3Client.php';
require_once __DIR__ . '/../../crm_extensions/file_storage/FilePathManager.php';
class S3StorageService {
private $s3Client;
private $bucket;
private $prefix;
private $config;
private $filePathManager;
public function __construct() {
// Инициализируем FilePathManager
$this->filePathManager = new FilePathManager();
// Загружаем конфигурацию S3
try {
file_put_contents('logs/debug.log', '[' . date('Y-m-d H:i:s') . '] S3StorageService: Loading config...' . PHP_EOL, FILE_APPEND);
@@ -43,17 +49,34 @@ class S3StorageService {
}
/**
* Загрузка файла в S3 с retry механизмом
* Загрузка файла в S3 с поддержкой универсальной структуры
*
* @param string $tmpFile Временный файл на сервере
* @param int $notesId ID записи документа
* @param string $filename Имя файла
* @param int $maxRetries Максимальное количество попыток
* @param array $context Контекст: ['module' => string, 'recordId' => int, 'recordName' => string, 'documentTitle' => string]
* @return array Результат загрузки
* @throws Exception При неудачной загрузке
*/
public function put($tmpFile, $notesId, $filename, $maxRetries = 3) {
$key = $this->prefix . '/' . $notesId . '/' . $filename;
public function put($tmpFile, $notesId, $filename, $maxRetries = 3, $context = []) {
// Определяем путь к файлу
if (!empty($context['module']) && !empty($context['recordId'])) {
// Новая универсальная структура
$module = $context['module'];
$recordId = $context['recordId'];
$recordName = $context['recordName'] ?? null;
$documentTitle = $context['documentTitle'] ?? null;
$key = $this->filePathManager->getFilePath($module, $recordId, $notesId, $filename, $documentTitle, $recordName);
$this->logInfo("Using universal path structure: module=$module, recordId=$recordId");
} else {
// Старая структура (обратная совместимость)
$key = $this->prefix . '/' . $notesId . '/' . $filename;
$this->logInfo("Using legacy path structure");
}
$this->logInfo("Starting S3 upload: key=$key, file=$tmpFile");
@@ -75,7 +98,9 @@ class S3StorageService {
'Metadata' => [
'notesId' => (string)$notesId,
'originalName' => (string)$filename,
'uploadedAt' => (string)date('Y-m-d H:i:s')
'uploadedAt' => (string)date('Y-m-d H:i:s'),
'module' => !empty($context['module']) ? (string)$context['module'] : '',
'recordId' => !empty($context['recordId']) ? (string)$context['recordId'] : ''
]
]);
@@ -262,7 +287,6 @@ class S3StorageService {
public function getPrefix() {
return $this->prefix;
}
/**
* Получение имени bucket'а
*
@@ -271,5 +295,14 @@ class S3StorageService {
public function getBucket() {
return $this->bucket;
}
/**
* Получение экземпляра FilePathManager
*
* @return FilePathManager
*/
public function getFilePathManager() {
return $this->filePathManager;
}
}
?>