187 lines
7.2 KiB
PHP
187 lines
7.2 KiB
PHP
|
|
<?php
|
|||
|
|
/**
|
|||
|
|
* File Storage Manager (Production Ready)
|
|||
|
|
* Менеджер для работы с S3 + Nextcloud + vTiger интеграцией
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
require_once __DIR__ . '/S3Client.php';
|
|||
|
|
require_once __DIR__ . '/NextcloudClient.php';
|
|||
|
|
require_once __DIR__ . '/../shared/Logger.php';
|
|||
|
|
|
|||
|
|
class FileStorageManager {
|
|||
|
|
private $s3Client;
|
|||
|
|
private $nextcloudClient;
|
|||
|
|
private $config;
|
|||
|
|
|
|||
|
|
public function __construct() {
|
|||
|
|
$this->config = require __DIR__ . '/config.php';
|
|||
|
|
$this->s3Client = new S3Client($this->config['s3']);
|
|||
|
|
$this->nextcloudClient = new NextcloudClient($this->config['nextcloud']);
|
|||
|
|
|
|||
|
|
CRM_Logger::info('FileStorageManager initialized');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Подготовка файла для редактирования
|
|||
|
|
* Получает файл из vTiger и готовит его в Nextcloud
|
|||
|
|
*/
|
|||
|
|
public function prepareForEditing($recordId, $fileName) {
|
|||
|
|
try {
|
|||
|
|
CRM_Logger::info("Preparing file for editing", ['record_id' => $recordId, 'file_name' => $fileName]);
|
|||
|
|
|
|||
|
|
// 1. Получаем информацию о файле из vTiger
|
|||
|
|
$fileInfo = $this->getVTigerFileInfo($recordId);
|
|||
|
|
if (!$fileInfo) {
|
|||
|
|
throw new Exception('File not found in vTiger CRM');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. Генерируем пути
|
|||
|
|
$nextcloudPath = $this->generateNextcloudPath($fileInfo);
|
|||
|
|
|
|||
|
|
// 3. Проверяем есть ли файл в Nextcloud
|
|||
|
|
if (!$this->nextcloudClient->fileExists($nextcloudPath)) {
|
|||
|
|
CRM_Logger::info("File not in Nextcloud, uploading from vTiger", ['local_path' => $fileInfo['local_path']]);
|
|||
|
|
|
|||
|
|
// Загружаем файл из локального хранилища vTiger в Nextcloud
|
|||
|
|
$uploadResult = $this->nextcloudClient->uploadFile($fileInfo['local_path'], $nextcloudPath);
|
|||
|
|
if (!$uploadResult['success']) {
|
|||
|
|
throw new Exception('Failed to upload to Nextcloud: ' . $uploadResult['error']);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CRM_Logger::info("File uploaded to Nextcloud successfully", ['nextcloud_path' => $nextcloudPath]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. Создаём ссылку для редактирования
|
|||
|
|
$editLinkResult = $this->nextcloudClient->createEditLink($nextcloudPath);
|
|||
|
|
if (!$editLinkResult['success']) {
|
|||
|
|
throw new Exception('Failed to create edit link: ' . $editLinkResult['error']);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CRM_Logger::info("Edit link created successfully", [
|
|||
|
|
'record_id' => $recordId,
|
|||
|
|
'edit_url' => $editLinkResult['edit_url']
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
return [
|
|||
|
|
'success' => true,
|
|||
|
|
'edit_url' => $editLinkResult['edit_url'],
|
|||
|
|
'share_url' => $editLinkResult['share_url'],
|
|||
|
|
'nextcloud_path' => $nextcloudPath,
|
|||
|
|
'file_info' => $fileInfo
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
CRM_Logger::error("Failed to prepare file for editing", [
|
|||
|
|
'record_id' => $recordId,
|
|||
|
|
'error' => $e->getMessage()
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
return [
|
|||
|
|
'success' => false,
|
|||
|
|
'error' => $e->getMessage()
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Получение информации о файле из vTiger
|
|||
|
|
*/
|
|||
|
|
private function getVTigerFileInfo($recordId) {
|
|||
|
|
try {
|
|||
|
|
// Подключаемся к базе данных vTiger
|
|||
|
|
$config_inc = dirname(dirname(__DIR__)) . '/config.inc.php';
|
|||
|
|
if (file_exists($config_inc)) {
|
|||
|
|
require_once $config_inc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Получаем информацию о файле из базы данных
|
|||
|
|
$query = "
|
|||
|
|
SELECT
|
|||
|
|
n.notesid,
|
|||
|
|
n.title,
|
|||
|
|
n.filename,
|
|||
|
|
n.filelocationtype,
|
|||
|
|
a.attachmentsid,
|
|||
|
|
a.name as stored_name,
|
|||
|
|
a.type as mime_type,
|
|||
|
|
a.path
|
|||
|
|
FROM vtiger_notes n
|
|||
|
|
LEFT JOIN vtiger_seattachmentsrel sar ON n.notesid = sar.crmid
|
|||
|
|
LEFT JOIN vtiger_attachments a ON sar.attachmentsid = a.attachmentsid
|
|||
|
|
WHERE n.notesid = ?
|
|||
|
|
";
|
|||
|
|
|
|||
|
|
// Используем PDO для безопасного запроса
|
|||
|
|
$pdo = new PDO("mysql:host=localhost;dbname=" . $dbconfig['db_name'], $dbconfig['db_username'], $dbconfig['db_password']);
|
|||
|
|
$stmt = $pdo->prepare($query);
|
|||
|
|
$stmt->execute([$recordId]);
|
|||
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|||
|
|
|
|||
|
|
if (!$result) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Формируем полный путь к файлу
|
|||
|
|
$storagePath = dirname(dirname(__DIR__)) . '/storage/';
|
|||
|
|
$localPath = $storagePath . $result['attachmentsid'] . '_' . $result['stored_name'];
|
|||
|
|
|
|||
|
|
return [
|
|||
|
|
'record_id' => $recordId,
|
|||
|
|
'title' => $result['title'],
|
|||
|
|
'file_name' => $result['filename'],
|
|||
|
|
'stored_name' => $result['stored_name'],
|
|||
|
|
'mime_type' => $result['mime_type'],
|
|||
|
|
'local_path' => $localPath,
|
|||
|
|
'attachments_id' => $result['attachmentsid'],
|
|||
|
|
'file_location_type' => $result['filelocationtype']
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
CRM_Logger::error("Failed to get vTiger file info", [
|
|||
|
|
'record_id' => $recordId,
|
|||
|
|
'error' => $e->getMessage()
|
|||
|
|
]);
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Генерация пути в Nextcloud
|
|||
|
|
*/
|
|||
|
|
private function generateNextcloudPath($fileInfo) {
|
|||
|
|
$recordId = $fileInfo['record_id'];
|
|||
|
|
$fileName = $fileInfo['file_name'];
|
|||
|
|
|
|||
|
|
// Создаём структуру: Documents/RecordID/filename
|
|||
|
|
return "Documents/{$recordId}/{$fileName}";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Синхронизация после редактирования
|
|||
|
|
*/
|
|||
|
|
public function syncAfterEditing($recordId) {
|
|||
|
|
try {
|
|||
|
|
CRM_Logger::info("Syncing file after editing", ['record_id' => $recordId]);
|
|||
|
|
|
|||
|
|
// Пока что просто логируем - полная синхронизация в следующей версии
|
|||
|
|
CRM_Logger::info("Sync completed (placeholder)", ['record_id' => $recordId]);
|
|||
|
|
|
|||
|
|
return [
|
|||
|
|
'success' => true,
|
|||
|
|
'message' => 'Синхронизация выполнена (базовая версия)'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
CRM_Logger::error("Failed to sync file after editing", [
|
|||
|
|
'record_id' => $recordId,
|
|||
|
|
'error' => $e->getMessage()
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
return [
|
|||
|
|
'success' => false,
|
|||
|
|
'error' => $e->getMessage()
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|