🔧 Исправления: - Исправлены пути к папкам проектов: теперь /Documents/Project/{Name}_{Id} - Исправлена функция openProjectFolder() во всех JS файлах - Добавлены кнопки создания Word/Excel/PowerPoint из CRM (10 модулей) - Создание файлов напрямую в S3 с автоиндексацией через Redis - Исправлена ошибка 'Class Redis not found' (использован Predis) 📁 Изменённые файлы: - layouts/v7/lib/nextcloud-editor.js - crm_extensions/nextcloud_editor/js/nextcloud-editor.js - layouts/v7/lib/nextcloud-editor-v3.js - crm_extensions/file_storage/api/create_nextcloud_file.php - layouts/v7/modules/*/DetailViewHeaderTitle.tpl (10 модулей) - layouts/v7/modules/Documents/*.tpl (кнопки редактирования) 🎯 Результат: - Кнопка 'Папка в Nextcloud' открывает правильную папку - Создание файлов работает молниеносно (прямо в S3) - Redis события публикуются корректно - OnlyOffice открывается для редактирования Проект 391552 теперь открывается по правильному пути!
234 lines
7.7 KiB
PHP
234 lines
7.7 KiB
PHP
<?php
|
||
/**
|
||
* Создание нового файла в Nextcloud
|
||
* Создаёт пустой DOCX/XLSX/PPTX и открывает для редактирования
|
||
*/
|
||
|
||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
|
||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
|
||
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
|
||
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', 1);
|
||
|
||
// Параметры
|
||
$module = $_GET['module'] ?? '';
|
||
$recordId = $_GET['recordId'] ?? '';
|
||
$recordName = $_GET['recordName'] ?? '';
|
||
$fileName = $_GET['fileName'] ?? '';
|
||
$fileType = $_GET['fileType'] ?? 'docx';
|
||
|
||
if (empty($module) || empty($recordId) || empty($fileName)) {
|
||
die("❌ Не указаны обязательные параметры");
|
||
}
|
||
|
||
// Nextcloud credentials
|
||
$nextcloudUrl = 'https://office.clientright.ru:8443';
|
||
$username = 'admin';
|
||
$password = 'office';
|
||
|
||
// Определяем папку модуля
|
||
$moduleFolders = [
|
||
'Project' => 'Project',
|
||
'Contacts' => 'Contacts',
|
||
'Accounts' => 'Accounts',
|
||
'Invoice' => 'Invoice',
|
||
'Quotes' => 'Quotes',
|
||
'SalesOrder' => 'SalesOrder',
|
||
'PurchaseOrder' => 'PurchaseOrder',
|
||
'HelpDesk' => 'HelpDesk',
|
||
'Leads' => 'Leads',
|
||
'Potentials' => 'Potentials'
|
||
];
|
||
|
||
$moduleFolder = $moduleFolders[$module] ?? 'Other';
|
||
|
||
// Формируем имя папки записи
|
||
$recordName = preg_replace('/[\/\\\\:\*\?"<>\|]/', '_', $recordName); // Убираем недопустимые символы
|
||
$folderName = $recordName . '_' . $recordId;
|
||
|
||
// Формируем путь к файлу в Nextcloud
|
||
$ncPath = "/crm/crm2/CRM_Active_Files/Documents/{$moduleFolder}/{$folderName}/{$fileName}.{$fileType}";
|
||
$webdavUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . $ncPath;
|
||
|
||
error_log("=== CREATE NEXTCLOUD FILE ===");
|
||
error_log("Module: " . $module);
|
||
error_log("Record ID: " . $recordId);
|
||
error_log("File name: " . $fileName);
|
||
error_log("File type: " . $fileType);
|
||
error_log("Nextcloud path: " . $ncPath);
|
||
error_log("WebDAV URL: " . $webdavUrl);
|
||
|
||
// СОЗДАЁМ ФАЙЛ ЧЕРЕЗ NEXTCLOUD OCS API (Direct Editing)
|
||
// Используем встроенный API Nextcloud для создания нового файла
|
||
|
||
$templateMap = [
|
||
'docx' => 'onlyoffice',
|
||
'xlsx' => 'onlyoffice',
|
||
'pptx' => 'onlyoffice'
|
||
];
|
||
|
||
$editorId = $templateMap[$fileType] ?? 'onlyoffice';
|
||
|
||
// Используем OCS API v2 для создания нового файла
|
||
$createUrl = $nextcloudUrl . '/ocs/v2.php/apps/files/api/v1/directEditing/create';
|
||
|
||
$postData = http_build_query([
|
||
'path' => $ncPath,
|
||
'editorId' => $editorId,
|
||
'templateId' => '',
|
||
'templateType' => $fileType
|
||
]);
|
||
|
||
error_log("Creating file via OCS API: " . $createUrl);
|
||
error_log("Post data: " . $postData);
|
||
|
||
// Вызываем API создания
|
||
$ch = curl_init($createUrl);
|
||
curl_setopt($ch, CURLOPT_POST, true);
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||
'OCS-APIRequest: true',
|
||
'Content-Type: application/x-www-form-urlencoded',
|
||
'Accept: application/json'
|
||
]);
|
||
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
error_log("OCS API response code: " . $httpCode);
|
||
error_log("OCS API response: " . substr($response, 0, 500));
|
||
|
||
// Если API сработал - парсим ответ и получаем URL редактора
|
||
if ($httpCode === 200) {
|
||
$data = json_decode($response, true);
|
||
if (isset($data['ocs']['data']['url'])) {
|
||
$editorUrl = $data['ocs']['data']['url'];
|
||
error_log("Got editor URL from API: " . $editorUrl);
|
||
header('Location: ' . $nextcloudUrl . $editorUrl);
|
||
exit;
|
||
}
|
||
}
|
||
|
||
// Если API не сработал - создаём файл НАПРЯМУЮ В S3 и открываем через OnlyOffice!
|
||
error_log("OCS API failed, creating file directly in S3");
|
||
|
||
// Извлекаем S3 путь из Nextcloud пути
|
||
// /crm/crm2/CRM_Active_Files/... → crm2/CRM_Active_Files/...
|
||
$s3Path = ltrim($ncPath, '/');
|
||
|
||
// S3 credentials
|
||
$s3Client = new Aws\S3\S3Client([
|
||
'version' => 'latest',
|
||
'region' => 'ru-1',
|
||
'endpoint' => 'https://s3.twcstorage.ru',
|
||
'use_path_style_endpoint' => true,
|
||
'credentials' => [
|
||
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
|
||
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
|
||
],
|
||
'suppress_php_deprecation_warning' => true
|
||
]);
|
||
|
||
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||
|
||
// Создаём минимальный пустой файл
|
||
$emptyContent = createEmptyFile($fileType);
|
||
|
||
error_log("Creating file in S3: " . $s3Path . " (" . strlen($emptyContent) . " bytes)");
|
||
|
||
// Загружаем файл в S3
|
||
try {
|
||
$result = $s3Client->putObject([
|
||
'Bucket' => $bucket,
|
||
'Key' => $s3Path,
|
||
'Body' => $emptyContent,
|
||
'ContentType' => getContentType($fileType)
|
||
]);
|
||
|
||
error_log("✅ File created in S3!");
|
||
|
||
} catch (Exception $e) {
|
||
error_log("Failed to create file in S3: " . $e->getMessage());
|
||
die("❌ Не удалось создать файл в S3: " . $e->getMessage());
|
||
}
|
||
|
||
// Формируем S3 URL
|
||
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
|
||
|
||
error_log("S3 URL: " . $s3Url);
|
||
|
||
// Публикуем событие в Redis для индексации Nextcloud
|
||
try {
|
||
// Используем Predis (установлен через composer)
|
||
$redis = new Predis\Client([
|
||
'scheme' => 'tcp',
|
||
'host' => '147.45.146.17',
|
||
'port' => 6379,
|
||
'password' => 'CRM_Redis_Pass_2025_Secure!'
|
||
]);
|
||
|
||
$event = json_encode([
|
||
'type' => 'file_created',
|
||
'source' => 'crm_create_file',
|
||
'path' => $s3Path,
|
||
'timestamp' => time()
|
||
]);
|
||
|
||
$redis->publish('crm:file:events', $event);
|
||
error_log("✅ Published event to Redis");
|
||
|
||
} catch (Exception $e) {
|
||
error_log("Redis publish failed: " . $e->getMessage());
|
||
}
|
||
|
||
// Открываем файл НАПРЯМУЮ через OnlyOffice (быстро!)
|
||
$redirectUrl = '/crm_extensions/file_storage/api/open_file_v2.php?recordId=' . urlencode($recordId) . '&fileName=' . urlencode($s3Url);
|
||
|
||
error_log("Redirecting to OnlyOffice: " . $redirectUrl);
|
||
|
||
// Редирект
|
||
header('Location: ' . $redirectUrl);
|
||
exit;
|
||
|
||
/**
|
||
* Создаёт минимальное пустое содержимое для Office файла
|
||
*/
|
||
function createEmptyFile($fileType) {
|
||
// Используем готовые минимальные шаблоны
|
||
$templatePath = __DIR__ . '/../templates/empty.' . $fileType;
|
||
|
||
if (file_exists($templatePath)) {
|
||
$content = file_get_contents($templatePath);
|
||
error_log("Using template: " . $templatePath . " (" . strlen($content) . " bytes)");
|
||
return $content;
|
||
}
|
||
|
||
error_log("Template not found: " . $templatePath);
|
||
|
||
// Fallback: пустая строка (не будет работать, но хотя бы не упадёт)
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Определяет Content-Type для файла
|
||
*/
|
||
function getContentType($fileType) {
|
||
$types = [
|
||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||
'doc' => 'application/msword',
|
||
'xls' => 'application/vnd.ms-excel',
|
||
'ppt' => 'application/vnd.ms-powerpoint'
|
||
];
|
||
return $types[$fileType] ?? 'application/octet-stream';
|
||
}
|
||
|
||
?>
|
||
|