Обновленные файлы: - crm_extensions/nextcloud_api.php (2 места) - modules/Documents/actions/NcPrepareEdit.php - crm_extensions/nextcloud_editor/js/nextcloud-editor.js - crm_extensions/file_storage/api/get_edit_urls.php - crm_extensions/file_storage/api/simple_edit.php - crm_extensions/README.md - NEXTCLOUD_EDIT_BUTTON_IMPLEMENTATION.md - crm_extensions/docs/NEXTCLOUD_EDITOR.md - test_syntax_check.html - crm_extensions/tests/test_edit_button.html Все ссылки теперь указывают на новый сервер office.clientright.ru Backup файлы и тестовые директории не изменены
203 lines
7.3 KiB
PHP
203 lines
7.3 KiB
PHP
<?php
|
||
/**
|
||
* Action для подготовки файла к редактированию в Nextcloud
|
||
*/
|
||
|
||
class Documents_NcPrepareEdit_Action extends Vtiger_Action_Controller {
|
||
|
||
public function requiresPermission(\Vtiger_Request $request) {
|
||
$permissions = parent::requiresPermission($request);
|
||
$permissions[] = array('module_parameter' => 'module', 'action' => 'DetailView', 'record_parameter' => 'record');
|
||
return $permissions;
|
||
}
|
||
|
||
public function checkPermission(\Vtiger_Request $request) {
|
||
return parent::checkPermission($request);
|
||
}
|
||
|
||
public function process(\Vtiger_Request $request) {
|
||
// Устанавливаем заголовки
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
|
||
try {
|
||
$recordId = trim($request->get('record'));
|
||
$fileName = trim($request->get('fileName'));
|
||
|
||
if (empty($recordId) || empty($fileName)) {
|
||
throw new Exception('record или fileName отсутствуют');
|
||
}
|
||
|
||
// Проверяем поддерживаемые расширения
|
||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||
if (!in_array($ext, ['docx', 'xlsx', 'pptx'], true)) {
|
||
throw new Exception('Неподдерживаемое расширение: ' . $ext);
|
||
}
|
||
|
||
// Получаем fileId из Nextcloud
|
||
$fileId = $this->resolveNcFileId((int)$recordId, $fileName);
|
||
|
||
$baseUrl = $this->getNcBaseUrl();
|
||
$dirPath = $this->getDirPath($recordId);
|
||
|
||
$urls = [
|
||
'collabora_id' => $fileId ? $baseUrl . '/apps/richdocuments/index?fileId=' . rawurlencode((string)$fileId) : null,
|
||
'onlyoffice_id' => $fileId ? $baseUrl . '/apps/onlyoffice?fileId=' . rawurlencode((string)$fileId) : null,
|
||
'files_manager' => $baseUrl . '/apps/files/?dir=' . rawurlencode($dirPath) . '&openfile=' . rawurlencode($fileName)
|
||
];
|
||
|
||
// Убираем null значения
|
||
$urls = array_filter($urls, function($url) {
|
||
return $url !== null;
|
||
});
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'data' => [
|
||
'record_id' => $recordId,
|
||
'file_name' => $fileName,
|
||
'file_id' => $fileId,
|
||
'urls' => $urls,
|
||
'message' => 'Файл подготовлен к редактированию'
|
||
]
|
||
], JSON_UNESCAPED_UNICODE);
|
||
|
||
} catch (Exception $e) {
|
||
http_response_code(500);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'error' => $e->getMessage()
|
||
], JSON_UNESCAPED_UNICODE);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Получение базового URL Nextcloud
|
||
*/
|
||
private function getNcBaseUrl(): string {
|
||
return 'https://office.clientright.ru';
|
||
}
|
||
|
||
/**
|
||
* Получение пути к директории
|
||
*/
|
||
private function getDirPath($recordId): string {
|
||
return '/crm2/CRM_Active_Files/Documents/' . $recordId;
|
||
}
|
||
|
||
/**
|
||
* Получение fileId из Nextcloud через WebDAV
|
||
*/
|
||
private function resolveNcFileId(int $recordId, string $fileName): ?int {
|
||
try {
|
||
$config = $this->getNcConfig();
|
||
$ncPath = $this->getNcPath($recordId, $fileName);
|
||
|
||
// 1) PROPFIND для получения метаданных
|
||
$meta = $this->webdavPropfind($config, $ncPath);
|
||
|
||
if ($meta['status'] === 404) {
|
||
// Файл не существует - нужно создать
|
||
error_log("File not found in Nextcloud: {$ncPath}");
|
||
return null;
|
||
}
|
||
|
||
if ($meta['status'] === 200 && isset($meta['fileid'])) {
|
||
error_log("Found fileId for {$fileName}: " . $meta['fileid']);
|
||
return (int)$meta['fileid'];
|
||
}
|
||
|
||
error_log("Could not get fileId from PROPFIND response");
|
||
return null;
|
||
|
||
} catch (Exception $e) {
|
||
error_log('Error resolving fileId: ' . $e->getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Получение конфигурации Nextcloud
|
||
*/
|
||
private function getNcConfig(): array {
|
||
$configPath = __DIR__ . '/../../../../crm_extensions/file_storage/config.php';
|
||
if (!file_exists($configPath)) {
|
||
throw new Exception('Nextcloud config not found');
|
||
}
|
||
$config = require_once $configPath;
|
||
return $config['nextcloud'];
|
||
}
|
||
|
||
/**
|
||
* Получение пути к файлу в Nextcloud
|
||
*/
|
||
private function getNcPath(int $recordId, string $fileName): string {
|
||
return "/crm2/CRM_Active_Files/Documents/{$recordId}/" . rawurlencode($fileName);
|
||
}
|
||
|
||
/**
|
||
* WebDAV PROPFIND запрос
|
||
*/
|
||
private function webdavPropfind(array $config, string $remotePath): array {
|
||
$url = $config['base_url'] . '/remote.php/dav/files/' . $config['username'] . $remotePath;
|
||
|
||
$ch = curl_init();
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_URL => $url,
|
||
CURLOPT_CUSTOMREQUEST => 'PROPFIND',
|
||
CURLOPT_USERPWD => $config['username'] . ':' . $config['password'],
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_TIMEOUT => 30,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/xml',
|
||
'Depth: 0'
|
||
],
|
||
CURLOPT_POSTFIELDS => '<?xml version="1.0" encoding="UTF-8"?>
|
||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||
<d:prop>
|
||
<d:getetag/>
|
||
<d:getlastmodified/>
|
||
<d:getcontentlength/>
|
||
<oc:fileid/>
|
||
</d:prop>
|
||
</d:propfind>'
|
||
]);
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
$error = curl_error($ch);
|
||
curl_close($ch);
|
||
|
||
if ($error) {
|
||
throw new Exception("cURL error: {$error}");
|
||
}
|
||
|
||
$result = ['status' => $httpCode];
|
||
|
||
if ($httpCode === 207 && $response) {
|
||
// Извлекаем данные с помощью регулярных выражений
|
||
// Ищем fileid
|
||
if (preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches)) {
|
||
$result['fileid'] = $matches[1];
|
||
}
|
||
|
||
// Ищем etag
|
||
if (preg_match('/<d:getetag>"([^&]+)"<\/d:getetag>/', $response, $matches)) {
|
||
$result['etag'] = $matches[1];
|
||
}
|
||
|
||
// Ищем размер
|
||
if (preg_match('/<d:getcontentlength>(\d+)<\/d:getcontentlength>/', $response, $matches)) {
|
||
$result['size'] = (int)$matches[1];
|
||
}
|
||
|
||
// Ищем дату модификации
|
||
if (preg_match('/<d:getlastmodified>([^<]+)<\/d:getlastmodified>/', $response, $matches)) {
|
||
$result['mtime'] = $matches[1];
|
||
}
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
}
|
||
?>
|