'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; } } ?>