✨ 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!
209 lines
8.1 KiB
PHP
209 lines
8.1 KiB
PHP
<?php
|
||
/**
|
||
* API v2 для подготовки файла к редактированию в Nextcloud
|
||
* Использует новую структуру файлов с FilePathManager
|
||
*/
|
||
|
||
// Подключаем конфигурацию
|
||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
|
||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/FilePathManager.php';
|
||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
|
||
|
||
// Загружаем переменные окружения
|
||
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
|
||
|
||
// Устанавливаем заголовки для JSON
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
header('Access-Control-Allow-Origin: *');
|
||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||
header('Access-Control-Allow-Headers: Content-Type');
|
||
|
||
// Включаем отображение ошибок для отладки
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', 1);
|
||
|
||
// Обрабатываем OPTIONS запросы
|
||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||
http_response_code(200);
|
||
exit;
|
||
}
|
||
|
||
try {
|
||
// Логируем запрос для отладки
|
||
error_log("Nextcloud API v2 called with: " . json_encode($_GET));
|
||
|
||
// Получаем параметры
|
||
$recordId = $_GET['recordId'] ?? $_POST['recordId'] ?? null;
|
||
$fileName = $_GET['fileName'] ?? $_POST['fileName'] ?? null;
|
||
$module = $_GET['module'] ?? $_POST['module'] ?? 'Project';
|
||
|
||
// Декодируем URL-кодированное имя файла
|
||
if ($fileName) {
|
||
$fileName = urldecode($fileName);
|
||
}
|
||
|
||
error_log("Parsed parameters: recordId=$recordId, fileName=$fileName, module=$module");
|
||
|
||
if (!$recordId || !$fileName) {
|
||
throw new Exception('Необходимы параметры recordId и fileName');
|
||
}
|
||
|
||
// Инициализируем FilePathManager
|
||
$pathMgr = new FilePathManager();
|
||
|
||
// Получаем информацию о файле из CRM
|
||
error_log("API: Calling getFileInfoFromCRM with recordId=$recordId, fileName=$fileName, module=$module");
|
||
$fileInfo = getFileInfoFromCRM($recordId, $fileName, $module);
|
||
error_log("API: getFileInfoFromCRM returned: " . json_encode($fileInfo));
|
||
|
||
if (!$fileInfo) {
|
||
// Добавляем отладочную информацию
|
||
$debugInfo = "recordId=$recordId, fileName=$fileName, module=$module";
|
||
throw new Exception("Файл не найден в CRM для записи $recordId. Debug: $debugInfo");
|
||
}
|
||
|
||
// Получаем правильный путь через FilePathManager
|
||
$recordName = $pathMgr->getRecordName($module, $recordId);
|
||
$filePath = $pathMgr->getFilePath($module, $recordId, $fileInfo['documentId'], $fileName, $fileInfo['title'], $recordName);
|
||
|
||
error_log("Generated file path: $filePath");
|
||
|
||
// Формируем URL для Nextcloud (используем внешнее хранилище S3)
|
||
$nextcloudPath = '/crm/' . $filePath;
|
||
|
||
error_log("Nextcloud path: $nextcloudPath");
|
||
|
||
// Создаём прямую ссылку для редактирования (Nextcloud сам найдет файл по пути)
|
||
$editResult = createDirectEditLink($nextcloudPath, $recordId, $fileName, $fileInfo['documentId']);
|
||
|
||
// Возвращаем результат
|
||
echo json_encode([
|
||
'success' => true,
|
||
'data' => [
|
||
'record_id' => $recordId,
|
||
'document_id' => $fileInfo['documentId'],
|
||
'file_name' => $fileName,
|
||
'file_id' => $fileInfo['documentId'],
|
||
'file_path' => $filePath,
|
||
'nextcloud_path' => $nextcloudPath,
|
||
'edit_url' => $editResult['edit_url'],
|
||
'share_url' => $editResult['share_url'] ?? null,
|
||
'message' => 'Файл подготовлен к редактированию'
|
||
]
|
||
]);
|
||
|
||
} catch (Exception $e) {
|
||
error_log("API v2 Error: " . $e->getMessage());
|
||
http_response_code(500);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'error' => $e->getMessage()
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Получает информацию о файле из CRM
|
||
*/
|
||
function getFileInfoFromCRM($recordId, $fileName, $module) {
|
||
try {
|
||
// Используем PDO для подключения к БД
|
||
$dsn = 'mysql:host=localhost;dbname=ci20465_72new;charset=utf8';
|
||
$pdo = new PDO($dsn, 'ci20465_72new', 'CRM_DB_Pass_2025_Secure!');
|
||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||
|
||
// Ищем файл в базе данных по documentId (извлекаем из fileName)
|
||
$documentId = null;
|
||
if (preg_match('/_(\d+)\.pdf$/', $fileName, $matches)) {
|
||
$documentId = (int)$matches[1];
|
||
}
|
||
|
||
if (!$documentId) {
|
||
error_log("ERROR: Could not extract documentId from fileName: $fileName");
|
||
return null;
|
||
}
|
||
|
||
error_log("Extracted documentId=$documentId from fileName=$fileName");
|
||
|
||
$sql = "SELECT n.notesid, n.title, n.filename, n.s3_key, n.s3_bucket
|
||
FROM vtiger_notes n
|
||
INNER JOIN vtiger_senotesrel sr ON n.notesid = sr.notesid
|
||
WHERE sr.crmid = ? AND n.notesid = ?";
|
||
|
||
$stmt = $pdo->prepare($sql);
|
||
$stmt->execute([$recordId, $documentId]);
|
||
|
||
error_log("Searching for recordId=$recordId, documentId=$documentId");
|
||
|
||
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||
error_log("Found file: " . json_encode($row));
|
||
return [
|
||
'documentId' => $row['notesid'],
|
||
'title' => $row['title'],
|
||
'filename' => $row['filename'],
|
||
's3_key' => $row['s3_key'],
|
||
's3_bucket' => $row['s3_bucket']
|
||
];
|
||
}
|
||
|
||
error_log("No file found for recordId=$recordId, documentId=$documentId");
|
||
|
||
return null;
|
||
|
||
} catch (Exception $e) {
|
||
error_log("Error getting file info from CRM: " . $e->getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Проверяет существование файла в S3
|
||
*/
|
||
function checkFileInS3($filePath) {
|
||
try {
|
||
// Используем S3 клиент для проверки
|
||
require_once __DIR__ . '/../S3Client.php';
|
||
|
||
$s3Config = [
|
||
'version' => 'latest',
|
||
'region' => 'ru-1',
|
||
'endpoint' => 'https://s3.twcstorage.ru',
|
||
'bucket' => 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c',
|
||
'use_path_style_endpoint' => true,
|
||
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
|
||
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
|
||
];
|
||
|
||
$s3Client = new S3Client($s3Config);
|
||
return $s3Client->fileExists($filePath);
|
||
|
||
} catch (Exception $e) {
|
||
error_log("Error checking S3 file: " . $e->getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Создаёт прямую ссылку для редактирования
|
||
*/
|
||
function createDirectEditLink($nextcloudPath, $recordId, $fileName, $documentId) {
|
||
$baseUrl = 'https://office.clientright.ru:8443';
|
||
|
||
// Кодируем путь правильно для Nextcloud
|
||
$pathParts = explode('/', $nextcloudPath);
|
||
$encodedParts = array_map('rawurlencode', $pathParts);
|
||
$encodedPath = implode('/', $encodedParts);
|
||
|
||
// Извлекаем директорию (без имени файла)
|
||
$dir = dirname($nextcloudPath);
|
||
$encodedDir = str_replace(basename($nextcloudPath), '', $encodedPath);
|
||
$encodedDir = rtrim($encodedDir, '/');
|
||
|
||
// URL для открытия файла в Nextcloud Files (он сам найдет fileId по пути)
|
||
$filesUrl = "$baseUrl/apps/files/?dir=" . rawurlencode($dir) . "&openfile=" . rawurlencode(basename($nextcloudPath));
|
||
|
||
return [
|
||
'edit_url' => $filesUrl,
|
||
'share_url' => $filesUrl
|
||
];
|
||
}
|