'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 '/crm/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 "/crm/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 => '
'
]);
$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('/(\d+)<\/oc:fileid>/', $response, $matches)) {
$result['fileid'] = $matches[1];
}
// Ищем etag
if (preg_match('/"([^&]+)"<\/d:getetag>/', $response, $matches)) {
$result['etag'] = $matches[1];
}
// Ищем размер
if (preg_match('/(\d+)<\/d:getcontentlength>/', $response, $matches)) {
$result['size'] = (int)$matches[1];
}
// Ищем дату модификации
if (preg_match('/([^<]+)<\/d:getlastmodified>/', $response, $matches)) {
$result['mtime'] = $matches[1];
}
}
return $result;
}
}
?>