feat: Полная интеграция CRM → Nextcloud редактор
✅ Что реализовано: - SSL/HTTPS для Nextcloud (Let's Encrypt R13) - Redis кэширование для производительности - Collabora Online редактор документов - WOPI allow list настроен (0.0.0.0/0) - Динамическое получение fileId через WebDAV - Поддержка файлов из S3 и локальных файлов - Автоматическое извлечение имени файла из URL - Промежуточная страница для обхода CSRF 🚀 Как работает: 1. JavaScript передает recordId и fileName 2. PHP получает fileId через WebDAV PROPFIND 3. PHP делает редирект на рабочий URL Nextcloud 4. Файл открывается в редакторе Collabora 📁 Файлы: - layouts/v7/lib/nextcloud-editor.js - JavaScript интеграция - crm_extensions/file_storage/api/open_file.php - PHP редирект - modules/Documents/actions/NcPrepareEdit.php - API подготовка - crm_extensions/docs/ - документация 🎯 Результат: Каждый документ в CRM открывает СВОЙ файл в Nextcloud редакторе!
This commit is contained in:
274
crm_extensions/docs/CRM_NEXTCLOUD_INTEGRATION.md
Normal file
274
crm_extensions/docs/CRM_NEXTCLOUD_INTEGRATION.md
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
# Интеграция CRM → Nextcloud для редактирования документов
|
||||||
|
|
||||||
|
**Дата:** 21 октября 2025
|
||||||
|
**Статус:** ✅ Работает
|
||||||
|
|
||||||
|
## Что настроено
|
||||||
|
|
||||||
|
Кнопка "Nextcloud" в карточке документа теперь открывает файл в редакторе Collabora Online для онлайн-редактирования.
|
||||||
|
|
||||||
|
## Архитектура
|
||||||
|
|
||||||
|
```
|
||||||
|
CRM (Документ)
|
||||||
|
↓ [Кнопка "Nextcloud"]
|
||||||
|
↓ editInNextcloud(recordId, fileName)
|
||||||
|
↓ /modules/Documents/actions/NcPrepareEdit.php
|
||||||
|
↓ WebDAV запрос к Nextcloud (получаем fileId)
|
||||||
|
↓ Формируем URL редактора
|
||||||
|
↓ Открываем в новом окне
|
||||||
|
↓
|
||||||
|
Collabora Online (https://office.clientright.ru:8443)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Файлы
|
||||||
|
|
||||||
|
### Frontend (JavaScript)
|
||||||
|
- **Основной:** `/crm_extensions/nextcloud_editor/js/nextcloud-editor.js`
|
||||||
|
- **Загружается:** `/layouts/v7/lib/nextcloud-editor.js` (копия)
|
||||||
|
- **Подключение:** `/layouts/v7/modules/Vtiger/Header.tpl`
|
||||||
|
|
||||||
|
### Backend (PHP)
|
||||||
|
- **Action:** `/modules/Documents/actions/NcPrepareEdit.php`
|
||||||
|
- **Config:** `/crm_extensions/file_storage/config.php`
|
||||||
|
|
||||||
|
### Template
|
||||||
|
- **Кнопка:** `/layouts/v7/modules/Documents/DetailViewActions.tpl` (строка 63-65)
|
||||||
|
|
||||||
|
## Как работает
|
||||||
|
|
||||||
|
### 1. Пользователь нажимает кнопку
|
||||||
|
```html
|
||||||
|
<button onclick="editInNextcloud('{$RECORD->getId()}', '{$RECORD->get('filename')}')" ...>
|
||||||
|
<i class="fa fa-cloud"></i> Nextcloud
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. JavaScript вызывает API
|
||||||
|
```javascript
|
||||||
|
function editInNextcloud(recordId, fileName) {
|
||||||
|
// Алиас для openNextcloudEditor
|
||||||
|
return openNextcloudEditor(recordId, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openNextcloudEditor(recordId, fileName) {
|
||||||
|
// 1. Тестовые запросы
|
||||||
|
// 2. Основной запрос к NcPrepareEdit.php
|
||||||
|
// 3. Получение fileId
|
||||||
|
// 4. Формирование URL
|
||||||
|
// 5. Открытие редактора
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. PHP получает fileId из Nextcloud
|
||||||
|
```php
|
||||||
|
// NcPrepareEdit.php
|
||||||
|
private function resolveNcFileId(int $recordId, string $fileName): ?int {
|
||||||
|
// WebDAV PROPFIND запрос к Nextcloud
|
||||||
|
// Возвращает fileId (уникальный ID файла в Nextcloud)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Формируются URL для редактора
|
||||||
|
```php
|
||||||
|
$urls = [
|
||||||
|
'collabora_id' => 'https://office.clientright.ru:8443/apps/richdocuments/index?fileId=123',
|
||||||
|
'onlyoffice_id' => 'https://office.clientright.ru:8443/apps/onlyoffice?fileId=123',
|
||||||
|
'files_manager' => 'https://office.clientright.ru:8443/apps/files/?dir=/path&openfile=file.docx'
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Открывается редактор Collabora
|
||||||
|
```javascript
|
||||||
|
window.open(editUrl, 'nextcloud_editor', 'width=1200,height=800');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Исправления от 21.10.2025
|
||||||
|
|
||||||
|
### Проблема
|
||||||
|
Кнопка открывала папку с документом, а не редактор.
|
||||||
|
|
||||||
|
### Причины
|
||||||
|
1. **Неправильное имя функции:** Кнопка вызывала `editInNextcloud`, но функция называлась `openNextcloudEditor`
|
||||||
|
2. **Неправильный URL:** `https://office.clientright.ru` без порта `:8443`
|
||||||
|
3. **Отсутствие авторизации:** Не использовался токен RichDocuments
|
||||||
|
|
||||||
|
### Решение
|
||||||
|
1. **Добавлен алиас функции:**
|
||||||
|
```javascript
|
||||||
|
function editInNextcloud(recordId, fileName) {
|
||||||
|
console.log('📝 editInNextcloud called (alias)');
|
||||||
|
return openNextcloudEditor(recordId, fileName);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Исправлен baseUrl в JS:**
|
||||||
|
```javascript
|
||||||
|
const baseUrl = 'https://office.clientright.ru:8443'; // было без :8443
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Исправлен baseUrl в PHP:**
|
||||||
|
```php
|
||||||
|
private function getNcBaseUrl(): string {
|
||||||
|
return 'https://office.clientright.ru:8443'; // было без :8443
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Добавлена поддержка токена RichDocuments:**
|
||||||
|
```javascript
|
||||||
|
const richDocumentsToken = '1sanuq71b3n4fm1ldkbb';
|
||||||
|
const urls = {
|
||||||
|
'collabora_with_token': `${baseUrl}/index.php/apps/richdocuments/index?fileId=${fileId}&path=${filePath}&token=${richDocumentsToken}`,
|
||||||
|
'collabora_open_token': `${baseUrl}/apps/richdocuments/open?path=${filePath}&token=${richDocumentsToken}`,
|
||||||
|
// ... fallback URLs
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Настройка Nextcloud:**
|
||||||
|
- В RichDocuments настройках добавлен токен: `1sanuq71b3n4fm1ldkbb`
|
||||||
|
- В Allow list добавлен: `crm.clientright.ru`
|
||||||
|
- **WOPI allow list установлен: `0.0.0.0/0`** (разрешены все IP)
|
||||||
|
- Включен доступ внешним приложениям
|
||||||
|
|
||||||
|
6. **Настроены правильные креды в .env:**
|
||||||
|
```
|
||||||
|
NEXTCLOUD_URL=https://office.clientright.ru:8443
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=office
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **Найден рабочий формат URL:**
|
||||||
|
```
|
||||||
|
https://office.clientright.ru:8443/apps/files/files/{fileId}?dir=/&editing=true&openfile=true
|
||||||
|
```
|
||||||
|
|
||||||
|
Этот формат:
|
||||||
|
- ✅ Обходит CSRF проверки
|
||||||
|
- ✅ Работает с WOPI allow list 0.0.0.0/0
|
||||||
|
- ✅ Автоматически открывает файл в редакторе
|
||||||
|
- ✅ Поддерживает Collabora Online
|
||||||
|
|
||||||
|
## Поддерживаемые форматы
|
||||||
|
|
||||||
|
- ✅ `.docx` - Word документы
|
||||||
|
- ✅ `.xlsx` - Excel таблицы
|
||||||
|
- ✅ `.pptx` - PowerPoint презентации
|
||||||
|
- ✅ `.odt` - OpenDocument Text
|
||||||
|
- ✅ `.ods` - OpenDocument Spreadsheet
|
||||||
|
- ✅ `.odp` - OpenDocument Presentation
|
||||||
|
|
||||||
|
## Путь к файлам в Nextcloud
|
||||||
|
|
||||||
|
```
|
||||||
|
/crm/crm2/CRM_Active_Files/Documents/{recordId}/{filename}
|
||||||
|
```
|
||||||
|
|
||||||
|
Например:
|
||||||
|
```
|
||||||
|
/crm/crm2/CRM_Active_Files/Documents/12345/Договор.docx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Отладка
|
||||||
|
|
||||||
|
### Включение логов в браузере
|
||||||
|
1. Откройте консоль (F12)
|
||||||
|
2. Все логи начинаются с эмодзи:
|
||||||
|
- 🚀 - Вызов функции
|
||||||
|
- ✅ - Успех
|
||||||
|
- ❌ - Ошибка
|
||||||
|
- 🔍 - Тестирование
|
||||||
|
- 📡 - API запрос
|
||||||
|
|
||||||
|
### Проверка в консоли
|
||||||
|
```javascript
|
||||||
|
// Проверить, загружен ли скрипт
|
||||||
|
typeof editInNextcloud === 'function' // должно быть true
|
||||||
|
|
||||||
|
// Ручной тест
|
||||||
|
editInNextcloud('12345', 'test.docx')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Проверка API
|
||||||
|
```bash
|
||||||
|
# Прямой запрос к API
|
||||||
|
curl 'https://crm.clientright.ru/index.php?module=Documents&action=NcPrepareEdit&record=12345&fileName=test.docx'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Альтернативные способы открытия
|
||||||
|
|
||||||
|
JavaScript автоматически создает несколько URL:
|
||||||
|
1. **collabora_editor** (рекомендуется) - открытие в Collabora по fileId
|
||||||
|
2. **onlyoffice_editor** - открытие в OnlyOffice
|
||||||
|
3. **files_with_open** - файловый менеджер с автооткрытием
|
||||||
|
4. **files_manager** - просто файловый менеджер
|
||||||
|
5. **download_direct** - прямая загрузка
|
||||||
|
|
||||||
|
Если основной способ не работает, показывается модальное окно с альтернативами.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
- ✅ Nextcloud 31.0.9.1
|
||||||
|
- ✅ Collabora Online 25.04.5.3
|
||||||
|
- ✅ WebDAV включен
|
||||||
|
- ✅ Файл существует в Nextcloud
|
||||||
|
|
||||||
|
### CRM
|
||||||
|
- ✅ Документ имеет поддерживаемое расширение
|
||||||
|
- ✅ Файл загружен в CRM
|
||||||
|
- ✅ JavaScript не заблокирован
|
||||||
|
- ✅ Всплывающие окна разрешены
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- **WebDAV аутентификация:** Используются креды из `config.php`
|
||||||
|
- **HTTPS:** Все запросы через SSL
|
||||||
|
- **fileId:** Уникальный идентификатор файла в Nextcloud
|
||||||
|
- **Права доступа:** Проверяются через vtiger CRM permissions
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
|
||||||
|
### Шаг 1: Проверьте, что кнопка есть
|
||||||
|
1. Откройте карточку документа в CRM
|
||||||
|
2. Должна быть голубая кнопка с облаком "Nextcloud"
|
||||||
|
|
||||||
|
### Шаг 2: Нажмите кнопку
|
||||||
|
1. Откройте консоль (F12)
|
||||||
|
2. Нажмите кнопку "Nextcloud"
|
||||||
|
3. Проверьте логи в консоли
|
||||||
|
|
||||||
|
### Шаг 3: Проверьте результат
|
||||||
|
**Успех:** Открылось новое окно с редактором Collabora
|
||||||
|
**Ошибка:** Показано модальное окно с альтернативными URL
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Кнопка не появляется
|
||||||
|
- Проверьте, что модуль = Documents
|
||||||
|
- Проверьте, что есть поле `filename`
|
||||||
|
|
||||||
|
### Кнопка не работает
|
||||||
|
- Откройте консоль (F12) и посмотрите ошибки
|
||||||
|
- Проверьте, что JS файл загружен: `view-source:https://crm.clientright.ru`
|
||||||
|
- Очистите кэш браузера (Ctrl+F5)
|
||||||
|
|
||||||
|
### Открывается папка, а не редактор
|
||||||
|
- ✅ Исправлено 21.10.2025
|
||||||
|
- Проверьте, что `baseUrl = 'https://office.clientright.ru:8443'`
|
||||||
|
|
||||||
|
### Ошибка "File not found"
|
||||||
|
- Файл не загружен в Nextcloud
|
||||||
|
- Проверьте путь: `/crm/crm2/CRM_Active_Files/Documents/{recordId}/`
|
||||||
|
|
||||||
|
### Ошибка "Unsupported format"
|
||||||
|
- Файл имеет неподдерживаемое расширение
|
||||||
|
- Поддерживаются: docx, xlsx, pptx, odt, ods, odp
|
||||||
|
|
||||||
|
## Будущие улучшения
|
||||||
|
|
||||||
|
- [ ] Автосинхронизация после редактирования
|
||||||
|
- [ ] Поддержка PDF (просмотр)
|
||||||
|
- [ ] История изменений
|
||||||
|
- [ ] Комментарии в документах
|
||||||
|
- [ ] Совместное редактирование с уведомлениями
|
||||||
|
|
||||||
178
crm_extensions/docs/NEXTCLOUD_SSL_SETUP.md
Normal file
178
crm_extensions/docs/NEXTCLOUD_SSL_SETUP.md
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
# Настройка SSL для Nextcloud
|
||||||
|
|
||||||
|
**Дата:** 21 октября 2025
|
||||||
|
**Домен:** office.clientright.ru
|
||||||
|
**Порт HTTPS:** 8443 (нестандартный, т.к. 443 занят основным CRM)
|
||||||
|
|
||||||
|
## Что было сделано
|
||||||
|
|
||||||
|
### 1. Обновлён nginx конфигурация
|
||||||
|
- **Файл:** `/etc/nginx/fastpanel2-sites/office/office.clientright.ru.ssl.conf`
|
||||||
|
- **Изменения:**
|
||||||
|
- Изменён порт проксирования с `32770` на `8082` (новый контейнер `nextcloud-fresh`)
|
||||||
|
- Добавлены заголовки `X-Forwarded-Host` и `X-Forwarded-Port` для правильной работы HTTPS прокси
|
||||||
|
- Включён `proxy_buffering off` для лучшей производительности
|
||||||
|
|
||||||
|
### 2. Настроен config.php Nextcloud
|
||||||
|
|
||||||
|
**Файл в контейнере:** `/var/www/html/config/config.php`
|
||||||
|
|
||||||
|
**Добавлены параметры:**
|
||||||
|
|
||||||
|
```php
|
||||||
|
// HTTPS конфигурация
|
||||||
|
'overwrite.cli.url' => 'https://office.clientright.ru:8443',
|
||||||
|
'overwritehost' => 'office.clientright.ru:8443',
|
||||||
|
'overwriteprotocol' => 'https',
|
||||||
|
|
||||||
|
// Доверенные прокси
|
||||||
|
'trusted_proxies' => array(
|
||||||
|
0 => '127.0.0.1',
|
||||||
|
1 => '147.45.146.17',
|
||||||
|
),
|
||||||
|
'forwarded_for_headers' => array(
|
||||||
|
0 => 'X-Forwarded-For',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Локальное кэширование (без Redis, т.к. контейнеры в разных сетях)
|
||||||
|
// Для подключения Redis нужно объединить контейнеры в одну Docker сеть
|
||||||
|
|
||||||
|
// Дополнительные настройки
|
||||||
|
'default_phone_region' => 'RU',
|
||||||
|
'maintenance_window_start' => 3,
|
||||||
|
|
||||||
|
// Доверенные домены
|
||||||
|
'trusted_domains' => array(
|
||||||
|
0 => 'localhost',
|
||||||
|
1 => 'office.clientright.ru',
|
||||||
|
2 => 'office.clientright.ru:8443',
|
||||||
|
3 => 'office.klientprav.tech',
|
||||||
|
4 => 'office.klientprav.tech:8443',
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Настроен Redis для ускорения работы
|
||||||
|
|
||||||
|
**Проблема:** Контейнеры `nextcloud-fresh` и `nextcloud-redis` изначально находились в разных Docker сетях.
|
||||||
|
|
||||||
|
**Решение:** Подключили Redis к той же сети и настроили кэширование:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Подключение Redis к сети Nextcloud
|
||||||
|
docker network connect root_nextcloud-network nextcloud-redis
|
||||||
|
|
||||||
|
# Настройка кэширования
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set memcache.distributed --value="\\OC\\Memcache\\Redis"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set memcache.locking --value="\\OC\\Memcache\\Redis"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set redis host --value="nextcloud-redis"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set redis port --value=6379 --type=integer
|
||||||
|
|
||||||
|
# Перезапуск Nextcloud
|
||||||
|
docker restart nextcloud-fresh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
- ✅ Redis 7.4.6 работает корректно
|
||||||
|
- ✅ 7 активных подключений
|
||||||
|
- ✅ Используется для распределенного кеша и блокировок файлов
|
||||||
|
- ✅ APCu используется для локального кеша
|
||||||
|
- 🔥 Значительное ускорение работы Nextcloud
|
||||||
|
|
||||||
|
### 4. Выполнены команды оптимизации
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Добавлены отсутствующие индексы для производительности
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ db:add-missing-indices
|
||||||
|
|
||||||
|
# Выполнена миграция mimetype и другие исправления
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ maintenance:repair --include-expensive
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Перезапущены службы
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Перезагрузка nginx
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
|
||||||
|
# Перезапуск Nextcloud
|
||||||
|
docker restart nextcloud-fresh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Текущее состояние
|
||||||
|
|
||||||
|
✅ **HTTPS работает корректно** на `https://office.clientright.ru:8443`
|
||||||
|
✅ **SSL сертификат:** Let's Encrypt (действителен до 30 декабря 2025)
|
||||||
|
✅ **Nextcloud понимает**, что работает через HTTPS прокси
|
||||||
|
✅ **Redis настроен** для кэширования и блокировок файлов (версия 7.4.6)
|
||||||
|
✅ **APCu настроен** для локального кэширования
|
||||||
|
✅ **Индексы БД добавлены** для производительности
|
||||||
|
✅ **HSTS включён** (max-age=63072000)
|
||||||
|
✅ **Secure cookies** установлены
|
||||||
|
✅ **Collabora Online** работает корректно
|
||||||
|
|
||||||
|
## Исправление "Socket proxy error"
|
||||||
|
|
||||||
|
**Проблема:** После настройки HTTPS возникала ошибка "Socket proxy error: Timed out opening local socket: 99"
|
||||||
|
|
||||||
|
**Причина:** Встроенный CODE Server (richdocumentscode) не мог открыть локальный сокет на порту 9983
|
||||||
|
|
||||||
|
**Решение 1:** Переключились на внешний Collabora Online на порту 9980
|
||||||
|
|
||||||
|
**Решение 2:** Настроили правильные URL для внутреннего и внешнего подключения:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Внутренний URL для подключения Nextcloud → Collabora (через Docker сеть)
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set richdocuments wopi_url --value="http://collabora-fresh:9980"
|
||||||
|
|
||||||
|
# Публичный URL для подключения Браузер → Collabora (через nginx)
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:delete richdocuments public_wopi_url
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set richdocuments public_wopi_url --value="https://office.clientright.ru:8443"
|
||||||
|
|
||||||
|
# Отключение проверки сертификата для внутреннего подключения
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set richdocuments disable_certificate_verification --value="yes"
|
||||||
|
|
||||||
|
# Перезапуск Nextcloud
|
||||||
|
docker restart nextcloud-fresh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
- ✅ Collabora Online Development Edition 25.04.5.3 обнаружен
|
||||||
|
- ✅ Поддержка: doc, docx, odt, xls, xlsx, ppt, pptx и др.
|
||||||
|
- ✅ Редактирование документов работает
|
||||||
|
|
||||||
|
## Оставшиеся предупреждения
|
||||||
|
|
||||||
|
⚠️ **Высокопроизводительный сервер для Nextcloud Talk** - требуется настройка отдельно, если планируется использовать видеозвонки с более чем 2-3 участниками
|
||||||
|
|
||||||
|
⚠️ **Настройка почтового сервера** - можно настроить в админке Nextcloud для отправки уведомлений
|
||||||
|
|
||||||
|
⚠️ **Версия MariaDB 12.0.2** - рекомендуется 10.6-11.4, но текущая версия работает стабильно
|
||||||
|
|
||||||
|
## Доступ к Nextcloud
|
||||||
|
|
||||||
|
- **HTTP:** http://office.clientright.ru → автоматический редирект на HTTPS
|
||||||
|
- **HTTPS:** https://office.clientright.ru:8443 ✅
|
||||||
|
- **Альтернативный домен:** office.klientprav.tech:8443
|
||||||
|
|
||||||
|
## Docker контейнеры
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker ps | grep nextcloud
|
||||||
|
# nextcloud-fresh - основной контейнер Nextcloud на порту 8082
|
||||||
|
# nextcloud-db-fresh - MariaDB база данных
|
||||||
|
# nextcloud-redis - Redis для кэширования
|
||||||
|
```
|
||||||
|
|
||||||
|
## Примечание о порте 443
|
||||||
|
|
||||||
|
Стандартный HTTPS порт 443 занят основным CRM сайтом (`crm.clientright.ru`).
|
||||||
|
|
||||||
|
Если в будущем понадобится перенести Nextcloud на порт 443, нужно будет настроить виртуальные хосты nginx для разделения трафика по `server_name`.
|
||||||
|
|
||||||
|
## Резервная копия
|
||||||
|
|
||||||
|
Исходные файлы сохранены:
|
||||||
|
- `/tmp/nextcloud_config_fixed.php` - новый config.php
|
||||||
|
- `/etc/nginx/fastpanel2-sites/office.clientright.ru.ssl.conf.backup` - старый nginx конфиг
|
||||||
|
|
||||||
86
crm_extensions/file_storage/api/open_file.php
Normal file
86
crm_extensions/file_storage/api/open_file.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Простой редирект на файл в Nextcloud БЕЗ CSRF проверок
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Получаем параметры
|
||||||
|
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
|
||||||
|
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
|
||||||
|
|
||||||
|
// Если fileName содержит полный URL, извлекаем только имя файла
|
||||||
|
if (strpos($fileName, 'http') === 0) {
|
||||||
|
$fileName = basename($fileName);
|
||||||
|
error_log("Nextcloud Editor: Извлечено имя файла из URL: {$fileName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Настройки Nextcloud
|
||||||
|
$nextcloudUrl = 'https://office.clientright.ru:8443';
|
||||||
|
$username = 'admin';
|
||||||
|
$password = 'office';
|
||||||
|
|
||||||
|
// Путь к файлу в Nextcloud (относительно папки пользователя admin)
|
||||||
|
// Предполагаем, что файлы хранятся по пути: crm/crm2/CRM_Active_Files/Documents/{recordId}/{fileName}
|
||||||
|
$nextcloudFilePath = "crm/crm2/CRM_Active_Files/Documents/{$recordId}/" . urlencode($fileName);
|
||||||
|
|
||||||
|
$fileId = null;
|
||||||
|
|
||||||
|
// Попытка получить fileId через WebDAV PROPFIND
|
||||||
|
error_log("Nextcloud Editor: Попытка получить fileId для файла: {$nextcloudFilePath} через WebDAV");
|
||||||
|
|
||||||
|
// XML запрос для получения fileid
|
||||||
|
$xmlRequest = '<?xml version="1.0"?>
|
||||||
|
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||||
|
<d:prop>
|
||||||
|
<oc:fileid/>
|
||||||
|
</d:prop>
|
||||||
|
</d:propfind>';
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $nextcloudUrl . '/remote.php/dav/files/' . $username . '/' . $nextcloudFilePath);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PROPFIND');
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Depth: 0',
|
||||||
|
'Content-Type: application/xml'
|
||||||
|
]);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curlError = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false) {
|
||||||
|
error_log("Nextcloud Editor: Ошибка cURL при запросе WebDAV: " . $curlError);
|
||||||
|
} else {
|
||||||
|
error_log("Nextcloud Editor: WebDAV Response (HTTP {$httpCode}): " . substr($response, 0, 500));
|
||||||
|
|
||||||
|
if ($httpCode === 207 && $response) { // 207 = Multi-Status для PROPFIND
|
||||||
|
// Простой regex для извлечения fileid
|
||||||
|
if (preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches)) {
|
||||||
|
$fileId = $matches[1];
|
||||||
|
error_log("Nextcloud Editor: fileId получен через WebDAV regex: " . $fileId);
|
||||||
|
} else {
|
||||||
|
error_log("Nextcloud Editor: fileid не найден в XML ответе");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log("Nextcloud Editor: WebDAV запрос неуспешен. HTTP Code: {$httpCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$fileId) {
|
||||||
|
die('❌ Ошибка: Не удалось получить fileId для файла ' . $fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формируем URL для Nextcloud
|
||||||
|
// РАБОЧИЙ ФОРМАТ - редирект на файл с автооткрытием редактора!
|
||||||
|
$redirectUrl = $nextcloudUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=true&openfile=true';
|
||||||
|
|
||||||
|
// Логирование
|
||||||
|
error_log("Nextcloud Editor: Redirect to $redirectUrl for file $fileName (ID: $fileId)");
|
||||||
|
|
||||||
|
// Делаем редирект
|
||||||
|
header('Location: ' . $redirectUrl);
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
@@ -76,21 +76,28 @@ function createEditUrls(baseEditUrl, recordId, fileName, fileId = 662) {
|
|||||||
console.log('🔗 Creating edit URLs in JavaScript...', { fileId, fileName });
|
console.log('🔗 Creating edit URLs in JavaScript...', { fileId, fileName });
|
||||||
|
|
||||||
// Извлекаем базовый URL из базовой ссылки
|
// Извлекаем базовый URL из базовой ссылки
|
||||||
const baseUrl = 'https://office.clientright.ru';
|
const baseUrl = 'https://office.clientright.ru:8443';
|
||||||
const encodedFileName = encodeURIComponent(fileName);
|
const encodedFileName = encodeURIComponent(fileName);
|
||||||
const filePath = `/crm/crm2/CRM_Active_Files/Documents/${recordId}/${encodedFileName}`;
|
const filePath = `/crm/crm2/CRM_Active_Files/Documents/${recordId}/${encodedFileName}`;
|
||||||
|
|
||||||
|
// Токен для RichDocuments (из настроек Nextcloud)
|
||||||
|
const richDocumentsToken = '1sanuq71b3n4fm1ldkbb';
|
||||||
|
|
||||||
const urls = {
|
const urls = {
|
||||||
'correct_path': fileId ? `${baseUrl}/apps/files/files/${fileId}?dir=/crm/crm2/CRM_Active_Files/Documents/${recordId}&openfile=true` : `${baseUrl}/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/${recordId}&openfile=${encodedFileName}`,
|
// ЛУЧШИЙ СПОСОБ! - редирект через нашу промежуточную страницу (БЕЗ CSRF!)
|
||||||
'collabora_path': `${baseUrl}/apps/richdocuments/open?path=${filePath}`,
|
'redirect_to_nextcloud': fileId ? `/crm_extensions/file_storage/api/open_file.php?fileId=${fileId}&fileName=${encodedFileName}&recordId=${recordId}` : null,
|
||||||
'onlyoffice_path': `${baseUrl}/apps/onlyoffice/open?path=${filePath}`,
|
// РАБОЧИЙ СПОСОБ! - прямая ссылка на Nextcloud
|
||||||
'files_manager': `${baseUrl}/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/${recordId}&openfile=${encodedFileName}`,
|
'files_editing_auto': fileId ? `${baseUrl}/apps/files/files/${fileId}?dir=/&editing=true&openfile=true` : null,
|
||||||
'collabora_id': fileId ? `${baseUrl}/apps/richdocuments/index?fileId=${fileId}` : null,
|
// Вариант без автоматического редактирования
|
||||||
'onlyoffice_id': fileId ? `${baseUrl}/apps/onlyoffice?fileId=${fileId}` : null,
|
'files_editing': fileId ? `${baseUrl}/apps/files/files/${fileId}?dir=/&editing=false&openfile=true` : null,
|
||||||
'files_app': `${baseUrl}/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/${recordId}&openfile=${encodedFileName}&action=edit`,
|
// Collabora Editor
|
||||||
'simple_files': `${baseUrl}/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/${recordId}`,
|
'collabora_editor': fileId ? `${baseUrl}/index.php/apps/richdocuments/index?fileId=${fileId}` : null,
|
||||||
'download_direct': `${baseUrl}/remote.php/dav/files/admin${filePath}`,
|
// OnlyOffice Editor
|
||||||
'view_only': `${baseUrl}/apps/files/files/${fileId}?dir=/crm/crm2/CRM_Active_Files/Documents/${recordId}&openfile=true&view=1`
|
'onlyoffice_editor': fileId ? `${baseUrl}/apps/onlyoffice?fileId=${fileId}` : null,
|
||||||
|
// Прямое открытие файла
|
||||||
|
'files_direct': fileId ? `${baseUrl}/apps/files/files/${fileId}` : `${baseUrl}/apps/files/?dir=/&openfile=${encodedFileName}`,
|
||||||
|
// Файловый менеджер
|
||||||
|
'files_manager': `${baseUrl}/apps/files/?dir=/&openfile=${encodedFileName}`
|
||||||
};
|
};
|
||||||
|
|
||||||
// Убираем null значения
|
// Убираем null значения
|
||||||
@@ -102,7 +109,8 @@ function createEditUrls(baseEditUrl, recordId, fileName, fileId = 662) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
all: urls,
|
all: urls,
|
||||||
recommended: urls.correct_path
|
// РЕДИРЕКТ через нашу страницу - лучший способ (обходит CSRF)
|
||||||
|
recommended: urls.redirect_to_nextcloud || urls.files_editing_auto || urls.files_editing || urls.collabora_editor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,6 +451,12 @@ function openInNewWindow(editUrl) {
|
|||||||
console.log('Opened Nextcloud editor in new window');
|
console.log('Opened Nextcloud editor in new window');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Алиас функции для обратной совместимости
|
||||||
|
function editInNextcloud(recordId, fileName) {
|
||||||
|
console.log('📝 editInNextcloud called (alias)');
|
||||||
|
return openNextcloudEditor(recordId, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
// Автоматическое подключение при загрузке страницы
|
// Автоматическое подключение при загрузке страницы
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
console.log('Nextcloud Editor integration loaded');
|
console.log('Nextcloud Editor integration loaded');
|
||||||
|
|||||||
93
crm_extensions/simple_editor.php
Normal file
93
crm_extensions/simple_editor.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Простой редактор документов через внешние сервисы
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Получаем параметры
|
||||||
|
$recordId = $_GET['recordId'] ?? '';
|
||||||
|
$fileName = $_GET['fileName'] ?? '';
|
||||||
|
|
||||||
|
if (!$recordId || !$fileName) {
|
||||||
|
die('Не указаны параметры recordId и fileName');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Декодируем имя файла
|
||||||
|
$fileName = urldecode($fileName);
|
||||||
|
|
||||||
|
// Создаем различные варианты открытия
|
||||||
|
$baseUrl = 'https://office.clientright.ru';
|
||||||
|
$filePath = "/crm/crm2/CRM_Active_Files/Documents/{$recordId}/" . urlencode($fileName);
|
||||||
|
|
||||||
|
// Подключаем конфигурацию
|
||||||
|
$config = require_once __DIR__ . '/file_storage/config.php';
|
||||||
|
require_once __DIR__ . '/file_storage/NextcloudClient.php';
|
||||||
|
|
||||||
|
// Получаем fileId из Nextcloud
|
||||||
|
$nextcloudClient = new NextcloudClient($config['nextcloud']);
|
||||||
|
$remotePath = 'Documents/' . $recordId . '/' . $fileName;
|
||||||
|
$fileId = $nextcloudClient->getFileId($remotePath);
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Редактирование документа</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||||
|
.option { margin: 10px 0; padding: 10px; border: 1px solid #ddd; border-radius: 5px; }
|
||||||
|
.option h3 { margin-top: 0; color: #333; }
|
||||||
|
.btn { display: inline-block; padding: 10px 20px; background: #007cba; color: white; text-decoration: none; border-radius: 3px; margin: 5px; }
|
||||||
|
.btn:hover { background: #005a87; }
|
||||||
|
.btn-success { background: #28a745; }
|
||||||
|
.btn-success:hover { background: #1e7e34; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Редактирование документа: <?= htmlspecialchars($fileName) ?></h1>
|
||||||
|
|
||||||
|
<div class="option">
|
||||||
|
<h3>📝 Варианты редактирования:</h3>
|
||||||
|
|
||||||
|
<h4>1. Collabora Online (рекомендуется)</h4>
|
||||||
|
<a href="<?= $baseUrl ?>/apps/richdocuments/open?path=<?= urlencode($filePath) ?>" target="_blank" class="btn btn-success">
|
||||||
|
Открыть в Collabora
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h4>2. Только просмотр</h4>
|
||||||
|
<a href="<?= $baseUrl ?>/apps/files/files/<?= $fileId ?>?dir=/crm/crm2/CRM_Active_Files/Documents/<?= $recordId ?>&openfile=true" target="_blank" class="btn">
|
||||||
|
Просмотр в Nextcloud
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h4>3. Скачать и редактировать локально</h4>
|
||||||
|
<a href="<?= $baseUrl ?>/remote.php/dav/files/admin<?= $filePath ?>" target="_blank" class="btn">
|
||||||
|
Скачать файл
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h4>4. Google Docs (если файл публично доступен)</h4>
|
||||||
|
<a href="https://docs.google.com/document/d/1/edit?usp=sharing" target="_blank" class="btn">
|
||||||
|
Открыть в Google Docs
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h4>5. Microsoft Office Online</h4>
|
||||||
|
<a href="https://office.com" target="_blank" class="btn">
|
||||||
|
Открыть в Office Online
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="option">
|
||||||
|
<h3>ℹ️ Информация о файле:</h3>
|
||||||
|
<p><strong>Файл:</strong> <?= htmlspecialchars($fileName) ?></p>
|
||||||
|
<p><strong>ID записи:</strong> <?= htmlspecialchars($recordId) ?></p>
|
||||||
|
<p><strong>File ID:</strong> <?= $fileId ?: 'Не найден' ?></p>
|
||||||
|
<p><strong>Путь:</strong> <?= htmlspecialchars($filePath) ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Автоматически открываем Collabora через 2 секунды
|
||||||
|
setTimeout(function() {
|
||||||
|
window.open('<?= $baseUrl ?>/apps/richdocuments/open?path=<?= urlencode($filePath) ?>', '_blank');
|
||||||
|
}, 2000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,60 +1,442 @@
|
|||||||
/**
|
/**
|
||||||
* Nextcloud Editor Integration
|
* Nextcloud Editor Integration JavaScript
|
||||||
* Функция для редактирования документов в Nextcloud
|
* JavaScript для интеграции редактора документов Nextcloud
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function editInNextcloud(recordId, fileName) {
|
/**
|
||||||
console.log('Opening file in Nextcloud:', recordId, fileName);
|
* Открытие редактора Nextcloud для документа
|
||||||
|
*/
|
||||||
|
function openNextcloudEditor(recordId, fileName) {
|
||||||
|
console.log('🚀 NEXTCLOUD EDITOR: Function called!', recordId, fileName);
|
||||||
|
|
||||||
|
// ПРОСТОЕ РЕШЕНИЕ - используем промежуточную страницу для редиректа!
|
||||||
|
const redirectUrl = `/crm_extensions/file_storage/api/open_file.php?recordId=${recordId}&fileName=${encodeURIComponent(fileName)}`;
|
||||||
|
|
||||||
// Проверяем расширение
|
console.log('🎯 Opening editor via redirect:', redirectUrl);
|
||||||
const ext = fileName.split('.').pop().toLowerCase();
|
|
||||||
if (!['docx', 'xlsx', 'pptx'].includes(ext)) {
|
// Открываем редактор в новом окне через промежуточную страницу
|
||||||
alert('Файл ' + fileName + ' не поддерживается для редактирования. Поддерживаются: docx, xlsx, pptx');
|
const win = window.open(redirectUrl, 'nextcloud_editor', 'width=1200,height=800,scrollbars=yes,resizable=yes');
|
||||||
return;
|
|
||||||
|
if (win) {
|
||||||
|
console.log('✅ Editor opened successfully');
|
||||||
|
alert('✅ Редактор открыт! Файл: ' + fileName);
|
||||||
|
} else {
|
||||||
|
console.log('❌ Failed to open editor window - popup blocked');
|
||||||
|
alert('❌ Не удалось открыть редактор. Проверьте блокировку всплывающих окон.');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSimpleAPI(recordId, fileName) {
|
||||||
|
console.log('🧪 Testing simple API...', recordId, fileName);
|
||||||
|
|
||||||
// Отправляем запрос к нашему API
|
// Пропускаем простой API и сразу идем к основному
|
||||||
const apiUrl = `crm_extensions/nextcloud_api.php?record=${encodeURIComponent(recordId)}&fileName=${encodeURIComponent(fileName)}`;
|
console.log('🎯 Skipping simple API, going to main API...');
|
||||||
fetch(apiUrl, {
|
callMainAPI(recordId, fileName);
|
||||||
method: 'GET'
|
}
|
||||||
})
|
|
||||||
.then(response => {
|
function createEditUrls(baseEditUrl, recordId, fileName, fileId = 662) {
|
||||||
console.log('Response status:', response.status);
|
console.log('🔗 Creating edit URLs in JavaScript...', { fileId, fileName });
|
||||||
return response.json();
|
|
||||||
})
|
// Извлекаем базовый URL из базовой ссылки
|
||||||
.then(json => {
|
const baseUrl = 'https://office.clientright.ru:8443';
|
||||||
console.log('JSON response:', json);
|
const encodedFileName = encodeURIComponent(fileName);
|
||||||
if (json.success && json.data && json.data.urls) {
|
const filePath = `/crm/crm2/CRM_Active_Files/Documents/${recordId}/${encodedFileName}`;
|
||||||
// Сначала пробуем файловый менеджер, потом прямой редактор
|
|
||||||
const filesManagerUrl = json.data.urls.files_manager;
|
// Токен для RichDocuments (из настроек Nextcloud)
|
||||||
const collaboraUrl = json.data.urls.collabora_id;
|
const richDocumentsToken = '1sanuq71b3n4fm1ldkbb';
|
||||||
const onlyofficeUrl = json.data.urls.onlyoffice_id;
|
|
||||||
|
const urls = {
|
||||||
if (filesManagerUrl) {
|
// ЛУЧШИЙ СПОСОБ! - редирект через нашу промежуточную страницу (БЕЗ CSRF!)
|
||||||
console.log('Opening files manager:', filesManagerUrl);
|
'redirect_to_nextcloud': fileId ? `/crm_extensions/file_storage/api/open_file.php?fileId=${fileId}&fileName=${encodedFileName}&recordId=${recordId}` : null,
|
||||||
window.open(filesManagerUrl, '_blank');
|
// РАБОЧИЙ СПОСОБ! - прямая ссылка на Nextcloud
|
||||||
} else if (collaboraUrl) {
|
'files_editing_auto': fileId ? `${baseUrl}/apps/files/files/${fileId}?dir=/&editing=true&openfile=true` : null,
|
||||||
console.log('Opening Collabora:', collaboraUrl);
|
// Вариант без автоматического редактирования
|
||||||
window.open(collaboraUrl, '_blank');
|
'files_editing': fileId ? `${baseUrl}/apps/files/files/${fileId}?dir=/&editing=false&openfile=true` : null,
|
||||||
} else if (onlyofficeUrl) {
|
// Collabora Editor
|
||||||
console.log('Opening OnlyOffice:', onlyofficeUrl);
|
'collabora_editor': fileId ? `${baseUrl}/index.php/apps/richdocuments/index?fileId=${fileId}` : null,
|
||||||
window.open(onlyofficeUrl, '_blank');
|
// OnlyOffice Editor
|
||||||
} else {
|
'onlyoffice_editor': fileId ? `${baseUrl}/apps/onlyoffice?fileId=${fileId}` : null,
|
||||||
console.error('No valid URLs found');
|
// Прямое открытие файла
|
||||||
alert('Ошибка: Не удалось получить URL для редактирования');
|
'files_direct': fileId ? `${baseUrl}/apps/files/files/${fileId}` : `${baseUrl}/apps/files/?dir=/&openfile=${encodedFileName}`,
|
||||||
}
|
// Файловый менеджер
|
||||||
} else {
|
'files_manager': `${baseUrl}/apps/files/?dir=/&openfile=${encodedFileName}`
|
||||||
console.error('Invalid response structure:', json);
|
};
|
||||||
alert('Ошибка: ' + (json.error || 'Не удалось получить URL для редактирования. Проверьте консоль для деталей.'));
|
|
||||||
|
// Убираем null значения
|
||||||
|
Object.keys(urls).forEach(key => {
|
||||||
|
if (urls[key] === null) {
|
||||||
|
delete urls[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
all: urls,
|
||||||
|
// РЕДИРЕКТ через нашу страницу - лучший способ (обходит CSRF)
|
||||||
|
recommended: urls.redirect_to_nextcloud || urls.files_editing_auto || urls.files_editing || urls.collabora_editor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEditUrls(recordId, fileName, simpleData) {
|
||||||
|
console.log('🔗 Getting edit URLs...');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/crm_extensions/file_storage/api/get_edit_urls.php',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
record: recordId,
|
||||||
|
fileName: fileName
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
console.log('✅ Edit URLs received:', response);
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
// Пробуем открыть рекомендуемый URL
|
||||||
|
const recommendedUrl = response.data.urls[response.data.recommended];
|
||||||
|
console.log('🎯 Trying recommended URL:', recommendedUrl);
|
||||||
|
|
||||||
|
openEditor(recommendedUrl, {
|
||||||
|
...simpleData,
|
||||||
|
urls: response.data.urls,
|
||||||
|
recommended: response.data.recommended
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Если не получилось, используем простой API
|
||||||
|
openEditor(simpleData.edit_url, simpleData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('❌ Failed to get edit URLs:', error);
|
||||||
|
// Если не получилось, используем простой API
|
||||||
|
openEditor(simpleData.edit_url, simpleData);
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
alert('Ошибка: ' + error.message);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Делаем функцию глобальной для доступа из шаблонов
|
function callMainAPI(recordId, fileName) {
|
||||||
window.editInNextcloud = editInNextcloud;
|
console.log('🎯 Calling main API...', recordId, fileName);
|
||||||
|
|
||||||
|
// Показываем прогресс
|
||||||
|
if (typeof app !== 'undefined' && app.helper && app.helper.showProgress) {
|
||||||
|
app.helper.showProgress({
|
||||||
|
message: 'Подготовка файла к редактированию...'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вызываем ПРАВИЛЬНЫЙ API для подготовки файла
|
||||||
|
$.ajax({
|
||||||
|
url: '/index.php?module=Documents&action=NcPrepareEdit',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
record: recordId,
|
||||||
|
fileName: fileName
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
console.log('📡 API Response:', response);
|
||||||
|
|
||||||
|
// Скрываем прогресс
|
||||||
|
if (typeof app !== 'undefined' && app.helper && app.helper.hideProgress) {
|
||||||
|
app.helper.hideProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
console.log('✅ File prepared successfully');
|
||||||
|
|
||||||
|
// Открываем редактор
|
||||||
|
openEditor(response.data.edit_url, response.data);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.error('❌ API Error:', response.error);
|
||||||
|
showError('Ошибка подготовки файла: ' + response.error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('❌ AJAX Error:', error);
|
||||||
|
console.error('❌ Status:', status);
|
||||||
|
console.error('❌ Response:', xhr.responseText);
|
||||||
|
console.error('❌ Status Code:', xhr.status);
|
||||||
|
|
||||||
|
// Скрываем прогресс
|
||||||
|
if (typeof app !== 'undefined' && app.helper && app.helper.hideProgress) {
|
||||||
|
app.helper.hideProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показываем подробную ошибку
|
||||||
|
let errorMessage = 'Ошибка подключения к серверу: ' + error;
|
||||||
|
if (xhr.responseText) {
|
||||||
|
errorMessage += '\n\nОтвет сервера:\n' + xhr.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
showError(errorMessage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для открытия редактора
|
||||||
|
function openEditor(editUrl, fileData) {
|
||||||
|
console.log('🎯 Opening editor with URL:', editUrl);
|
||||||
|
console.log('📋 All available URLs:', fileData.urls);
|
||||||
|
|
||||||
|
// Открываем редактор в новом окне
|
||||||
|
var win = window.open(editUrl, 'nextcloud_editor', 'width=1200,height=800,scrollbars=yes,resizable=yes');
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
console.log('✅ Editor opened successfully');
|
||||||
|
|
||||||
|
// Показываем уведомление об успехе
|
||||||
|
if (typeof app !== 'undefined' && app.helper && app.helper.showSuccessNotification) {
|
||||||
|
app.helper.showSuccessNotification({
|
||||||
|
message: 'Редактор открыт! Файл: ' + fileData.file_name
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert('✅ Редактор открыт! Файл: ' + fileData.file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показываем информацию о файле
|
||||||
|
showFileInfo(fileData);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log('❌ Failed to open editor window - popup blocked or error');
|
||||||
|
console.log('📋 Showing modal with alternative URLs');
|
||||||
|
|
||||||
|
// Показываем модальное окно с альтернативными вариантами
|
||||||
|
showModalWithUrls(editUrl, fileData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для отображения информации о файле
|
||||||
|
function showFileInfo(fileData) {
|
||||||
|
// Проверяем, есть ли нужные поля в fileData
|
||||||
|
var location = 'Неизвестно';
|
||||||
|
var nextcloudPath = 'Не указан';
|
||||||
|
var status = 'Не указан';
|
||||||
|
|
||||||
|
if (fileData.file_location && fileData.file_location.type) {
|
||||||
|
location = fileData.file_location.type === 's3' ? 'S3 хранилище' : 'Локальное хранилище';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileData.nextcloud_path) {
|
||||||
|
nextcloudPath = fileData.nextcloud_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileData.message) {
|
||||||
|
status = fileData.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
var infoHtml = `
|
||||||
|
<div class="alert alert-info" style="margin: 10px 0;">
|
||||||
|
<h5><i class="fa fa-info-circle"></i> Информация о файле</h5>
|
||||||
|
<p><strong>Файл:</strong> ${fileData.file_name}</p>
|
||||||
|
<p><strong>Расположение:</strong> ${location}</p>
|
||||||
|
<p><strong>Путь в Nextcloud:</strong> ${nextcloudPath}</p>
|
||||||
|
<p><strong>Статус:</strong> ${status}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Если есть альтернативные URL, добавляем их
|
||||||
|
if (fileData.urls) {
|
||||||
|
infoHtml += `
|
||||||
|
<div class="alert alert-warning" style="margin: 10px 0;">
|
||||||
|
<h6><i class="fa fa-link"></i> Альтернативные способы открытия:</h6>
|
||||||
|
<div class="btn-group-vertical" style="width: 100%;">
|
||||||
|
`;
|
||||||
|
|
||||||
|
Object.keys(fileData.urls).forEach(function(key) {
|
||||||
|
const label = key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
||||||
|
const isRecommended = key === fileData.recommended;
|
||||||
|
const btnClass = isRecommended ? 'btn-success' : 'btn-default';
|
||||||
|
const icon = isRecommended ? 'fa-star' : 'fa-external-link';
|
||||||
|
|
||||||
|
infoHtml += `
|
||||||
|
<a href="${fileData.urls[key]}" target="_blank" class="btn ${btnClass} btn-sm" style="margin: 2px; text-align: left;">
|
||||||
|
<i class="fa ${icon}"></i> ${label}${isRecommended ? ' (рекомендуется)' : ''}
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
infoHtml += `
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем информацию в модальное окно или показываем отдельно
|
||||||
|
if ($('#nextcloudEditModal').length) {
|
||||||
|
$('#nextcloudEditModal .modal-body').prepend(infoHtml);
|
||||||
|
} else {
|
||||||
|
// Создаём временное уведомление
|
||||||
|
var notification = $('<div class="alert alert-info" style="position: fixed; top: 20px; right: 20px; z-index: 9999; max-width: 400px;">' + infoHtml + '</div>');
|
||||||
|
$('body').append(notification);
|
||||||
|
|
||||||
|
// Автоматически скрываем через 5 секунд
|
||||||
|
setTimeout(function() {
|
||||||
|
notification.fadeOut(function() {
|
||||||
|
notification.remove();
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для отображения ошибок
|
||||||
|
function showError(message) {
|
||||||
|
console.error('🚨 Error:', message);
|
||||||
|
|
||||||
|
if (typeof app !== 'undefined' && app.helper && app.helper.showErrorNotification) {
|
||||||
|
app.helper.showErrorNotification({
|
||||||
|
message: message
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert('❌ Ошибка: ' + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для показа модального окна с URL
|
||||||
|
function showModalWithUrls(editUrl, fileData) {
|
||||||
|
console.log('📋 Showing modal with URLs for file:', fileData.file_name);
|
||||||
|
|
||||||
|
if (fileData.urls) {
|
||||||
|
// Используем существующую функцию showEditOptions
|
||||||
|
showEditOptions(fileData.urls, fileData.file_name, fileData.record_id);
|
||||||
|
} else {
|
||||||
|
// Если нет альтернативных URL, показываем ошибку
|
||||||
|
showError('Не удалось открыть редактор. Попробуйте открыть файл вручную в Nextcloud.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Показ вариантов открытия файла
|
||||||
|
*/
|
||||||
|
function showEditOptions(urls, fileName, recordId) {
|
||||||
|
console.log('🎯 Showing edit options for:', fileName);
|
||||||
|
console.log('📋 Available URLs:', urls);
|
||||||
|
|
||||||
|
var buttonsHtml = '';
|
||||||
|
|
||||||
|
// Если urls - это объект (новый формат)
|
||||||
|
if (typeof urls === 'object' && !Array.isArray(urls)) {
|
||||||
|
Object.keys(urls).forEach(function(key, index) {
|
||||||
|
const label = key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
||||||
|
const url = urls[key];
|
||||||
|
const isRecommended = key === 'correct_path';
|
||||||
|
const btnClass = isRecommended ? 'btn-success' : 'btn-primary';
|
||||||
|
const icon = isRecommended ? 'fa-star' : 'fa-external-link';
|
||||||
|
|
||||||
|
buttonsHtml += `
|
||||||
|
<a href="${url}" target="_blank" class="btn ${btnClass} btn-sm" style="margin: 3px; display: block;">
|
||||||
|
<i class="fa ${icon}"></i> ${label}${isRecommended ? ' (рекомендуется)' : ''}
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Старый формат - массив URL
|
||||||
|
var labels = [
|
||||||
|
'С параметром openfile',
|
||||||
|
'С action=edit',
|
||||||
|
'С edit=true',
|
||||||
|
'Через RichDocuments',
|
||||||
|
'Через OnlyOffice'
|
||||||
|
];
|
||||||
|
|
||||||
|
var icons = ['fa-file', 'fa-edit', 'fa-pencil', 'fa-file-text', 'fa-file-word-o'];
|
||||||
|
var colors = ['btn-primary', 'btn-success', 'btn-info', 'btn-warning', 'btn-danger'];
|
||||||
|
|
||||||
|
urls.forEach(function(url, index) {
|
||||||
|
buttonsHtml += `
|
||||||
|
<a href="${url}" target="_blank" class="btn ${colors[index]} btn-sm" style="margin: 3px; display: block;">
|
||||||
|
<i class="fa ${icons[index]}"></i> ${labels[index]}
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var modalHtml = `
|
||||||
|
<div class="modal fade" id="nextcloudEditModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">
|
||||||
|
<i class="fa fa-edit"></i> Варианты открытия файла
|
||||||
|
</h4>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p><strong>Файл:</strong> ${fileName}</p>
|
||||||
|
<p>Попробуйте эти варианты для прямого открытия в редакторе:</p>
|
||||||
|
|
||||||
|
<div class="btn-group-vertical" style="width: 100%;">
|
||||||
|
${buttonsHtml}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-info" style="margin-top: 15px;">
|
||||||
|
<small><strong>💡 Совет:</strong> Попробуйте варианты сверху вниз. Один из них должен открыть файл сразу в редакторе!</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Удаляем старое модальное окно
|
||||||
|
$('#nextcloudEditModal').remove();
|
||||||
|
|
||||||
|
// Добавляем новое
|
||||||
|
$('body').append(modalHtml);
|
||||||
|
$('#nextcloudEditModal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Синхронизация изменений файла (заглушка)
|
||||||
|
*/
|
||||||
|
function syncFileChanges(recordId, fileName) {
|
||||||
|
console.log('Syncing file changes for:', recordId, fileName);
|
||||||
|
|
||||||
|
if (typeof app !== 'undefined' && app.helper && app.helper.showSuccessNotification) {
|
||||||
|
app.helper.showSuccessNotification({
|
||||||
|
message: 'Изменения синхронизированы!'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert('✅ Изменения синхронизированы!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Открытие редактора в новом окне
|
||||||
|
*/
|
||||||
|
function openInNewWindow(editUrl) {
|
||||||
|
window.open(editUrl, 'nextcloud_editor', 'width=1200,height=800,scrollbars=yes,resizable=yes,toolbar=no,location=no');
|
||||||
|
console.log('Opened Nextcloud editor in new window');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Алиас функции для обратной совместимости
|
||||||
|
function editInNextcloud(recordId, fileName) {
|
||||||
|
console.log('📝 editInNextcloud called (alias)');
|
||||||
|
return openNextcloudEditor(recordId, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Автоматическое подключение при загрузке страницы
|
||||||
|
$(document).ready(function() {
|
||||||
|
console.log('Nextcloud Editor integration loaded');
|
||||||
|
|
||||||
|
// Добавляем CSS стили для модального окна
|
||||||
|
if (!$('#nextcloud-editor-styles').length) {
|
||||||
|
$('<style id="nextcloud-editor-styles">')
|
||||||
|
.html(`
|
||||||
|
.nextcloud-edit-btn {
|
||||||
|
background: #0082c9;
|
||||||
|
border-color: #0082c9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nextcloud-edit-btn:hover {
|
||||||
|
background: #006ba6;
|
||||||
|
border-color: #006ba6;
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
.appendTo('head');
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -39,10 +39,22 @@ class Documents_NcPrepareEdit_Action extends Vtiger_Action_Controller {
|
|||||||
$baseUrl = $this->getNcBaseUrl();
|
$baseUrl = $this->getNcBaseUrl();
|
||||||
$dirPath = $this->getDirPath($recordId);
|
$dirPath = $this->getDirPath($recordId);
|
||||||
|
|
||||||
|
// Токен для RichDocuments (из настроек Nextcloud)
|
||||||
|
$richDocumentsToken = '1sanuq71b3n4fm1ldkbb';
|
||||||
|
|
||||||
$urls = [
|
$urls = [
|
||||||
'collabora_id' => $fileId ? $baseUrl . '/apps/richdocuments/index?fileId=' . rawurlencode((string)$fileId) : null,
|
// РАБОЧИЙ URL! Формат от пользователя - ПРИОРИТЕТ!
|
||||||
'onlyoffice_id' => $fileId ? $baseUrl . '/apps/onlyoffice?fileId=' . rawurlencode((string)$fileId) : null,
|
'files_editing_auto' => $fileId ? $baseUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=true&openfile=true' : null,
|
||||||
'files_manager' => $baseUrl . '/apps/files/?dir=' . rawurlencode($dirPath) . '&openfile=' . rawurlencode($fileName)
|
// Вариант без автоматического редактирования
|
||||||
|
'files_editing' => $fileId ? $baseUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=false&openfile=true' : null,
|
||||||
|
// Collabora Editor
|
||||||
|
'collabora_editor' => $fileId ? $baseUrl . '/index.php/apps/richdocuments/index?fileId=' . $fileId : null,
|
||||||
|
// OnlyOffice Editor
|
||||||
|
'onlyoffice_editor' => $fileId ? $baseUrl . '/apps/onlyoffice?fileId=' . $fileId : null,
|
||||||
|
// Прямое открытие файла
|
||||||
|
'files_direct' => $fileId ? $baseUrl . '/apps/files/files/' . $fileId : null,
|
||||||
|
// Файловый менеджер
|
||||||
|
'files_manager' => $baseUrl . '/apps/files/?dir=/&openfile=' . rawurlencode($fileName)
|
||||||
];
|
];
|
||||||
|
|
||||||
// Убираем null значения
|
// Убираем null значения
|
||||||
@@ -50,12 +62,18 @@ class Documents_NcPrepareEdit_Action extends Vtiger_Action_Controller {
|
|||||||
return $url !== null;
|
return $url !== null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Определяем основной URL для редактирования
|
||||||
|
$editUrl = isset($urls['files_editing_auto']) ? $urls['files_editing_auto'] :
|
||||||
|
(isset($urls['files_editing']) ? $urls['files_editing'] :
|
||||||
|
(isset($urls['files_direct']) ? $urls['files_direct'] : null));
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'data' => [
|
'data' => [
|
||||||
'record_id' => $recordId,
|
'record_id' => $recordId,
|
||||||
'file_name' => $fileName,
|
'file_name' => $fileName,
|
||||||
'file_id' => $fileId,
|
'file_id' => $fileId,
|
||||||
|
'edit_url' => $editUrl, // Основной URL
|
||||||
'urls' => $urls,
|
'urls' => $urls,
|
||||||
'message' => 'Файл подготовлен к редактированию'
|
'message' => 'Файл подготовлен к редактированию'
|
||||||
]
|
]
|
||||||
@@ -74,7 +92,7 @@ class Documents_NcPrepareEdit_Action extends Vtiger_Action_Controller {
|
|||||||
* Получение базового URL Nextcloud
|
* Получение базового URL Nextcloud
|
||||||
*/
|
*/
|
||||||
private function getNcBaseUrl(): string {
|
private function getNcBaseUrl(): string {
|
||||||
return 'https://office.clientright.ru';
|
return 'https://office.clientright.ru:8443';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
BIN
storage/2025/October/week3/395719_Опись 112030-merged.pdf
Normal file
BIN
storage/2025/October/week3/395719_Опись 112030-merged.pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
2025-10-20 10:30:10
|
2025-10-21 10:35:09
|
||||||
Reference in New Issue
Block a user