Исправление путей к папкам проектов в Nextcloud + создание файлов из CRM

🔧 Исправления:
- Исправлены пути к папкам проектов: теперь /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 теперь открывается по правильному пути!
This commit is contained in:
Fedor
2025-11-01 12:22:12 +03:00
parent 3a1635ec4d
commit 7e3f0dcede
117 changed files with 2520 additions and 2034 deletions

View File

@@ -0,0 +1,233 @@
<?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';
}
?>

View File

@@ -0,0 +1,97 @@
<?php
/**
* Открытие файла через Nextcloud + OnlyOffice
* Для сравнения с прямым OnlyOffice
*/
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');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
}
}
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Nextcloud credentials
$nextcloudUrl = 'https://office.clientright.ru:8443';
$username = 'admin';
$password = 'office';
// Формируем WebDAV путь
$ncPath = '/crm/' . $s3Path;
$webdavUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . $ncPath;
error_log("=== NEXTCLOUD OPEN ===");
error_log("S3 Path: " . $s3Path);
error_log("Nextcloud WebDAV: " . $webdavUrl);
// Получаем fileId через PROPFIND
$ch = curl_init($webdavUrl);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PROPFIND');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Depth: 0',
'Content-Type: application/xml'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, '<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:fileid/>
</d:prop>
</d:propfind>');
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("PROPFIND HTTP код: " . $httpCode);
if ($httpCode !== 207) {
die("❌ Файл не найден в Nextcloud (HTTP $httpCode). Возможно, он не проиндексирован.");
}
// Извлекаем fileId из XML
preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches);
if (!isset($matches[1])) {
die("Не удалось получить fileId");
}
$fileId = $matches[1];
error_log("Получен fileId: " . $fileId);
// Извлекаем директорию из пути
$dirPath = dirname($ncPath);
// Формируем URL для открытия в Nextcloud
// Nextcloud автоматически откроет OnlyOffice для редактирования
$redirectUrl = $nextcloudUrl . '/apps/files/files/' . $fileId . '?dir=' . urlencode($dirPath) . '&openfile=true';
error_log("Redirect to: " . $redirectUrl);
// Редирект в Nextcloud
header('Location: ' . $redirectUrl);
exit;
?>

View File

@@ -0,0 +1,39 @@
<?php
/**
* Создание минимальных пустых шаблонов Office файлов
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpPresentation\PhpPresentation;
$templatesDir = __DIR__ . '/templates/';
// Создаём Word документ
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$section->addText('');
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$objWriter->save($templatesDir . 'empty.docx');
echo "✅ Created empty.docx\n";
// Создаём Excel таблицу
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', '');
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save($templatesDir . 'empty.xlsx');
echo "✅ Created empty.xlsx\n";
// Создаём PowerPoint презентацию
$presentation = new PhpPresentation();
$slide = $presentation->getActiveSlide();
$writer = \PhpOffice\PhpPresentation\IOFactory::createWriter($presentation, 'PowerPoint2007');
$writer->save($templatesDir . 'empty.pptx');
echo "✅ Created empty.pptx\n";
echo "\nВсе шаблоны созданы!\n";
?>

View File

@@ -121,3 +121,4 @@ process.on('SIGTERM', () => {
process.exit(0);
});

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -22,8 +22,8 @@ function openProjectFolder(projectId, projectName) {
const encodedFolderName = encodeURIComponent(folderName);
const nextcloudUrl = 'https://office.clientright.ru:8443';
// URL для папки проекта в Nextcloud External Storage
const folderUrl = `${nextcloudUrl}/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/${encodedFolderName}`;
// URL для папки проекта в Nextcloud External Storage (со структурой Project/)
const folderUrl = `${nextcloudUrl}/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/Project/${encodedFolderName}`;
console.log('🔗 Folder URL:', folderUrl);