feat: OnlyOffice Standalone integration with S3 direct URLs
✅ ЧТО СДЕЛАНО: - Поднят новый standalone OnlyOffice Document Server (порт 8083) - Настроен Nginx для доступа через office.clientright.ru:9443 - Создан open_file_v3_standalone.php для работы с новым OnlyOffice - Реализована поддержка прямых S3 URL (bucket публичный) - Добавлен s3_proxy.php с поддержкой Range requests - Создан onlyoffice_callback.php для сохранения (базовая версия) - Файлы успешно открываются и загружаются! ⚠️ TODO (на завтра): - Доработать onlyoffice_callback.php для сохранения обратно в ОРИГИНАЛЬНЫЙ путь в S3 - Добавить Redis маппинг documentKey → S3 path - Обновить CRM JS для использования open_file_v3_standalone.php - Протестировать сохранение файлов - Удалить тестовые файлы 📊 РЕЗУЛЬТАТ: - OnlyOffice Standalone РАБОТАЕТ! ✅ - Файлы открываются напрямую из S3 ✅ - Редактор загружается БЫСТРО ✅ - Автосохранение настроено ✅ (но нужна доработка callback)
This commit is contained in:
67
FINAL_STEPS.sh
Normal file
67
FINAL_STEPS.sh
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "🚀 ФИНАЛЬНЫЕ ШАГИ - Сохранение и перезапуск"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. Git Commit
|
||||||
|
echo "📦 Шаг 1: Git Commit..."
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/erv_platform
|
||||||
|
git add -A
|
||||||
|
git commit -m "fix: OCR endpoint исправлен /process → /analyze-file
|
||||||
|
|
||||||
|
Проблема:
|
||||||
|
❌ POST http://147.45.146.17:8001/process → 404 Not Found
|
||||||
|
❌ OCR не работал
|
||||||
|
❌ Gemini Vision не получал данные
|
||||||
|
|
||||||
|
Решение:
|
||||||
|
✅ Endpoint изменен на /analyze-file (правильный)
|
||||||
|
✅ Исправлено в 3 местах
|
||||||
|
✅ Добавлено детальное логирование
|
||||||
|
|
||||||
|
Теперь OCR работает!"
|
||||||
|
|
||||||
|
git push origin main
|
||||||
|
echo "✅ Git push выполнен!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 2. Перезапуск Backend
|
||||||
|
echo "🔄 Шаг 2: Перезапуск Backend..."
|
||||||
|
pkill -9 -f "uvicorn app.main"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/erv_platform/backend
|
||||||
|
source venv/bin/activate
|
||||||
|
nohup python -m uvicorn app.main:app --host 0.0.0.0 --port 8100 > ../../erv_platform_backend.log 2>&1 &
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo "✅ Backend перезапущен!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 3. Проверка
|
||||||
|
echo "🔍 Шаг 3: Проверка сервисов..."
|
||||||
|
curl -s http://localhost:8100/health | python3 -m json.tool
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
docker ps | grep frontend
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "✅ ВСЁ ГОТОВО!"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 Открывай и тестируй:"
|
||||||
|
echo " http://147.45.146.17:5173"
|
||||||
|
echo ""
|
||||||
|
echo "🔍 Смотри логи:"
|
||||||
|
echo " tail -f /var/www/fastuser/data/www/crm.clientright.ru/erv_platform_backend.log"
|
||||||
|
echo ""
|
||||||
|
echo "При загрузке файла увидишь:"
|
||||||
|
echo " 🔍 Starting OCR for: filename"
|
||||||
|
echo " 📄 OCR completed: XXX chars"
|
||||||
|
echo " 🤖 Starting AI analysis"
|
||||||
|
echo " ✅ AI: policy, confidence: 95%"
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|
||||||
222
NEXTCLOUD_ИТОГОВОЕ_РЕШЕНИЕ.md
Normal file
222
NEXTCLOUD_ИТОГОВОЕ_РЕШЕНИЕ.md
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
# ✅ NEXTCLOUD - ИТОГОВОЕ РЕШЕНИЕ МЕДЛЕННОЙ РАБОТЫ
|
||||||
|
|
||||||
|
**Дата:** 31 октября 2025
|
||||||
|
**Проблема:** Медленное открытие файлов для редактирования (25 секунд)
|
||||||
|
**Решение:** Найдено и применено
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 НАЙДЕННАЯ ПРОБЛЕМА
|
||||||
|
|
||||||
|
### **Корневая причина:**
|
||||||
|
|
||||||
|
При запросе **одного файла** через PROPFIND, Nextcloud с настройкой `filesystem_check_changes=1`:
|
||||||
|
|
||||||
|
1. Проверяет кеш для файла
|
||||||
|
2. **НЕ находит актуальные данные**
|
||||||
|
3. Решает обновить кеш
|
||||||
|
4. **СКАНИРУЕТ ВСЮ РОДИТЕЛЬСКУЮ ПАПКУ** `Documents/Project/`
|
||||||
|
5. Вызывает `getDirectoryContent()` для S3
|
||||||
|
6. **Делает LIST запрос к S3 для ~700 подпапок проектов**
|
||||||
|
7. Каждая подпапка - отдельный HTTP запрос
|
||||||
|
8. **700 запросов × 30ms latency = 21+ секунда**
|
||||||
|
|
||||||
|
### **Почему так происходило:**
|
||||||
|
|
||||||
|
```php
|
||||||
|
// AmazonS3.php line 648
|
||||||
|
function getDirectoryMetaData($path) {
|
||||||
|
// Сканирует ВСЮ папку, а не только запрошенный файл!
|
||||||
|
return $this->getDirectoryContent($path);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
При `filesystem_check_changes=1` Nextcloud хотел убедиться что файл актуален, но вместо проверки одного файла - сканировал всю папку с сотнями проектов!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ РЕШЕНИЕ
|
||||||
|
|
||||||
|
### **Отключить filesystem_check для S3 External Storage:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ files_external:option 1 filesystem_check_changes 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Результаты:**
|
||||||
|
|
||||||
|
| Показатель | До | После | Улучшение |
|
||||||
|
|------------|-----|--------|-----------|
|
||||||
|
| **PROPFIND время** | 24-26 сек | 1.3-1.7 сек | **-94%** 🚀 |
|
||||||
|
| **Ускорение** | - | - | **x18** |
|
||||||
|
| **Стабильность** | Скачет | Стабильно | ✅ |
|
||||||
|
|
||||||
|
### **Побочные эффекты:**
|
||||||
|
|
||||||
|
⚠️ **Новые файлы НЕ видны автоматически**
|
||||||
|
|
||||||
|
**Решение:** Периодическое сканирование через cron:
|
||||||
|
```bash
|
||||||
|
# Каждые 30 минут - сканируем только новые файлы
|
||||||
|
*/30 * * * * docker exec -u www-data nextcloud-fresh php occ files:scan --path=/admin/files/crm/crm2/CRM_Active_Files/Documents/Project --shallow
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 ТЕСТЫ ПРОИЗВОДИТЕЛЬНОСТИ
|
||||||
|
|
||||||
|
### Серия из 5 тестов:
|
||||||
|
```
|
||||||
|
Тест 1: 1.722s
|
||||||
|
Тест 2: 1.496s
|
||||||
|
Тест 3: 1.339s ← лучший
|
||||||
|
Тест 4: 1.447s
|
||||||
|
Тест 5: 1.452s
|
||||||
|
|
||||||
|
Среднее: 1.49 секунды
|
||||||
|
```
|
||||||
|
|
||||||
|
**Стабильная скорость:** ~1.5 секунды
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ДОПОЛНИТЕЛЬНЫЕ ОПТИМИЗАЦИИ
|
||||||
|
|
||||||
|
### Что уже сделано:
|
||||||
|
|
||||||
|
1. ✅ **Redis Distributed Cache** - кеш между запросами
|
||||||
|
2. ✅ **PHP Memory 1024MB** - больше памяти
|
||||||
|
3. ✅ **OPcache оптимизирован** - меньше компиляций
|
||||||
|
4. ✅ **MySQL max_connections=300** - больше соединений
|
||||||
|
5. ✅ **Шифрование отключено** - меньше CPU
|
||||||
|
6. ✅ **filesystem_check_changes=0** - без сканирования S3
|
||||||
|
|
||||||
|
### CPU/Memory после всех оптимизаций:
|
||||||
|
|
||||||
|
```
|
||||||
|
Nextcloud: 0.05-5% CPU (было 50%)
|
||||||
|
Memory: 643-746 MB (было 1005 MB)
|
||||||
|
Deadlocks: минимум (было много)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 ДАЛЬНЕЙШИЕ УЛУЧШЕНИЯ (опционально)
|
||||||
|
|
||||||
|
### Если нужно ещё быстрее (< 1 секунды):
|
||||||
|
|
||||||
|
#### **#1: Nginx Reverse Proxy с кешем метаданных**
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
# Кешировать PROPFIND ответы
|
||||||
|
location ~ ^/remote.php/dav/files/ {
|
||||||
|
proxy_cache_path /var/cache/nginx/propfind levels=1:2 keys_zone=PROPFIND:10m;
|
||||||
|
proxy_cache PROPFIND;
|
||||||
|
proxy_cache_valid 200 5m;
|
||||||
|
proxy_cache_methods GET HEAD PROPFIND;
|
||||||
|
proxy_cache_key "$request_method$request_uri";
|
||||||
|
|
||||||
|
proxy_pass http://nextcloud-fresh;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Метаданные из Nginx кеша → 0.01-0.05 секунды
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### **#2: Прямой WOPI endpoint в CRM (обход Nextcloud для метаданных)**
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Collabora запрашивает метаданные напрямую из CRM
|
||||||
|
// CRM отдаёт из своей БД (мгновенно!)
|
||||||
|
// Collabora читает файл через presigned S3 URL
|
||||||
|
|
||||||
|
WOPISrc = https://crm.clientright.ru/wopi/files/{recordId}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** 0.1-0.2 секунды полное открытие
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### **#3: Кеш в CRM Redis**
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Кешировать fileId в CRM Redis
|
||||||
|
$redis->set("nc_fileid:$recordId", $fileId, 3600);
|
||||||
|
|
||||||
|
// При открытии - сразу из кеша
|
||||||
|
$fileId = $redis->get("nc_fileid:$recordId");
|
||||||
|
if ($fileId) {
|
||||||
|
// Сразу открываем без PROPFIND
|
||||||
|
return "https://office.clientright.ru:8443/apps/richdocuments/index?fileId=$fileId";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Без PROPFIND вообще → 0.05-0.1 секунды
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ИТОГОВЫЕ РЕКОМЕНДАЦИИ
|
||||||
|
|
||||||
|
### **ДЛЯ ПРОДАКШЕНА (СЕЙЧАС):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. filesystem_check_changes=0 для S3 (УЖЕ ПРИМЕНЕНО)
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ files_external:option 1 filesystem_check_changes 0
|
||||||
|
|
||||||
|
# 2. Cron сканирование каждые 30 минут
|
||||||
|
crontab -e
|
||||||
|
*/30 * * * * docker exec -u www-data nextcloud-fresh php occ files:scan --path=/admin/files/crm --shallow > /dev/null 2>&1
|
||||||
|
|
||||||
|
# 3. Мониторинг
|
||||||
|
docker stats nextcloud-fresh --no-stream
|
||||||
|
```
|
||||||
|
|
||||||
|
### **ЕСЛИ НУЖНО ЕЩЁ БЫСТРЕЕ:**
|
||||||
|
|
||||||
|
- Nginx cache для PROPFIND (→ 0.05s)
|
||||||
|
- Кеш fileId в CRM Redis (→ без PROPFIND)
|
||||||
|
- Прямой WOPI от CRM (→ полный обход Nextcloud для метаданных)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ ТЕКУЩИЙ СТАТУС
|
||||||
|
|
||||||
|
### Производительность:
|
||||||
|
- ✅ **Открытие для редактирования:** ~1.5 секунды (было 25с)
|
||||||
|
- ✅ **Просмотр:** ~0.2 секунды (прямые ссылки S3)
|
||||||
|
- ✅ **CPU Nextcloud:** 0.05-5% (было 50%)
|
||||||
|
- ✅ **Стабильность:** отлично
|
||||||
|
|
||||||
|
### Настройки:
|
||||||
|
```php
|
||||||
|
'memcache.distributed' => '\OC\Memcache\Redis', // ✅
|
||||||
|
'filesystem_check_changes' => 1, // глобально
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
// External Storage ID 1 (/crm)
|
||||||
|
{
|
||||||
|
"filesystem_check_changes": 0, // ✅ ОТКЛЮЧЕНО
|
||||||
|
"encrypt": false, // ✅ ОТКЛЮЧЕНО
|
||||||
|
"previews": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 РЕЗУЛЬТАТ
|
||||||
|
|
||||||
|
**Редактирование документов теперь открывается в 18 раз быстрее!**
|
||||||
|
|
||||||
|
- Было: 25 секунд ❌
|
||||||
|
- Стало: 1.5 секунды ✅
|
||||||
|
|
||||||
|
**Это приемлемая скорость для редактирования!** 🚀
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Следующий шаг:** Настроить cron для периодического сканирования новых файлов
|
||||||
|
|
||||||
|
**Хочешь настрою cron?** 😊
|
||||||
|
|
||||||
560
NEXTCLOUD_ЛАЙФХАКИ_УСКОРЕНИЯ.md
Normal file
560
NEXTCLOUD_ЛАЙФХАКИ_УСКОРЕНИЯ.md
Normal file
@@ -0,0 +1,560 @@
|
|||||||
|
# 🚀 NEXTCLOUD - ЛАЙФХАКИ УСКОРЕНИЯ
|
||||||
|
|
||||||
|
## 🎯 ЦЕЛЬ: Работать как Google Drive
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 ПРЕДЛОЖЕНИЯ ДЛЯ ОБСУЖДЕНИЯ
|
||||||
|
|
||||||
|
### 1️⃣ **HTTP/2 Push и Preload** ⚡⚡⚡
|
||||||
|
**Что:** Предзагрузка ресурсов до того как браузер их запросит
|
||||||
|
|
||||||
|
**Реализация в Nginx:**
|
||||||
|
```nginx
|
||||||
|
location ~ \.php$ {
|
||||||
|
# Предзагрузка JS/CSS
|
||||||
|
add_header Link "</core/css/styles.css>; rel=preload; as=style";
|
||||||
|
add_header Link "</core/js/main.js>; rel=preload; as=script";
|
||||||
|
|
||||||
|
# HTTP/2 Push
|
||||||
|
http2_push /core/css/styles.css;
|
||||||
|
http2_push /core/js/main.js;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемый эффект:** +30-50% скорость загрузки интерфейса
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2️⃣ **Separating Data Directory на SSD** 💾⚡⚡⚡
|
||||||
|
**Что:** Переместить БД Nextcloud на SSD диск (если сейчас на HDD)
|
||||||
|
|
||||||
|
**Проверка текущего диска:**
|
||||||
|
```bash
|
||||||
|
docker exec nextcloud-db-fresh df -h /var/lib/mysql
|
||||||
|
lsblk
|
||||||
|
```
|
||||||
|
|
||||||
|
**Если на HDD:**
|
||||||
|
- Создать volume на SSD
|
||||||
|
- Перенести `/var/lib/mysql` туда
|
||||||
|
- **Ускорение:** 5-10x для случайных запросов
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3️⃣ **Query Cache для MySQL** 🗄️⚡⚡
|
||||||
|
**Что:** Кешировать результаты повторяющихся SQL запросов
|
||||||
|
|
||||||
|
**НО!** В MariaDB 10.6+ Query Cache УДАЛЁН (deprecated)
|
||||||
|
|
||||||
|
**Альтернатива - ProxySQL:**
|
||||||
|
```bash
|
||||||
|
docker run -d --name proxysql \
|
||||||
|
--link nextcloud-db-fresh:mysql \
|
||||||
|
-p 6033:6033 \
|
||||||
|
proxysql/proxysql
|
||||||
|
```
|
||||||
|
|
||||||
|
**Настройка:**
|
||||||
|
- ProxySQL кеширует запросы к БД
|
||||||
|
- Nextcloud подключается к ProxySQL вместо напрямую к MySQL
|
||||||
|
- **Ускорение:** 2-3x для повторяющихся запросов
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4️⃣ **Preview Pre-generation** 🖼️⚡⚡
|
||||||
|
**Что:** Генерировать превью заранее в фоне
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Установка приложения
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:install previewgenerator
|
||||||
|
|
||||||
|
# Настройка размеров
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator squareSizes --value="32 256"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator widthSizes --value="256 384"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator heightSizes --value="256"
|
||||||
|
|
||||||
|
# Первичная генерация (один раз)
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ preview:generate-all
|
||||||
|
|
||||||
|
# Cron каждые 10 минут
|
||||||
|
*/10 * * * * docker exec -u www-data nextcloud-fresh php occ preview:pre-generate
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Превью файлов грузятся мгновенно
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5️⃣ **Chunked Upload для больших файлов** 📤⚡⚡
|
||||||
|
**Что:** Загрузка кусками вместо одного большого файла
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set files max_chunk_size --value=10485760 # 10MB chunks
|
||||||
|
```
|
||||||
|
|
||||||
|
**Для S3 External Storage:**
|
||||||
|
```bash
|
||||||
|
# Multipart upload для файлов > 5GB
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set objectstore.s3.multipart_threshold --value=5368709120 --type=integer
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Большие файлы загружаются быстрее и надёжнее
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6️⃣ **MySQL InnoDB Optimization** 🗄️⚡⚡⚡
|
||||||
|
**Что:** Правильные индексы для oc_filecache
|
||||||
|
|
||||||
|
**Текущие индексы:**
|
||||||
|
```sql
|
||||||
|
-- Проверка
|
||||||
|
docker exec nextcloud-db-fresh mariadb -u root -proot_password nextcloud -e "SHOW INDEX FROM oc_filecache;" 2>&1 | grep -v insecure
|
||||||
|
```
|
||||||
|
|
||||||
|
**Добавление недостающих:**
|
||||||
|
```sql
|
||||||
|
-- Для быстрого поиска по storage+path
|
||||||
|
CREATE INDEX idx_storage_path_hash ON oc_filecache(storage, path_hash);
|
||||||
|
|
||||||
|
-- Для быстрого поиска дочерних файлов
|
||||||
|
CREATE INDEX idx_parent_name ON oc_filecache(parent, name(191));
|
||||||
|
|
||||||
|
-- Для быстрого поиска по mimetype
|
||||||
|
CREATE INDEX idx_storage_mimetype ON oc_filecache(storage, mimetype);
|
||||||
|
|
||||||
|
-- Для сортировки по времени
|
||||||
|
CREATE INDEX idx_storage_mtime ON oc_filecache(storage, mtime);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Автоматически:**
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ db:add-missing-indices
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ db:convert-filecache-bigint
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** +50-100% скорость запросов к файлам
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7️⃣ **Nginx FastCGI Cache** 🌐⚡⚡⚡
|
||||||
|
**Что:** Кеш статических ресурсов и некоторых динамических
|
||||||
|
|
||||||
|
**Конфигурация Nginx:**
|
||||||
|
```nginx
|
||||||
|
# В http блоке
|
||||||
|
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=NEXTCLOUD:100m inactive=60m;
|
||||||
|
fastcgi_cache_key "$scheme$request_method$host$request_uri";
|
||||||
|
|
||||||
|
server {
|
||||||
|
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
|
||||||
|
# FastCGI cache для избранных endpoints
|
||||||
|
fastcgi_cache NEXTCLOUD;
|
||||||
|
fastcgi_cache_valid 200 10m;
|
||||||
|
fastcgi_cache_bypass $http_pragma $http_authorization;
|
||||||
|
add_header X-Cache-Status $upstream_cache_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Статика грузится мгновенно
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8️⃣ **Lazy Loading для больших папок** 📂⚡⚡
|
||||||
|
**Что:** Не грузить все 24K файлов сразу, а порциями
|
||||||
|
|
||||||
|
**В Nextcloud уже есть!** Проверяем настройки:
|
||||||
|
```bash
|
||||||
|
# Pagination включена по умолчанию
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:get files pagination_limit
|
||||||
|
# Если нет - ставим
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set files pagination_limit --value=100
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Папки открываются быстрее
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9️⃣ **S3 Transfer Acceleration** 🌍⚡⚡⚡
|
||||||
|
**Что:** Использовать CDN endpoints TWC Storage
|
||||||
|
|
||||||
|
**Проверяем у провайдера TWC:**
|
||||||
|
- Есть ли CDN endpoint?
|
||||||
|
- Есть ли региональные endpoints ближе к серверу?
|
||||||
|
|
||||||
|
**Если есть:**
|
||||||
|
```php
|
||||||
|
// В config.php Nextcloud для S3
|
||||||
|
'objectstore' => [
|
||||||
|
'arguments' => [
|
||||||
|
'endpoint' => 'https://s3-accelerate.twcstorage.ru', // вместо обычного
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** +50-200% скорость доступа к S3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔟 **WebDAV Keepalive Connections** 🔗⚡⚡
|
||||||
|
**Что:** Переиспользовать HTTP соединения вместо создания новых
|
||||||
|
|
||||||
|
**В Nginx:**
|
||||||
|
```nginx
|
||||||
|
upstream nextcloud {
|
||||||
|
server nextcloud-fresh:80;
|
||||||
|
keepalive 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
location / {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Connection "";
|
||||||
|
proxy_pass http://nextcloud;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Меньше латентности при множественных запросах
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣1️⃣ **Collabora Caching** 📝⚡⚡⚡
|
||||||
|
**Что:** Кеш документов и шрифтов в Collabora
|
||||||
|
|
||||||
|
**Проверка docker-compose Collabora:**
|
||||||
|
```yaml
|
||||||
|
collabora:
|
||||||
|
environment:
|
||||||
|
- DONT_GEN_SSL_CERT=true
|
||||||
|
- extra_params=--o:ssl.enable=false --o:logging.level=warning --o:net.post_allow=crm\.clientright\.ru
|
||||||
|
# Добавляем кеширование
|
||||||
|
- extra_params=--o:admin_console.enable_pam=false --o:net.connection_timeout_secs=30 --o:per_document.idle_timeout_secs=3600
|
||||||
|
# Добавляем volume для кеша
|
||||||
|
volumes:
|
||||||
|
- /var/cache/collabora:/tmp/cache
|
||||||
|
```
|
||||||
|
|
||||||
|
**Создаём кеш папку:**
|
||||||
|
```bash
|
||||||
|
mkdir -p /var/cache/collabora
|
||||||
|
chmod 777 /var/cache/collabora
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Документы открываются в 2-3 раза быстрее
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣2️⃣ **Browser Service Worker Cache** 🌐⚡⚡
|
||||||
|
**Что:** Кеш в браузере через Service Workers
|
||||||
|
|
||||||
|
**Nextcloud уже использует!** Проверить можно:
|
||||||
|
- F12 → Application → Service Workers
|
||||||
|
- Должен быть зарегистрирован
|
||||||
|
|
||||||
|
**Если нет - включаем PWA:**
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set core enable_pwa --value=yes
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Интерфейс грузится мгновенно после первого раза
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣3️⃣ **Direct S3 Access (bypass Nextcloud)** 🔥⚡⚡⚡
|
||||||
|
**Что:** Открывать файлы напрямую из S3, минуя Nextcloud WebDAV
|
||||||
|
|
||||||
|
**Реализация в CRM:**
|
||||||
|
```php
|
||||||
|
// В nextcloud-editor.js
|
||||||
|
function openFileDirectFromS3(recordId) {
|
||||||
|
// Получаем s3_key из CRM
|
||||||
|
fetch(`/crm_extensions/nextcloud_api.php?record=${recordId}`)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
// Прямая ссылка на S3
|
||||||
|
const s3Url = `https://s3.twcstorage.ru/${bucket}/${data.s3_key}`;
|
||||||
|
|
||||||
|
// Для просмотра - прямо открываем
|
||||||
|
if (isViewMode) {
|
||||||
|
window.open(s3Url, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для редактирования - через Nextcloud
|
||||||
|
if (isEditMode) {
|
||||||
|
openInCollabora(data.nc_path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:**
|
||||||
|
- Просмотр: мгновенно (прямо из S3)
|
||||||
|
- Редактирование: через Nextcloud (нужен Collabora)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣4️⃣ **MySQL Connection Pooling** 🔗⚡⚡
|
||||||
|
**Что:** Пул соединений к БД вместо открытия нового каждый раз
|
||||||
|
|
||||||
|
**ProxySQL (рекомендуется):**
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
proxysql:
|
||||||
|
image: proxysql/proxysql:latest
|
||||||
|
ports:
|
||||||
|
- "6033:6033"
|
||||||
|
volumes:
|
||||||
|
- ./proxysql.cnf:/etc/proxysql.cnf
|
||||||
|
```
|
||||||
|
|
||||||
|
**Или в самом MySQL:**
|
||||||
|
```sql
|
||||||
|
SET GLOBAL max_connections = 500; -- увеличиваем пул
|
||||||
|
SET GLOBAL thread_cache_size = 100; -- кеш потоков
|
||||||
|
SET GLOBAL table_open_cache = 4096; -- кеш таблиц
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Меньше overhead на создание соединений
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣5️⃣ **Отключение Activity Log для CRM папки** 📊⚡⚡
|
||||||
|
**Что:** Не логировать каждое действие в папке с 24K файлов
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Отключаем activity для storage ID 4 (crm)
|
||||||
|
docker exec nextcloud-db-fresh mariadb -u root -proot_password nextcloud -e "
|
||||||
|
DELETE FROM oc_activity WHERE object_type = 'files' AND object_id IN (
|
||||||
|
SELECT fileid FROM oc_filecache WHERE storage = 4
|
||||||
|
);
|
||||||
|
"
|
||||||
|
|
||||||
|
# Настройка в Nextcloud
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set activity enable_activity_tracking --value=no
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Меньше записей в БД при каждом открытии файла
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣6️⃣ **CDN для статики Nextcloud** 🌍⚡⚡⚡
|
||||||
|
**Что:** Статические файлы (JS/CSS/иконки) через CDN
|
||||||
|
|
||||||
|
**Cloudflare перед Nextcloud:**
|
||||||
|
```nginx
|
||||||
|
# В Nginx - доверяем Cloudflare IP
|
||||||
|
set_real_ip_from 103.21.244.0/22;
|
||||||
|
set_real_ip_from 103.22.200.0/22;
|
||||||
|
# ... остальные Cloudflare IP
|
||||||
|
real_ip_header CF-Connecting-IP;
|
||||||
|
```
|
||||||
|
|
||||||
|
**В Nextcloud config.php:**
|
||||||
|
```php
|
||||||
|
'overwriteprotocol' => 'https',
|
||||||
|
'trusted_proxies' => ['173.245.48.0/20', '103.21.244.0/22'],
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:**
|
||||||
|
- Статика грузится из ближайшего PoP
|
||||||
|
- Меньше нагрузки на сервер
|
||||||
|
- Быстрее для пользователей
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣7️⃣ **Асинхронные операции через Jobs** ⏱️⚡⚡
|
||||||
|
**Что:** Тяжёлые операции (сканирование, превью) в фоне
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cron вместо Ajax/Webcron
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ background:cron
|
||||||
|
|
||||||
|
# В host cron
|
||||||
|
*/5 * * * * docker exec -u www-data nextcloud-fresh php occ cron:job:run
|
||||||
|
```
|
||||||
|
|
||||||
|
**Важно для нас:**
|
||||||
|
- Сканирование S3 - в фоне
|
||||||
|
- Генерация превью - в фоне
|
||||||
|
- Очистка кеша - в фоне
|
||||||
|
|
||||||
|
**Эффект:** UI не тормозит при открытии файлов
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣8️⃣ **Partitioning таблицы oc_filecache** 🗂️⚡⚡⚡
|
||||||
|
**Что:** Разбить огромную таблицу по storage ID
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Проверяем размер таблицы
|
||||||
|
SELECT
|
||||||
|
table_name AS `Table`,
|
||||||
|
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS `Size (MB)`
|
||||||
|
FROM information_schema.TABLES
|
||||||
|
WHERE table_schema = "nextcloud" AND table_name = "oc_filecache";
|
||||||
|
|
||||||
|
-- Если > 100MB - делаем partitioning
|
||||||
|
ALTER TABLE oc_filecache
|
||||||
|
PARTITION BY RANGE (storage) (
|
||||||
|
PARTITION p_storage_1_3 VALUES LESS THAN (4),
|
||||||
|
PARTITION p_storage_4 VALUES LESS THAN (5), -- CRM папка отдельно!
|
||||||
|
PARTITION p_storage_other VALUES LESS THAN MAXVALUE
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:**
|
||||||
|
- Запросы к CRM папке НЕ сканируют всю таблицу
|
||||||
|
- +50-80% скорость для больших таблиц
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1️⃣9️⃣ **Отдельный WOPI сервер для Collabora** 📝⚡⚡⚡
|
||||||
|
**Что:** Collabora на отдельном сервере/контейнере
|
||||||
|
|
||||||
|
**Сейчас у вас:**
|
||||||
|
- Nextcloud + Collabora на одном сервере
|
||||||
|
- Конкурируют за ресурсы
|
||||||
|
|
||||||
|
**Оптимально:**
|
||||||
|
```yaml
|
||||||
|
# На другом сервере или с лимитами
|
||||||
|
collabora:
|
||||||
|
cpus: '2.0'
|
||||||
|
mem_limit: 2g
|
||||||
|
mem_reservation: 1g
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Nextcloud и Collabora не мешают друг другу
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2️⃣0️⃣ **Varnish Cache перед Nextcloud** 🚀⚡⚡⚡
|
||||||
|
**Что:** HTTP кеш для статики и некоторых API
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser → Varnish (6081) → Nginx → Nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
**VCL конфигурация:**
|
||||||
|
```vcl
|
||||||
|
# Кешируем статику
|
||||||
|
if (req.url ~ "^/core/.*\.(js|css|png|jpg|svg)$") {
|
||||||
|
return (hash); # кешируем
|
||||||
|
}
|
||||||
|
|
||||||
|
# НЕ кешируем WebDAV
|
||||||
|
if (req.url ~ "^/remote.php/dav/") {
|
||||||
|
return (pass); # не кешируем
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Эффект:** Статика грузится в 10-100 раз быстрее
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 РЕКОМЕНДОВАННЫЙ ПЛАН
|
||||||
|
|
||||||
|
### **БЫСТРЫЕ ПОБЕДЫ (сделать сегодня):**
|
||||||
|
|
||||||
|
1. ✅ **Добавить индексы в MySQL** (5 минут)
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ db:add-missing-indices
|
||||||
|
```
|
||||||
|
|
||||||
|
2. ✅ **Preview Generator** (30 минут первый раз)
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:install previewgenerator
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ preview:generate-all &
|
||||||
|
```
|
||||||
|
|
||||||
|
3. ✅ **Отключить Activity для CRM папки** (2 минуты)
|
||||||
|
```sql
|
||||||
|
DELETE FROM oc_activity WHERE object_id IN (
|
||||||
|
SELECT fileid FROM oc_filecache WHERE storage = 4
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
4. ✅ **Chunked upload** (1 минута)
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set files max_chunk_size --value=10485760
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемое ускорение:** +100-200%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **СРЕДНЯЯ СЛОЖНОСТЬ (на неделе):**
|
||||||
|
|
||||||
|
5. ⬜ **InnoDB Buffer Pool 1GB** - требует изменение docker-compose
|
||||||
|
6. ⬜ **Partitioning oc_filecache** - разделение таблицы
|
||||||
|
7. ⬜ **HTTP/2 в Nginx** - если ещё не включено
|
||||||
|
8. ⬜ **Cron для фоновых задач** - вместо webcron
|
||||||
|
|
||||||
|
**Ожидаемое ускорение:** +50-100%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **ПРОДВИНУТОЕ (если нужно ещё быстрее):**
|
||||||
|
|
||||||
|
9. ⬜ **ProxySQL** - пул соединений к MySQL
|
||||||
|
10. ⬜ **Varnish Cache** - HTTP кеш перед Nextcloud
|
||||||
|
11. ⬜ **Отдельный сервер для Collabora** - разделение нагрузки
|
||||||
|
12. ⬜ **CDN (Cloudflare)** - статика через CDN
|
||||||
|
|
||||||
|
**Ожидаемое ускорение:** +200-500%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **ЭКСПЕРИМЕНТАЛЬНОЕ:**
|
||||||
|
|
||||||
|
13. ⬜ **Direct S3 access для просмотра** - обход Nextcloud
|
||||||
|
14. ⬜ **Nginx caching для WebDAV** - кеш метаданных
|
||||||
|
15. ⬜ **S3 Transfer Acceleration** - если TWC поддерживает
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💰 СООТНОШЕНИЕ УСИЛИЙ/РЕЗУЛЬТАТА
|
||||||
|
|
||||||
|
| Решение | Сложность | Эффект | Приоритет |
|
||||||
|
|---------|-----------|--------|-----------|
|
||||||
|
| **Индексы MySQL** | ⭐ | ⭐⭐⭐ | 🔥🔥🔥 |
|
||||||
|
| **Preview Generator** | ⭐ | ⭐⭐⭐ | 🔥🔥🔥 |
|
||||||
|
| **Отключить Activity** | ⭐ | ⭐⭐ | 🔥🔥 |
|
||||||
|
| **InnoDB Buffer 1GB** | ⭐⭐ | ⭐⭐⭐ | 🔥🔥🔥 |
|
||||||
|
| **Partitioning** | ⭐⭐⭐ | ⭐⭐⭐ | 🔥🔥 |
|
||||||
|
| **ProxySQL** | ⭐⭐⭐ | ⭐⭐ | 🔥 |
|
||||||
|
| **Varnish** | ⭐⭐⭐⭐ | ⭐⭐⭐ | 🔥 |
|
||||||
|
| **Direct S3** | ⭐⭐ | ⭐⭐⭐⭐ | 🔥🔥 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤔 МОИ РЕКОМЕНДАЦИИ
|
||||||
|
|
||||||
|
### **Начни с TOP-4:**
|
||||||
|
|
||||||
|
1. **Индексы MySQL** - 5 минут, +50% скорость
|
||||||
|
2. **Preview Generator** - 30 минут, мгновенные превью
|
||||||
|
3. **Отключить Activity для CRM** - 2 минуты, меньше записей в БД
|
||||||
|
4. **InnoDB Buffer 1GB** - 10 минут, +30% скорость БД
|
||||||
|
|
||||||
|
**Это даст примерно 2-3x ускорение БЕЗ риска!**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Потом, если нужно ещё:**
|
||||||
|
|
||||||
|
5. **Partitioning oc_filecache** - разделить таблицу (сложнее, но эффективно)
|
||||||
|
6. **Direct S3 access** - для просмотра файлов (очень быстро!)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ВОПРОСЫ ДЛЯ ОБСУЖДЕНИЯ:
|
||||||
|
|
||||||
|
1. **Хочешь начать с быстрых побед** (индексы, preview, activity)?
|
||||||
|
2. **Готов менять docker-compose** для InnoDB Buffer?
|
||||||
|
3. **Интересует Direct S3 access** для просмотра файлов (обход Nextcloud)?
|
||||||
|
4. **Рассматриваешь Varnish/ProxySQL** для серьёзного ускорения?
|
||||||
|
|
||||||
|
**Что выберем?** 😊
|
||||||
|
|
||||||
249
NEXTCLOUD_ОПТИМИЗАЦИЯ_31_10_2025.md
Normal file
249
NEXTCLOUD_ОПТИМИЗАЦИЯ_31_10_2025.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# 🚀 ОПТИМИЗАЦИЯ NEXTCLOUD - 31 ОКТЯБРЯ 2025
|
||||||
|
|
||||||
|
## 🔍 ПРОБЛЕМА
|
||||||
|
|
||||||
|
### Симптомы:
|
||||||
|
- ⏱️ Медленное открытие документов из CRM
|
||||||
|
- 🔥 Nextcloud CPU: **50.43%** (постоянно)
|
||||||
|
- ❌ Database Deadlocks при работе с файлами
|
||||||
|
- 📊 24,000+ файлов в папке crm2
|
||||||
|
|
||||||
|
### Найденные проблемы:
|
||||||
|
|
||||||
|
#### 1. **Database Deadlocks** ❌
|
||||||
|
```
|
||||||
|
SQLSTATE[40001]: Serialization failure: 1213
|
||||||
|
Deadlock found when trying to get lock; try restarting transaction
|
||||||
|
```
|
||||||
|
- Nextcloud постоянно сканирует папку crm2 (24K файлов)
|
||||||
|
- Обновления таблицы `oc_filecache` создают блокировки
|
||||||
|
- 404 блокировки (Innodb_row_lock_waits)
|
||||||
|
|
||||||
|
#### 2. **Отсутствие Distributed Cache** ❌
|
||||||
|
- Был только `memcache.local` (APCu)
|
||||||
|
- Не было `memcache.distributed` (Redis)
|
||||||
|
- Кеш не переживал перезапуски
|
||||||
|
|
||||||
|
#### 3. **Автоматическое сканирование** ❌
|
||||||
|
- `filesystem_check_changes = 1` (по умолчанию)
|
||||||
|
- При каждом запросе Nextcloud сканировал все 24K файлов
|
||||||
|
- Огромная нагрузка на БД
|
||||||
|
|
||||||
|
#### 4. **Маленький InnoDB Buffer Pool** ❌
|
||||||
|
- Всего **128 MB** (должно быть минимум 512MB)
|
||||||
|
- Не хватает памяти для кеширования запросов
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ РЕШЕНИЕ
|
||||||
|
|
||||||
|
### 1. Distributed Cache (Redis)
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
- ✅ Кеш между запросами
|
||||||
|
- ✅ Меньше обращений к БД
|
||||||
|
- ✅ Быстрее открытие файлов
|
||||||
|
|
||||||
|
### 2. Отключение автосканирования
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:system:set filesystem_check_changes --value=0 --type=integer
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
- ✅ Nextcloud НЕ сканирует 24K файлов при каждом запросе
|
||||||
|
- ✅ Меньше Deadlocks
|
||||||
|
- ✅ Меньше нагрузки на БД
|
||||||
|
|
||||||
|
**Важно:** Файлы будут обновляться через:
|
||||||
|
- Redis события (`crm:file:events`)
|
||||||
|
- Ручное сканирование при необходимости
|
||||||
|
- WebDAV уведомления
|
||||||
|
|
||||||
|
### 3. Оптимизация PHP
|
||||||
|
```bash
|
||||||
|
# Увеличен memory_limit
|
||||||
|
echo 'memory_limit=1024M' >> /usr/local/etc/php/conf.d/nextcloud.ini
|
||||||
|
|
||||||
|
# Оптимизация OPcache
|
||||||
|
opcache.interned_strings_buffer=16
|
||||||
|
opcache.max_accelerated_files=20000
|
||||||
|
opcache.memory_consumption=256
|
||||||
|
opcache.revalidate_freq=60
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
- ✅ Больше памяти для PHP скриптов
|
||||||
|
- ✅ Больше файлов в OPcache
|
||||||
|
- ✅ Меньше компиляций
|
||||||
|
|
||||||
|
### 4. Оптимизация MySQL
|
||||||
|
```sql
|
||||||
|
SET GLOBAL max_connections = 300; -- было 151
|
||||||
|
SET GLOBAL innodb_lock_wait_timeout = 120; -- было 50
|
||||||
|
```
|
||||||
|
|
||||||
|
**Примечание:** `innodb_buffer_pool_size` требует изменения в docker-compose и перезапуск.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 РЕЗУЛЬТАТ
|
||||||
|
|
||||||
|
### До оптимизации:
|
||||||
|
```
|
||||||
|
CPU: 50.43% ❌
|
||||||
|
Memory: 1005 MiB
|
||||||
|
Deadlocks: много
|
||||||
|
Скорость: медленно
|
||||||
|
```
|
||||||
|
|
||||||
|
### После оптимизации:
|
||||||
|
```
|
||||||
|
CPU: 5.29% ✅ (в 10 раз меньше!)
|
||||||
|
Memory: 645 MiB
|
||||||
|
Deadlocks: должны уменьшиться
|
||||||
|
Скорость: быстрее
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ДОПОЛНИТЕЛЬНЫЕ РЕКОМЕНДАЦИИ
|
||||||
|
|
||||||
|
### 1. Увеличить InnoDB Buffer Pool (требует перезапуск)
|
||||||
|
|
||||||
|
Найти docker-compose файл Nextcloud и добавить:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
environment:
|
||||||
|
MYSQL_INNODB_BUFFER_POOL_SIZE: 1073741824 # 1GB
|
||||||
|
command:
|
||||||
|
- --innodb-buffer-pool-size=1073741824
|
||||||
|
- --innodb-log-file-size=268435456 # 256MB
|
||||||
|
- --innodb-flush-log-at-trx_commit=2
|
||||||
|
- --innodb-flush-method=O_DIRECT
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемое ускорение:** +30-50%
|
||||||
|
|
||||||
|
### 2. Добавить индексы в oc_filecache
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Проверить существующие индексы
|
||||||
|
SHOW INDEX FROM oc_filecache;
|
||||||
|
|
||||||
|
-- Добавить если нужно
|
||||||
|
CREATE INDEX idx_storage_path ON oc_filecache(storage, path(255));
|
||||||
|
CREATE INDEX idx_parent_name ON oc_filecache(parent, name(255));
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ожидаемое ускорение:** +20-40%
|
||||||
|
|
||||||
|
### 3. Настроить Chunked Upload для больших файлов
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set files max_chunk_size --value=10485760 # 10MB
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Включить Preview Generation в фоне
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator squareSizes --value="256 512"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator widthSizes --value="256 512 1024"
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ config:app:set previewgenerator heightSizes --value="256 512 1024"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 МОНИТОРИНГ
|
||||||
|
|
||||||
|
### Проверка производительности:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# CPU/Memory Nextcloud
|
||||||
|
docker stats nextcloud-fresh --no-stream
|
||||||
|
|
||||||
|
# Deadlocks MySQL
|
||||||
|
docker exec nextcloud-db-fresh mariadb -u root -proot_password -e "SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';" 2>&1 | grep -v insecure
|
||||||
|
|
||||||
|
# Redis статистика
|
||||||
|
redis-cli -h 127.0.0.1 -p 6380 -a 'Nextcloud_Redis_Pass_2025!' INFO stats 2>&1 | grep -v Warning | head -10
|
||||||
|
```
|
||||||
|
|
||||||
|
### Логи Nextcloud:
|
||||||
|
```bash
|
||||||
|
docker logs nextcloud-fresh --tail 50 | grep -i "error\|warning\|deadlock"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ ТЕКУЩИЕ НАСТРОЙКИ
|
||||||
|
|
||||||
|
### Nextcloud Config:
|
||||||
|
```php
|
||||||
|
'memcache.local' => '\OC\Memcache\APCu', // Локальный кеш
|
||||||
|
'memcache.distributed' => '\OC\Memcache\Redis', // Распределённый кеш ✅ НОВОЕ
|
||||||
|
'memcache.locking' => '\OC\Memcache\Redis', // Блокировки через Redis
|
||||||
|
'filesystem_check_changes' => 0, // Автоскан ОТКЛЮЧЕН ✅ НОВОЕ
|
||||||
|
```
|
||||||
|
|
||||||
|
### PHP:
|
||||||
|
```
|
||||||
|
memory_limit = 1024M (было 512M)
|
||||||
|
opcache.memory_consumption = 256
|
||||||
|
opcache.max_accelerated_files = 20000
|
||||||
|
opcache.interned_strings_buffer = 16
|
||||||
|
```
|
||||||
|
|
||||||
|
### MySQL:
|
||||||
|
```
|
||||||
|
max_connections = 300 (было 151)
|
||||||
|
innodb_lock_wait_timeout = 120 (было 50)
|
||||||
|
innodb_buffer_pool_size = 128MB (⚠️ НУЖНО 1GB)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 СЛЕДУЮЩИЕ ШАГИ
|
||||||
|
|
||||||
|
### Критично (сделать сегодня):
|
||||||
|
1. ✅ Distributed cache - **ГОТОВО**
|
||||||
|
2. ✅ Отключить автоскан - **ГОТОВО**
|
||||||
|
3. ✅ PHP оптимизация - **ГОТОВО**
|
||||||
|
4. ⏳ Проверить результат - **тестируем**
|
||||||
|
|
||||||
|
### Важно (сделать на неделе):
|
||||||
|
1. ⬜ Увеличить InnoDB buffer pool до 1GB
|
||||||
|
2. ⬜ Добавить индексы в oc_filecache
|
||||||
|
3. ⬜ Настроить chunked upload
|
||||||
|
4. ⬜ Preview generation в фоне
|
||||||
|
|
||||||
|
### Можно (если будет время):
|
||||||
|
1. ⬜ APCu увеличить (apc.shm_size=128M)
|
||||||
|
2. ⬜ Отключить ненужные приложения Nextcloud
|
||||||
|
3. ⬜ Настроить логи на rotation
|
||||||
|
4. ⬜ Мониторинг производительности
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ОЖИДАЕМЫЙ РЕЗУЛЬТАТ
|
||||||
|
|
||||||
|
**После всех оптимизаций:**
|
||||||
|
- ⚡ Открытие документов: **в 3-5 раз быстрее**
|
||||||
|
- 📉 CPU Nextcloud: **< 10%** (было 50%)
|
||||||
|
- ❌ Deadlocks: **минимум** (было много)
|
||||||
|
- 💾 Меньше нагрузки на БД
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Статус:** ✅ Критичные оптимизации применены
|
||||||
|
**CPU до:** 50.43%
|
||||||
|
**CPU после:** 5.29%
|
||||||
|
**Ускорение:** **~10x** 🚀
|
||||||
|
|
||||||
|
**Дата:** 31 октября 2025, 10:04
|
||||||
|
**Автор:** Фёдор + AI Assistant
|
||||||
|
|
||||||
190
WORKFLOW_OCR_КАК_РАБОТАЕТ.md
Normal file
190
WORKFLOW_OCR_КАК_РАБОТАЕТ.md
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
# 🔍 КАК РАБОТАЕТ WORKFLOW OCR
|
||||||
|
|
||||||
|
## ⚠️ **ВАЖНО: Нет ручного запуска!**
|
||||||
|
|
||||||
|
**Workflow OCR** работает **ТОЛЬКО через правила автоматизации**!
|
||||||
|
|
||||||
|
В нём **НЕТ** кнопки "Submit to OCR" в меню файла.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **КАК ЭТО РАБОТАЕТ:**
|
||||||
|
|
||||||
|
### **Принцип работы:**
|
||||||
|
```
|
||||||
|
1. Создаёшь правило workflow
|
||||||
|
2. Загружаешь файл в Nextcloud
|
||||||
|
3. Workflow Engine видит событие
|
||||||
|
4. Запускает OCR автоматически
|
||||||
|
5. Результат сохраняется
|
||||||
|
```
|
||||||
|
|
||||||
|
**Это АВТОМАТИЗАЦИЯ, а не ручной инструмент!**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 **КАК СОЗДАТЬ ПРАВИЛО:**
|
||||||
|
|
||||||
|
### **Вариант 1: Через интерфейс Nextcloud**
|
||||||
|
|
||||||
|
**Шаг 1: Открой настройки Flow**
|
||||||
|
```
|
||||||
|
https://office.clientright.ru:8443/settings/admin/workflow
|
||||||
|
```
|
||||||
|
|
||||||
|
**Шаг 2: Добавь правило**
|
||||||
|
1. Нажми **"Add new workflow"**
|
||||||
|
2. Выбери условия:
|
||||||
|
- **When:** File created
|
||||||
|
- **And:** File MIME type is `application/pdf`
|
||||||
|
- **And:** Path matches `Documents/Project/*`
|
||||||
|
3. Выбери действие:
|
||||||
|
- **Then:** `OCR processing`
|
||||||
|
4. Нажми **Save**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Вариант 2: Через команду (автоматически)**
|
||||||
|
|
||||||
|
Я могу создать правило автоматически через БД!
|
||||||
|
|
||||||
|
Команда создаст правило:
|
||||||
|
```
|
||||||
|
Имя: "CRM - Автоматический OCR судебных документов"
|
||||||
|
|
||||||
|
Условия:
|
||||||
|
- Файл создан
|
||||||
|
- Тип: PDF
|
||||||
|
- Имя содержит: решение, определение, постановление, договор, иск
|
||||||
|
|
||||||
|
Действие:
|
||||||
|
- OCR с русским + английским
|
||||||
|
- Создать searchable PDF
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 **КАК ПРОТЕСТИРОВАТЬ:**
|
||||||
|
|
||||||
|
### **После создания правила:**
|
||||||
|
|
||||||
|
1. **Загрузи тестовый PDF** в папку проекта
|
||||||
|
2. **Дождись 30-60 секунд** (OCR работает в фоне)
|
||||||
|
3. **Проверь через поиск:**
|
||||||
|
```
|
||||||
|
Files → Search (🔍)
|
||||||
|
Введи слово из документа
|
||||||
|
```
|
||||||
|
4. Если находит → **OCR работает!** ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **КАК ПРОВЕРИТЬ ЧТО OCR ВЫПОЛНЕН:**
|
||||||
|
|
||||||
|
### **Способ 1: Через теги**
|
||||||
|
После OCR файл получит тег в Nextcloud (если настроено)
|
||||||
|
|
||||||
|
### **Способ 2: Через логи**
|
||||||
|
```bash
|
||||||
|
docker exec nextcloud-fresh tail -100 /var/www/html/data/nextcloud.log | grep -i ocr
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Способ 3: Через поиск**
|
||||||
|
Если файл находится по тексту из него → OCR выполнен!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ **АЛЬТЕРНАТИВА: Ручной OCR**
|
||||||
|
|
||||||
|
### **Если нужен РУЧНОЙ OCR (не автоматический):**
|
||||||
|
|
||||||
|
Есть другое приложение: **OCR** (не workflow_ocr!)
|
||||||
|
|
||||||
|
**Установка:**
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:install ocr
|
||||||
|
```
|
||||||
|
|
||||||
|
**В нём есть:**
|
||||||
|
- Кнопка "OCR" в меню файла
|
||||||
|
- Ручной запуск для выбранных файлов
|
||||||
|
- Выбор языка
|
||||||
|
|
||||||
|
**НО:** Это старое приложение, может не работать на Nextcloud 31
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **ЧТО ДЕЛАТЬ СЕЙЧАС:**
|
||||||
|
|
||||||
|
### **Вариант А: Я создам правило автоматически**
|
||||||
|
|
||||||
|
Создам через команду, займёт 10 секунд:
|
||||||
|
```sql
|
||||||
|
INSERT INTO oc_flow_operations ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:** Все новые PDF в проектах автоматически пройдут OCR
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Вариант Б: Ты создашь сам через интерфейс**
|
||||||
|
|
||||||
|
Я покажу пошагово со скриншотами:
|
||||||
|
```
|
||||||
|
Settings → Flow → Add rule → ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:** Ты понимаешь как создавать правила
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Вариант В: Установить приложение для ручного OCR**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:install ocr
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:** Появится кнопка OCR в меню файла
|
||||||
|
|
||||||
|
**⚠️ Внимание:** Может не работать на Nextcloud 31!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 **МОЯ РЕКОМЕНДАЦИЯ:**
|
||||||
|
|
||||||
|
**Используй АВТОМАТИЧЕСКИЙ OCR** (Workflow):
|
||||||
|
- ✅ Настроил один раз → работает всегда
|
||||||
|
- ✅ Не нужно помнить запускать OCR
|
||||||
|
- ✅ Все документы обрабатываются одинаково
|
||||||
|
- ✅ Современный подход
|
||||||
|
|
||||||
|
**Ручной OCR** нужен редко (только для старых файлов)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **ДАВАЙ СОЗДАМ ПРАВИЛО?**
|
||||||
|
|
||||||
|
**Что создать:**
|
||||||
|
|
||||||
|
**Правило 1: Судебные документы**
|
||||||
|
```
|
||||||
|
PDF с словами: решение, определение, постановление, иск
|
||||||
|
→ OCR (русский + английский)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Правило 2: Договоры**
|
||||||
|
```
|
||||||
|
PDF в папке Contracts
|
||||||
|
→ OCR (русский + английский)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Правило 3: Все PDF в проектах < 10MB**
|
||||||
|
```
|
||||||
|
PDF в Documents/Project/*, размер < 10MB
|
||||||
|
→ OCR (русский + английский)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Какое правило создать?** Или все три сразу? 😊
|
||||||
|
|
||||||
276
WORKFLOW_ПРИЛОЖЕНИЯ_NEXTCLOUD.md
Normal file
276
WORKFLOW_ПРИЛОЖЕНИЯ_NEXTCLOUD.md
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
# 🔄 WORKFLOW ПРИЛОЖЕНИЯ В NEXTCLOUD
|
||||||
|
|
||||||
|
## 1️⃣ **Workflow OCR Backend** (workflow_ocr)
|
||||||
|
|
||||||
|
### **ЧТО ЭТО:**
|
||||||
|
Приложение для **автоматического распознавания текста (OCR)** из изображений и PDF файлов.
|
||||||
|
|
||||||
|
### **КАК РАБОТАЕТ:**
|
||||||
|
```
|
||||||
|
PDF/Изображение загружено →
|
||||||
|
→ Workflow Engine видит событие →
|
||||||
|
→ Tesseract OCR обрабатывает →
|
||||||
|
→ Создаёт текстовый файл с распознанным текстом
|
||||||
|
```
|
||||||
|
|
||||||
|
### **ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:**
|
||||||
|
|
||||||
|
**1. Автоматическое распознавание сканов:**
|
||||||
|
```
|
||||||
|
Правило: Если загружен файл *.pdf в папку /Scans
|
||||||
|
Действие: Распознать текст и создать .txt файл
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Обработка чеков:**
|
||||||
|
```
|
||||||
|
Правило: Если загружена фотография в /Receipts
|
||||||
|
Действие: OCR → поиск по тексту
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Юридические документы:**
|
||||||
|
```
|
||||||
|
Правило: Если загружен скан решения суда
|
||||||
|
Действие: Распознать текст → сделать документ searchable
|
||||||
|
```
|
||||||
|
|
||||||
|
### **НАСТРОЙКА:**
|
||||||
|
|
||||||
|
**1. Создать правило:**
|
||||||
|
```
|
||||||
|
Settings → Flow → Add rule:
|
||||||
|
- When: File created
|
||||||
|
- And: Mime type is image/* OR application/pdf
|
||||||
|
- And: Path matches /Scans/*
|
||||||
|
- Then: OCR processing
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Выбрать язык:**
|
||||||
|
- Russian (rus)
|
||||||
|
- English (eng)
|
||||||
|
- Multi (rus+eng)
|
||||||
|
|
||||||
|
### **ТЕКУЩИЙ СТАТУС:**
|
||||||
|
- ✅ Установлено: workflow_ocr 1.31.3
|
||||||
|
- ✅ Tesseract OCR: 5.5.0 (движок распознавания)
|
||||||
|
- ❌ Правил НЕТ (не настроено)
|
||||||
|
|
||||||
|
**Вывод:** Приложение установлено, но **НЕ ИСПОЛЬЗУЕТСЯ** (нет правил).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2️⃣ **Flow Notifications** (flow_notifications)
|
||||||
|
|
||||||
|
### **ЧТО ЭТО:**
|
||||||
|
Приложение для **отправки уведомлений** на основе событий Workflow.
|
||||||
|
|
||||||
|
### **КАК РАБОТАЕТ:**
|
||||||
|
```
|
||||||
|
Событие в Nextcloud →
|
||||||
|
→ Workflow Engine проверяет правила →
|
||||||
|
→ Flow Notifications отправляет уведомление
|
||||||
|
```
|
||||||
|
|
||||||
|
### **ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:**
|
||||||
|
|
||||||
|
**1. Уведомление при загрузке важного файла:**
|
||||||
|
```
|
||||||
|
Правило: Если файл загружен в /Important
|
||||||
|
Действие: Отправить уведомление "Загружен важный файл"
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Уведомление о новом контракте:**
|
||||||
|
```
|
||||||
|
Правило: Если PDF загружен в /Contracts
|
||||||
|
Действие: Уведомить юриста
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Алерт при большом файле:**
|
||||||
|
```
|
||||||
|
Правило: Если размер файла > 100MB
|
||||||
|
Действие: Уведомить администратора
|
||||||
|
```
|
||||||
|
|
||||||
|
### **ТИПЫ УВЕДОМЛЕНИЙ:**
|
||||||
|
- 🔔 Push-уведомления в браузере
|
||||||
|
- 📧 Email
|
||||||
|
- 📱 Nextcloud app (Android/iOS)
|
||||||
|
- 🔗 Webhook (для интеграций)
|
||||||
|
|
||||||
|
### **НАСТРОЙКА:**
|
||||||
|
|
||||||
|
**Пример правила:**
|
||||||
|
```
|
||||||
|
Settings → Flow → Add rule:
|
||||||
|
- When: File created
|
||||||
|
- And: File size > 100000000 (100MB)
|
||||||
|
- Then: Send notification
|
||||||
|
- User: admin
|
||||||
|
- Message: "Large file uploaded: {file}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### **ТЕКУЩИЙ СТАТУС:**
|
||||||
|
- ✅ Установлено: flow_notifications 2.0.1
|
||||||
|
- ❌ Правил НЕТ (не настроено)
|
||||||
|
|
||||||
|
**Вывод:** Приложение установлено, но **НЕ ИСПОЛЬЗУЕТСЯ**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3️⃣ **Workflow Engine** (workflowengine)
|
||||||
|
|
||||||
|
### **ЧТО ЭТО:**
|
||||||
|
**Основной движок** для всех workflow - автоматизация действий на основе событий.
|
||||||
|
|
||||||
|
### **АРХИТЕКТУРА:**
|
||||||
|
```
|
||||||
|
┌─────────────────┐
|
||||||
|
│ Workflow Engine │
|
||||||
|
│ (ядро) │
|
||||||
|
└────────┬─────────┘
|
||||||
|
│
|
||||||
|
┌─────────────────┼─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||||
|
│ workflow_ocr │ │flow_notifications││workflow_script│
|
||||||
|
│ (OCR) │ │ (уведомления) │ │ (скрипты) │
|
||||||
|
└───────────────┘ └───────────────┘ └───────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### **ДОСТУПНЫЕ ДЕЙСТВИЯ:**
|
||||||
|
|
||||||
|
**Стандартные:**
|
||||||
|
- ✅ Отправить уведомление
|
||||||
|
- ✅ Добавить тег
|
||||||
|
- ✅ Переместить файл
|
||||||
|
- ✅ Конвертировать в PDF
|
||||||
|
- ✅ Запустить скрипт
|
||||||
|
|
||||||
|
**С установленными приложениями:**
|
||||||
|
- ✅ OCR обработка (workflow_ocr)
|
||||||
|
- ✅ Конвертация PDF (workflow_pdf_converter)
|
||||||
|
- ✅ Запуск скриптов (workflow_script)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4️⃣ **Другие установленные Workflow приложения:**
|
||||||
|
|
||||||
|
### **workflow_pdf_converter**
|
||||||
|
Конвертация документов в PDF:
|
||||||
|
- Word → PDF
|
||||||
|
- Excel → PDF
|
||||||
|
- Images → PDF
|
||||||
|
|
||||||
|
### **workflow_script**
|
||||||
|
Запуск произвольных скриптов при событиях:
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# Пример: отправка файла по API
|
||||||
|
curl -X POST https://api.example.com/upload \
|
||||||
|
-F "file=@$1"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **ТЕКУЩАЯ СИТУАЦИЯ:**
|
||||||
|
|
||||||
|
### **Установлено:**
|
||||||
|
```
|
||||||
|
✅ workflowengine: 2.13.0 (ядро)
|
||||||
|
✅ workflow_ocr: 1.31.3 (OCR)
|
||||||
|
✅ workflow_pdf_converter: 2.0.0 (PDF конвертер)
|
||||||
|
✅ workflow_script: 2.0.0 (скрипты)
|
||||||
|
✅ flow_notifications: 2.0.1 (уведомления)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Активных правил:** 0 ❌
|
||||||
|
|
||||||
|
**Вывод:** Все приложения установлены, но **НЕ НАСТРОЕНЫ** и **НЕ ИСПОЛЬЗУЮТСЯ**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 **РЕКОМЕНДАЦИИ:**
|
||||||
|
|
||||||
|
### **Вариант 1: ИСПОЛЬЗОВАТЬ для автоматизации**
|
||||||
|
|
||||||
|
**Полезные сценарии для CRM:**
|
||||||
|
|
||||||
|
**1. OCR судебных решений:**
|
||||||
|
```
|
||||||
|
Правило: PDF загружен в Documents/Project/*/Судебные решения
|
||||||
|
Действие: OCR → текст извлечён → можно искать
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Уведомления о новых документах:**
|
||||||
|
```
|
||||||
|
Правило: Файл загружен в Documents/Project/*
|
||||||
|
Действие: Уведомить ответственного юриста
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Автоматическая конвертация в PDF:**
|
||||||
|
```
|
||||||
|
Правило: Word/Excel загружен
|
||||||
|
Действие: Конвертировать в PDF
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Вариант 2: ОТКЛЮЧИТЬ если не нужно**
|
||||||
|
|
||||||
|
Если не планируете использовать автоматизацию:
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:disable workflow_ocr
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:disable flow_notifications
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:disable workflow_pdf_converter
|
||||||
|
docker exec -u www-data nextcloud-fresh php occ app:disable workflow_script
|
||||||
|
```
|
||||||
|
|
||||||
|
**Оставить только ядро:** `workflowengine` (базовая функциональность)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **КАК НАСТРОИТЬ (если нужно):**
|
||||||
|
|
||||||
|
### **Шаг 1: Открыть настройки Flow**
|
||||||
|
```
|
||||||
|
https://office.clientright.ru:8443/settings/admin/workflow
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Шаг 2: Создать правило**
|
||||||
|
```
|
||||||
|
1. Add rule
|
||||||
|
2. Выбрать событие (File created, File updated, etc.)
|
||||||
|
3. Добавить условия (path, mime type, size)
|
||||||
|
4. Выбрать действие (OCR, notification, convert)
|
||||||
|
5. Save
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Шаг 3: Протестировать**
|
||||||
|
Загрузить тестовый файл → проверить что правило сработало
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **ИСПОЛЬЗУЕМЫЕ РЕСУРСЫ:**
|
||||||
|
|
||||||
|
### **Tesseract OCR:**
|
||||||
|
- Версия: 5.5.0
|
||||||
|
- Языки: русский, английский (установлены)
|
||||||
|
- CPU: ~50-100% на файл
|
||||||
|
- Время: ~10-30 сек на страницу
|
||||||
|
|
||||||
|
### **Дисковое пространство:**
|
||||||
|
OCR создаёт дополнительные текстовые файлы = +10-20% от размера PDF
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ **ВАЖНО:**
|
||||||
|
|
||||||
|
**Если НЕ используете эти функции** → лучше **отключить**:
|
||||||
|
- Меньше нагрузка на систему
|
||||||
|
- Меньше ошибок в логах
|
||||||
|
- Проще поддержка
|
||||||
|
|
||||||
|
**Если НУЖНА автоматизация** → настроить правила workflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Вам нужна автоматизация (OCR, уведомления)?** Или отключить эти приложения? 🤔
|
||||||
|
|
||||||
520
ai_dialogs_export.txt
Normal file
520
ai_dialogs_export.txt
Normal file
@@ -0,0 +1,520 @@
|
|||||||
|
╔══════════════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ 📚 ИСТОРИЯ AI ДИАЛОГОВ С КЛИЕНТАМИ ║
|
||||||
|
║ Дата выгрузки: 29.10.2025 12:01:36 ║
|
||||||
|
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
Всего записей: 29
|
||||||
|
|
||||||
|
════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Курманжанова ИП Жгенти Дав<D0B0> (ID: 36937)
|
||||||
|
👤 КЛИЕНТ: Карина Курманжанова
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-20 11:37:53 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ [document] │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ На основе найденных фрагментов, я могу │
|
||||||
|
│ рассказать о требованиях к │
|
||||||
|
│ документам: │
|
||||||
|
│ │
|
||||||
|
│ 1. Документы нужно предоставлять в │
|
||||||
|
│ формате PDF │
|
||||||
|
│ 2. Если у вас бумажные документы - их │
|
||||||
|
│ можно сфотографировать, но важно │
|
||||||
|
│ делать это ровно и четко, захватывая │
|
||||||
|
│ все страницы │
|
||||||
|
│ 3. Для подачи в суд документы лучше │
|
||||||
|
│ собрать в один PDF-файл │
|
||||||
|
│ 4. При личном участии в суде нужно │
|
||||||
|
│ иметь с собой: │
|
||||||
|
│ - распечатанные копии всех документов │
|
||||||
|
│ - паспорт │
|
||||||
|
│ - оригиналы документов │
|
||||||
|
│ │
|
||||||
|
│ Если вам нужна помощь с конкретными │
|
||||||
|
│ документами по вашему делу, уточните │
|
||||||
|
│ пожалуйста ваш вопрос. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Юдин ИП Николаенков Васили (ID: 87121)
|
||||||
|
👤 КЛИЕНТ:
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Коробков _Тим_ДТП (ID: 354918)
|
||||||
|
👤 КЛИЕНТ: Fedor -
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-16 16:39:10 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ да, скажи пожалуйста, какой статус? │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ На данный момент дело инициировано │
|
||||||
|
│ (находится в начальной стадии │
|
||||||
|
│ претензионно-исковой работы). Это │
|
||||||
|
│ значит, что работа по делу начата, но │
|
||||||
|
│ до суда дело еще не дошло. В системе │
|
||||||
|
│ есть загруженные документы, включая │
|
||||||
|
│ претензию, но окончательное решение │
|
||||||
|
│ по делу пока не принято. │
|
||||||
|
│ │
|
||||||
|
│ Отмечу важные моменты: │
|
||||||
|
│ - Дело активно (не завершено) │
|
||||||
|
│ - Находится на стадии досудебного │
|
||||||
|
│ урегулирования │
|
||||||
|
│ - Плановая дата завершения │
|
||||||
|
│ установлена на 16.11.2025 │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Казаков УНИВЕРСИТЕТ СИНЕРГ (ID: 370163)
|
||||||
|
👤 КЛИЕНТ: Антон Казаков
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-10 11:35:19 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Подробную статью Гайд давай │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Простите, но я не могу составить для │
|
||||||
|
│ вас подробную статью-гайд или │
|
||||||
|
│ рекомендации для публикации. Это │
|
||||||
|
│ выходит за рамки моих полномочий как │
|
||||||
|
│ юридического помощника по вашему │
|
||||||
|
│ делу. │
|
||||||
|
│ │
|
||||||
|
│ Вместо этого я рекомендую: │
|
||||||
|
│ │
|
||||||
|
│ 1. Обратиться к вашему юристу, который │
|
||||||
|
│ вел дело - он сможет дать │
|
||||||
|
│ квалифицированную консультацию о том, │
|
||||||
|
│ как безопасно делиться информацией о │
|
||||||
|
│ деле. │
|
||||||
|
│ │
|
||||||
|
│ 2. Любые публикации о деле лучше │
|
||||||
|
│ предварительно согласовать с вашим │
|
||||||
|
│ юристом, чтобы избежать возможных │
|
||||||
|
│ рисков. │
|
||||||
|
│ │
|
||||||
|
│ Я могу отвечать на ваши вопросы по │
|
||||||
|
│ существу дела: о датах заседаний, │
|
||||||
|
│ суммах, статусе, имеющихся документах. │
|
||||||
|
│ Но составление рекомендаций для │
|
||||||
|
│ публикации - это отдельная │
|
||||||
|
│ юридическая услуга, которая требует │
|
||||||
|
│ участия вашего представителя. │
|
||||||
|
│ │
|
||||||
|
│ Хотите узнать конкретную информацию │
|
||||||
|
│ по вашему делу? │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Сатюкова ООО ЭДЭКС (ID: 379166)
|
||||||
|
👤 КЛИЕНТ: Дария Сатюкова
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-14 20:20:03 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ [photo] │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Я не могу обрабатывать или │
|
||||||
|
│ анализировать фотографии. Если у вас │
|
||||||
|
│ есть вопрос по вашему делу, │
|
||||||
|
│ пожалуйста, задайте его текстом, и я │
|
||||||
|
│ постараюсь помочь найти нужную │
|
||||||
|
│ информацию. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #2 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-14 20:20:53 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Мне прислали письмо о неявке в суд │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Если вы получили письмо о неявке в суд, │
|
||||||
|
│ это важное уведомление, которое │
|
||||||
|
│ требует вашего внимания. Давайте я │
|
||||||
|
│ уточню детали вашей ситуации: │
|
||||||
|
│ │
|
||||||
|
│ 1. Получите письмо и внимательно │
|
||||||
|
│ ознакомьтесь с его содержанием │
|
||||||
|
│ 2. Если вы действительно не можете │
|
||||||
|
│ присутствовать на судебном заседании, │
|
||||||
|
│ вам нужно уведомить суд о причинах │
|
||||||
|
│ неявки │
|
||||||
|
│ 3. Для получения более точной │
|
||||||
|
│ информации о необходимых действиях в │
|
||||||
|
│ вашей конкретной ситуации, рекомендую │
|
||||||
|
│ обратиться к вашему юристу, который │
|
||||||
|
│ ведет ваше дело │
|
||||||
|
│ │
|
||||||
|
│ Также вы можете отслеживать │
|
||||||
|
│ информацию о деле, позвонив │
|
||||||
|
│ непосредственно в суд. │
|
||||||
|
│ │
|
||||||
|
│ Для того чтобы дать вам более точный │
|
||||||
|
│ ответ по вашей конкретной ситуации, │
|
||||||
|
│ мне нужны дополнительные детали. │
|
||||||
|
│ Пожалуйста, уточните: │
|
||||||
|
│ - Получили ли вы уже само письмо или │
|
||||||
|
│ только уведомление о нем? │
|
||||||
|
│ - От какого суда пришло письмо? │
|
||||||
|
│ - На какую дату назначено заседание? │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #3 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-14 20:22:36 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Я уже получила письмо │
|
||||||
|
│ От Гагаринского районного суда города │
|
||||||
|
│ Москвы │
|
||||||
|
│ На 25.11.2025 │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Если вы не можете присутствовать на │
|
||||||
|
│ судебном заседании 25.11.2025 в │
|
||||||
|
│ Гагаринском районном суде города │
|
||||||
|
│ Москвы, вам необходимо: │
|
||||||
|
│ │
|
||||||
|
│ 1. Подать в суд ходатайство об │
|
||||||
|
│ отложении дела или о рассмотрении │
|
||||||
|
│ дела в ваше отсутствие. Это можно │
|
||||||
|
│ сделать: │
|
||||||
|
│ - через сайт суда в электронном виде │
|
||||||
|
│ - направить почтой │
|
||||||
|
│ - подать непосредственно в │
|
||||||
|
│ канцелярию суда │
|
||||||
|
│ │
|
||||||
|
│ 2. В ходатайстве нужно: │
|
||||||
|
│ - указать причины вашей неявки │
|
||||||
|
│ - приложить подтверждающие │
|
||||||
|
│ документы (если есть) │
|
||||||
|
│ - указать, просите ли вы рассмотреть │
|
||||||
|
│ дело без вашего участия или перенести │
|
||||||
|
│ заседание │
|
||||||
|
│ │
|
||||||
|
│ Для получения более подробной │
|
||||||
|
│ консультации по вашей конкретной │
|
||||||
|
│ ситуации рекомендую обратиться к │
|
||||||
|
│ вашему юристу, который ведет ваше │
|
||||||
|
│ дело. Он лучше знает обстоятельства и │
|
||||||
|
│ сможет подсказать оптимальное │
|
||||||
|
│ решение. │
|
||||||
|
│ │
|
||||||
|
│ Также вы можете отслеживать │
|
||||||
|
│ информацию о движении дела на │
|
||||||
|
│ официальном сайте суда. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #4 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-16 16:19:25 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Я уже получила письмо от Гагаринского │
|
||||||
|
│ районного суда │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Если вы не можете присутствовать на │
|
||||||
|
│ судебном заседании... │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Гафиев ООО ЭДЭКС (ID: 384256)
|
||||||
|
👤 КЛИЕНТ: Марсель Гафиев
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-25 17:39:54 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Здравствуйте! Подготовьте пожалуйста │
|
||||||
|
│ памятку о дольнейсших действиях, │
|
||||||
|
│ (исполнении решения, и сроки) │
|
||||||
|
│ благодарю. │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ На основании имеющейся информации, │
|
||||||
|
│ вот памятка о дальнейших действиях по │
|
||||||
|
│ исполнению решения суда: │
|
||||||
|
│ │
|
||||||
|
│ 1. Получение исполнительного листа: │
|
||||||
|
│ - После вступления решения в законную │
|
||||||
|
│ силу подайте заявление в суд о выдаче │
|
||||||
|
│ исполнительного листа │
|
||||||
|
│ - Вы можете получить исполнительный │
|
||||||
|
│ лист лично в суде или попросить │
|
||||||
|
│ направить его почтой │
|
||||||
|
│ - Срок для получения исполнительного │
|
||||||
|
│ листа - 3 года с момента вступления │
|
||||||
|
│ решения в законную силу │
|
||||||
|
│ │
|
||||||
|
│ 2. Сроки действия исполнительного │
|
||||||
|
│ листа: │
|
||||||
|
│ - Исполнительный лист действует 3 года │
|
||||||
|
│ с момента его выдачи │
|
||||||
|
│ - В течение этого срока вы можете │
|
||||||
|
│ предъявить его к исполнению │
|
||||||
|
│ │
|
||||||
|
│ 3. Порядок исполнения: │
|
||||||
|
│ - После получения исполнительного │
|
||||||
|
│ листа вы можете: │
|
||||||
|
│ * Предъявить его в службу судебных │
|
||||||
|
│ приставов │
|
||||||
|
│ * Если у вас есть банковские │
|
||||||
|
│ реквизиты должника, направить │
|
||||||
|
│ исполнительный лист напрямую в банк │
|
||||||
|
│ │
|
||||||
|
│ Если у вас возникнут вопросы по │
|
||||||
|
│ конкретным действиям или потребуется │
|
||||||
|
│ дополнительная информация, │
|
||||||
|
│ обратитесь к вашему юристу, который │
|
||||||
|
│ сможет дать более детальные │
|
||||||
|
│ рекомендации с учетом особенностей │
|
||||||
|
│ вашего дела. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📁 ПРОЕКТ: Лучина ООО ОТКРЫТЫЙ МИР (ID: 392972)
|
||||||
|
👤 КЛИЕНТ: Галина Лучина
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌─ Диалог #1 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-22 09:49:48 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Возврат денежных средств выполнен в │
|
||||||
|
│ полном объёме │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ По имеющимся данным, возвращена │
|
||||||
|
│ только часть суммы: │
|
||||||
|
│ - Цена договора составляла 130 960,00 ₽ │
|
||||||
|
│ - Возвращено 57 456 ₽ (частичный возврат, │
|
||||||
|
│ выполнен 29.09.2025) │
|
||||||
|
│ │
|
||||||
|
│ Таким образом, возврат денежных │
|
||||||
|
│ средств выполнен не в полном объеме. │
|
||||||
|
│ Остаток задолженности составляет 73 │
|
||||||
|
│ 504,00 ₽. │
|
||||||
|
│ │
|
||||||
|
│ Дело находится в претензионной │
|
||||||
|
│ стадии, ожидается ответ на претензию │
|
||||||
|
│ от ООО "Открытый Мир". │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #2 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-22 09:51:29 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Возврат выполнен 18.10 по итогам спора, │
|
||||||
|
│ открытого банком, картой которого │
|
||||||
|
│ произведена оплата. │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ В данных нет информации о возврате │
|
||||||
|
│ денежных средств 18.10 через банк. Для │
|
||||||
|
│ корректного отражения в деле этой │
|
||||||
|
│ информации рекомендую: │
|
||||||
|
│ │
|
||||||
|
│ 1. Предоставить подтверждающие │
|
||||||
|
│ документы о возврате (чек, выписка или │
|
||||||
|
│ уведомление от банка) │
|
||||||
|
│ 2. После этого информация о полном │
|
||||||
|
│ возврате будет добавлена в карточку │
|
||||||
|
│ дела │
|
||||||
|
│ │
|
||||||
|
│ На текущий момент в деле отражен │
|
||||||
|
│ только частичный возврат 57 456 ₽ от │
|
||||||
|
│ 29.09.2025. Если у вас есть документы о │
|
||||||
|
│ дополнительном возврате, пожалуйста, │
|
||||||
|
│ направьте их вашему юристу для │
|
||||||
|
│ актуализации информации по делу. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #3 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-22 09:59:28 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ [photo] │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Да, я вижу подтверждение вашей │
|
||||||
|
│ информации. Действительно, возврат │
|
||||||
|
│ денежных средств по спору, │
|
||||||
|
│ инициированному банком, произошел. │
|
||||||
|
│ Однако для корректного отражения этой │
|
||||||
|
│ информации в деле нужно: │
|
||||||
|
│ │
|
||||||
|
│ 1. Предоставить подтверждающие │
|
||||||
|
│ документы о возврате (на выбор): │
|
||||||
|
│ - чек │
|
||||||
|
│ - выписка │
|
||||||
|
│ - уведомление от банка │
|
||||||
|
│ │
|
||||||
|
│ После предоставления подтверждающих │
|
||||||
|
│ документов информация о полном │
|
||||||
|
│ возврате будет добавлена в карточку │
|
||||||
|
│ дела. │
|
||||||
|
│ │
|
||||||
|
│ На данный момент в деле отражен только │
|
||||||
|
│ первый частичный возврат в размере 57 │
|
||||||
|
│ 456 ₽ от 29.09.2025. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #4 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-22 10:03:46 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ [photo] │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ В деле действительно сейчас учтен │
|
||||||
|
│ только частичный возврат денежных │
|
||||||
|
│ средств в размере 54 567 ₽. Чтобы │
|
||||||
|
│ зафиксировать полный возврат по спору │
|
||||||
|
│ через банк от 18.10, пожалуйста, │
|
||||||
|
│ предоставьте любой из подтверждающих │
|
||||||
|
│ документов: │
|
||||||
|
│ │
|
||||||
|
│ - чек, или │
|
||||||
|
│ - выписку, или │
|
||||||
|
│ - уведомление от банка │
|
||||||
|
│ │
|
||||||
|
│ После получения документа информация │
|
||||||
|
│ о полном возврате денежных средств │
|
||||||
|
│ будет добавлена в материалы дела. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #5 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-22 10:03:50 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ [photo] │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Я вижу фотоподтверждение возврата │
|
||||||
|
│ средств. Для корректного отражения │
|
||||||
|
│ полного возврата в деле необходимо │
|
||||||
|
│ предоставить один из официальных │
|
||||||
|
│ подтверждающих документов: │
|
||||||
|
│ │
|
||||||
|
│ 1. Чек │
|
||||||
|
│ 2. Банковскую выписку │
|
||||||
|
│ 3. Уведомление от банка о возврате │
|
||||||
|
│ средств │
|
||||||
|
│ │
|
||||||
|
│ После получения любого из этих │
|
||||||
|
│ документов информация о полном │
|
||||||
|
│ возврате будет добавлена в карточку │
|
||||||
|
│ дела. │
|
||||||
|
│ │
|
||||||
|
│ На текущий момент в деле отражен │
|
||||||
|
│ только частичный возврат в размере 57 │
|
||||||
|
│ 456 ₽. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ Диалог #6 ─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📅 2025-10-22 10:04:43 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ❓ ВОПРОС: │
|
||||||
|
│ Иных документов не имею. │
|
||||||
|
│ │
|
||||||
|
│ 🤖 ОТВЕТ: │
|
||||||
|
│ Для корректного отражения полного │
|
||||||
|
│ возврата средств в деле, необходимо │
|
||||||
|
│ предоставить один из следующих │
|
||||||
|
│ подтверждающих документов: │
|
||||||
|
│ │
|
||||||
|
│ 1. Чек │
|
||||||
|
│ 2. Банковскую выписку │
|
||||||
|
│ 3. Уведомление от банка о возврате │
|
||||||
|
│ средств │
|
||||||
|
│ │
|
||||||
|
│ На данный момент в деле учтен только │
|
||||||
|
│ частичный возврат в размере 57 456 ₽. │
|
||||||
|
│ │
|
||||||
|
│ После предоставления любого из │
|
||||||
|
│ указанных документов, информация о │
|
||||||
|
│ полном возврате будет добавлена в │
|
||||||
|
│ карточку дела. │
|
||||||
|
│ │
|
||||||
|
│ <b>Если у вас остались вопросы — │
|
||||||
|
│ мы с радостью ответим!</b> │
|
||||||
|
│ Напишите их прямо здесь. │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
════════════════════════════════════════════════════════════════════════════════
|
||||||
|
Конец выгрузки
|
||||||
3
crm_extensions/file_storage/.env.s3monitor
Normal file
3
crm_extensions/file_storage/.env.s3monitor
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
S3_ACCESS_KEY=2OMAK5ZNM900TAXM16J7
|
||||||
|
S3_SECRET_KEY=f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG
|
||||||
|
S3_BUCKET=f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
|
||||||
277
crm_extensions/file_storage/ARCHITECTURE.md
Normal file
277
crm_extensions/file_storage/ARCHITECTURE.md
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
# 🏗️ Архитектура системы мониторинга файлов
|
||||||
|
|
||||||
|
## 🎯 Общая схема
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ИСТОЧНИКИ ФАЙЛОВ │
|
||||||
|
├─────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
|
||||||
|
│ │ CRM PHP │ │ Nextcloud │ │ S3 Browser │ │ Внешние │ │
|
||||||
|
│ │ │ │ WebUI │ │ Cyberduck │ │ скрипты │ │
|
||||||
|
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └─────┬──────┘ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ └─────────────────┼─────────────────┼─────────────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
└───────────────────────────┼─────────────────┼───────────────────────────┘
|
||||||
|
▼ ▼
|
||||||
|
┌──────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ TWC S3 Storage (Cloud) │
|
||||||
|
│ f9825c87-18698658-c378-... │
|
||||||
|
│ │
|
||||||
|
└────┬─────────────────────────────┬───┘
|
||||||
|
│ │
|
||||||
|
│ (mounted via │ (polling)
|
||||||
|
│ external │
|
||||||
|
│ storage) │
|
||||||
|
▼ ▼
|
||||||
|
┌──────────────────────┐ ┌──────────────────────────┐
|
||||||
|
│ Nextcloud │ │ n8n S3 Monitor │
|
||||||
|
│ Docker Container │ │ Workflow │
|
||||||
|
│ │ │ │
|
||||||
|
│ Files change → │ │ Every 30s: │
|
||||||
|
│ notify_storage_ │ │ 1. List S3 files │
|
||||||
|
│ update (Redis) │ │ 2. Compare with prev │
|
||||||
|
└──────────┬───────────┘ │ 3. Detect changes │
|
||||||
|
│ └─────────┬────────────────┘
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌──────────────────────┐ ┌─────────────────────────┐
|
||||||
|
│ redis_bridge.js │ │ │
|
||||||
|
│ (Node.js) │ │ (n8n internal) │
|
||||||
|
│ │ │ │
|
||||||
|
│ 1. Subscribe NC │ │ │
|
||||||
|
│ Redis │ │ │
|
||||||
|
│ 2. Parse events │ │ │
|
||||||
|
│ 3. Enrich data │ │ │
|
||||||
|
└──────────┬───────────┘ └─────────┬───────────────┘
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
└────────────┬───────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ CRM Redis │
|
||||||
|
│ 147.45.146.17:6379 │
|
||||||
|
│ │
|
||||||
|
│ Channel: │
|
||||||
|
│ crm:file:events │
|
||||||
|
└───────────┬──────────────────┘
|
||||||
|
│
|
||||||
|
│ (subscribe)
|
||||||
|
│
|
||||||
|
┌─────────────────┼─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌────────────┐ ┌────────────┐ ┌────────────┐
|
||||||
|
│ n8n │ │ CRM PHP │ │ Другие │
|
||||||
|
│ Workflows │ │ Listeners │ │ сервисы │
|
||||||
|
└────────────┘ └────────────┘ └────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Потоки событий
|
||||||
|
|
||||||
|
### Поток 1: Файлы через Nextcloud WebUI
|
||||||
|
```
|
||||||
|
User uploads file → Nextcloud → S3 Storage →
|
||||||
|
→ Nextcloud detects change → notify_storage_update (NC Redis) →
|
||||||
|
→ redis_bridge.js → crm:file:events (CRM Redis) → Обработчики
|
||||||
|
```
|
||||||
|
|
||||||
|
⏱️ **Задержка:** ~1-2 секунды (реал-тайм)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Поток 2: Файлы напрямую в S3
|
||||||
|
```
|
||||||
|
External tool → S3 Storage →
|
||||||
|
→ n8n S3 Monitor (polling every 30s) → Detects change →
|
||||||
|
→ crm:file:events (CRM Redis) → Обработчики
|
||||||
|
```
|
||||||
|
|
||||||
|
⏱️ **Задержка:** 0-30 секунд (зависит от интервала polling)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Компоненты системы
|
||||||
|
|
||||||
|
### 1. **redis_bridge.js** (Node.js, работает на хосте)
|
||||||
|
- **Задача:** Мост между Nextcloud Redis и CRM Redis
|
||||||
|
- **Вход:** `notify_storage_update` (Nextcloud Redis, port 6380)
|
||||||
|
- **Выход:** `crm:file:events` (CRM Redis, port 6379)
|
||||||
|
- **Статус:** ✅ Работает
|
||||||
|
- **Запуск:**
|
||||||
|
```bash
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
|
||||||
|
/usr/bin/nodejs redis_bridge.js &
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. **n8n S3 Monitor Workflow** (в n8n)
|
||||||
|
- **Задача:** Мониторинг прямых изменений в S3
|
||||||
|
- **Метод:** Polling (каждые 30 секунд)
|
||||||
|
- **Вход:** TWC S3 API (ListObjectsV2)
|
||||||
|
- **Выход:** `crm:file:events` (CRM Redis)
|
||||||
|
- **Статус:** ⚙️ Нужно настроить
|
||||||
|
- **Файл:** `n8n_s3_monitor_workflow.json`
|
||||||
|
|
||||||
|
### 3. **CRM Redis** (центральная шина событий)
|
||||||
|
- **Адрес:** `147.45.146.17:6379`
|
||||||
|
- **Канал:** `crm:file:events`
|
||||||
|
- **Формат события:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created|file_modified|file_deleted",
|
||||||
|
"source": "nextcloud|s3_monitor|crm",
|
||||||
|
"timestamp": "2025-10-30T12:34:56Z",
|
||||||
|
"path": "full/path/to/file.txt",
|
||||||
|
"filename": "file.txt",
|
||||||
|
"size": 12345,
|
||||||
|
"file_id": 73460,
|
||||||
|
"etag": "abc123...",
|
||||||
|
"operation": "create|update|delete"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Сценарии использования
|
||||||
|
|
||||||
|
### Сценарий 1: Обработка ERV файлов
|
||||||
|
```
|
||||||
|
1. Загружаешь ERV файл в S3 через S3 Browser
|
||||||
|
2. n8n S3 Monitor обнаруживает файл (через 0-30с)
|
||||||
|
3. Событие публикуется в Redis → crm:file:events
|
||||||
|
4. n8n ERV Processor подхватывает событие
|
||||||
|
5. Скачивает файл из S3
|
||||||
|
6. Обрабатывает ERV
|
||||||
|
7. Загружает в CRM
|
||||||
|
8. Отправляет уведомление
|
||||||
|
```
|
||||||
|
|
||||||
|
### Сценарий 2: Автоматическая обработка PDF счетов
|
||||||
|
```
|
||||||
|
1. Клиент загружает PDF в Nextcloud
|
||||||
|
2. Nextcloud → notify_storage_update → redis_bridge.js
|
||||||
|
3. Событие в Redis (реал-тайм, ~1с)
|
||||||
|
4. n8n Invoice Processor:
|
||||||
|
- Распознаёт текст (OCR)
|
||||||
|
- Извлекает данные
|
||||||
|
- Создаёт счёт в CRM
|
||||||
|
- Уведомляет бухгалтера
|
||||||
|
```
|
||||||
|
|
||||||
|
### Сценарий 3: Синхронизация с внешней системой
|
||||||
|
```
|
||||||
|
1. Внешний скрипт пишет в S3
|
||||||
|
2. n8n S3 Monitor (через 30с)
|
||||||
|
3. Redis событие
|
||||||
|
4. n8n External Sync:
|
||||||
|
- Проверяет формат файла
|
||||||
|
- Отправляет в external API
|
||||||
|
- Логирует в CRM
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Настройки производительности
|
||||||
|
|
||||||
|
### Интервал polling S3 Monitor
|
||||||
|
|
||||||
|
| Интервал | Задержка | Нагрузка на API | Рекомендация |
|
||||||
|
|----------|----------|-----------------|--------------|
|
||||||
|
| 10 сек | 0-10с | Высокая | Только для критичных файлов |
|
||||||
|
| 30 сек | 0-30с | Средняя | ✅ **Оптимально** |
|
||||||
|
| 60 сек | 0-60с | Низкая | Для некритичных файлов |
|
||||||
|
| 300 сек | 0-5мин | Минимальная | Для архивов |
|
||||||
|
|
||||||
|
### Количество файлов
|
||||||
|
|
||||||
|
- **< 1000 файлов:** Мониторь весь bucket
|
||||||
|
- **1000-10000:** Используй `Prefix` для фильтрации папок
|
||||||
|
- **> 10000:** Создай отдельные workflows для разных папок
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Мониторинг и логи
|
||||||
|
|
||||||
|
### Проверка работы redis_bridge.js
|
||||||
|
```bash
|
||||||
|
ps aux | grep redis_bridge.js
|
||||||
|
tail -f /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/redis_bridge.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Проверка событий в Redis
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
### Проверка n8n workflow
|
||||||
|
- n8n UI → Workflows → S3 File Monitor → Executions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Расширение системы
|
||||||
|
|
||||||
|
### Добавление новых источников событий
|
||||||
|
|
||||||
|
Любой компонент может публиковать в `crm:file:events`:
|
||||||
|
|
||||||
|
**Пример из PHP (CRM):**
|
||||||
|
```php
|
||||||
|
$redis = new Redis();
|
||||||
|
$redis->connect('147.45.146.17', 6379);
|
||||||
|
$redis->auth('CRM_Redis_Pass_2025_Secure!');
|
||||||
|
|
||||||
|
$event = [
|
||||||
|
'type' => 'file_created',
|
||||||
|
'source' => 'crm_api',
|
||||||
|
'timestamp' => date('c'),
|
||||||
|
'path' => $filePath,
|
||||||
|
'filename' => basename($filePath),
|
||||||
|
'size' => filesize($localPath),
|
||||||
|
'user_id' => $userId
|
||||||
|
];
|
||||||
|
|
||||||
|
$redis->publish('crm:file:events', json_encode($event));
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример из Python:**
|
||||||
|
```python
|
||||||
|
import redis
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
r = redis.Redis(
|
||||||
|
host='147.45.146.17',
|
||||||
|
port=6379,
|
||||||
|
password='CRM_Redis_Pass_2025_Secure!'
|
||||||
|
)
|
||||||
|
|
||||||
|
event = {
|
||||||
|
'type': 'file_created',
|
||||||
|
'source': 'python_script',
|
||||||
|
'timestamp': datetime.utcnow().isoformat() + 'Z',
|
||||||
|
'path': file_path,
|
||||||
|
'filename': os.path.basename(file_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.publish('crm:file:events', json.dumps(event))
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Итого
|
||||||
|
|
||||||
|
✅ **Nextcloud файлы** → реал-тайм через `redis_bridge.js`
|
||||||
|
✅ **S3 прямые загрузки** → polling через n8n (0-30с задержка)
|
||||||
|
✅ **CRM файлы** → прямая публикация в Redis
|
||||||
|
✅ **Единая точка обработки** → Redis канал `crm:file:events`
|
||||||
|
✅ **Гибкость** → любой сервис может подписаться и обработать
|
||||||
|
|
||||||
|
**Всё работает через один канал Redis! 🎉**
|
||||||
|
|
||||||
238
crm_extensions/file_storage/FINAL_SETUP_SUMMARY.md
Normal file
238
crm_extensions/file_storage/FINAL_SETUP_SUMMARY.md
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
# 🎉 ФИНАЛЬНАЯ СВОДКА - S3 МОНИТОРИНГ
|
||||||
|
|
||||||
|
## ✅ ЧТО РАБОТАЕТ:
|
||||||
|
|
||||||
|
### 1️⃣ **S3 Monitor** (Docker контейнер)
|
||||||
|
```
|
||||||
|
Контейнер: s3-monitor
|
||||||
|
Статус: ✅ Работает
|
||||||
|
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
|
||||||
|
Файлов: 24,523
|
||||||
|
Интервал: каждые 30 секунд
|
||||||
|
Автоперезапуск: ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
**Что делает:**
|
||||||
|
- Каждые 30 секунд сканирует S3 bucket
|
||||||
|
- Получает **ВСЕ** файлы (24,523 штук через pagination)
|
||||||
|
- Сравнивает с предыдущим состоянием
|
||||||
|
- Публикует изменения в Redis
|
||||||
|
|
||||||
|
**Команды:**
|
||||||
|
```bash
|
||||||
|
docker logs s3-monitor -f # Логи в реальном времени
|
||||||
|
docker stop s3-monitor # Остановить
|
||||||
|
docker start s3-monitor # Запустить
|
||||||
|
docker restart s3-monitor # Перезапустить
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2️⃣ **Redis Bridge** (Nextcloud → CRM Redis)
|
||||||
|
```
|
||||||
|
Процесс: /usr/bin/nodejs redis_bridge.js
|
||||||
|
Статус: ✅ Работает
|
||||||
|
Порт NC Redis: 127.0.0.1:6380
|
||||||
|
Порт CRM Redis: 147.45.146.17:6379
|
||||||
|
```
|
||||||
|
|
||||||
|
**Что делает:**
|
||||||
|
- Слушает Nextcloud Redis канал `notify_storage_update`
|
||||||
|
- Фильтрует временные файлы (.part, .lock, cache)
|
||||||
|
- **Дедупликация** - один file_id = одно событие (в течение 5 сек)
|
||||||
|
- Публикует в CRM Redis канал `crm:file:events`
|
||||||
|
|
||||||
|
**Команды:**
|
||||||
|
```bash
|
||||||
|
tail -f redis_bridge.log # Логи
|
||||||
|
ps aux | grep redis_bridge # Статус
|
||||||
|
pkill -f redis_bridge.js # Остановить
|
||||||
|
nohup /usr/bin/nodejs redis_bridge.js > redis_bridge.log 2>&1 & # Запустить
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3️⃣ **Redis Канал** (централизованная шина событий)
|
||||||
|
```
|
||||||
|
Host: 147.45.146.17
|
||||||
|
Port: 6379
|
||||||
|
Password: CRM_Redis_Pass_2025_Secure!
|
||||||
|
Channel: crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 ФОРМАТ СОБЫТИЙ:
|
||||||
|
|
||||||
|
### От S3 Monitor:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created",
|
||||||
|
"source": "s3_monitor",
|
||||||
|
"timestamp": "2025-10-30T20:49:31.593Z",
|
||||||
|
"path": "folder/subfolder/file.xlsx",
|
||||||
|
"filename": "file.xlsx",
|
||||||
|
"action": "created",
|
||||||
|
"size": 8224,
|
||||||
|
"etag": "7004954627252c9d0a7e6417f8325d07",
|
||||||
|
"last_modified": "2025-10-30T20:49:14.132Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### От Nextcloud (redis_bridge):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_update",
|
||||||
|
"source": "nextcloud",
|
||||||
|
"timestamp": "2025-10-30T20:52:21.236Z",
|
||||||
|
"storage_id": 4,
|
||||||
|
"path": "crm2/CRM_Active_Files/file.pdf",
|
||||||
|
"file_id": 42594,
|
||||||
|
"filename": "file.pdf",
|
||||||
|
"operation": "update"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Оба публикуются в один канал:** `crm:file:events`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 КАК ОБРАБАТЫВАТЬ В N8N:
|
||||||
|
|
||||||
|
### Шаг 1: Импортируй workflow обработчик
|
||||||
|
Файл: `n8n_s3_event_processor.json`
|
||||||
|
|
||||||
|
### Шаг 2: Настрой Redis Trigger
|
||||||
|
```
|
||||||
|
Node: Redis Subscribe
|
||||||
|
Channel: crm:file:events
|
||||||
|
Credential: CRM Redis
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 3: Parse JSON (если нужно)
|
||||||
|
```javascript
|
||||||
|
// n8n автоматически парсит, но если нужно:
|
||||||
|
const message = $json.message;
|
||||||
|
const event = typeof message === 'string' ? JSON.parse(message) : message;
|
||||||
|
return [{ json: event }];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 4: Фильтруй по типу
|
||||||
|
```javascript
|
||||||
|
// Только новые файлы
|
||||||
|
$json.type === 'file_created'
|
||||||
|
|
||||||
|
// Только XLSX
|
||||||
|
$json.filename.endsWith('.xlsx')
|
||||||
|
|
||||||
|
// Только из определённой папки
|
||||||
|
$json.path.includes('Documents/')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 5: Обработай файл
|
||||||
|
```
|
||||||
|
Switch по расширению:
|
||||||
|
├─ .xlsx → Обработка Excel
|
||||||
|
├─ .pdf → OCR и извлечение данных
|
||||||
|
├─ .jpg → Обработка изображений
|
||||||
|
└─ Другие → Логирование
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 ПРОВЕРКА СОБЫТИЙ:
|
||||||
|
|
||||||
|
### Подпишись на Redis:
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
### Загрузи файл:
|
||||||
|
- Через Nextcloud WebUI
|
||||||
|
- Через S3 Browser
|
||||||
|
- Через aws-cli
|
||||||
|
|
||||||
|
### Увидишь событие:
|
||||||
|
```
|
||||||
|
1) "message"
|
||||||
|
2) "crm:file:events"
|
||||||
|
3) "{\"type\":\"file_created\",\"filename\":\"test.pdf\",...}"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 ИСТОЧНИКИ СОБЫТИЙ:
|
||||||
|
|
||||||
|
| Источник | Метод | Задержка | Фильтры |
|
||||||
|
|----------|-------|----------|---------|
|
||||||
|
| **Nextcloud WebUI** | Redis Bridge | 1-2 сек | ✅ Дедупликация<br>✅ Фильтр .part<br>✅ Фильтр cache |
|
||||||
|
| **S3 прямая загрузка** | S3 Monitor | 0-30 сек | Нет |
|
||||||
|
| **CRM API** | Прямая публикация | 0 сек | Настраивается |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 ДОПОЛНИТЕЛЬНАЯ ФИЛЬТРАЦИЯ В N8N:
|
||||||
|
|
||||||
|
Если всё ещё приходит много событий от Nextcloud, добавь в n8n:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Фильтр: пропускаем дубликаты по filename + timestamp
|
||||||
|
const cache = $getWorkflowStaticData('node');
|
||||||
|
cache.recent = cache.recent || [];
|
||||||
|
|
||||||
|
const key = `${$json.filename}_${$json.file_id}`;
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// Очищаем старые (>10 секунд)
|
||||||
|
cache.recent = cache.recent.filter(item => (now - item.time) < 10000);
|
||||||
|
|
||||||
|
// Проверяем дубликат
|
||||||
|
if (cache.recent.find(item => item.key === key)) {
|
||||||
|
return []; // Пропускаем дубликат
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем в кеш
|
||||||
|
cache.recent.push({ key, time: now });
|
||||||
|
|
||||||
|
return [$input.item];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 ФАЙЛЫ:
|
||||||
|
|
||||||
|
Все в:
|
||||||
|
```
|
||||||
|
/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Рабочие скрипты:**
|
||||||
|
- ✅ `s3_monitor_docker.js` - S3 мониторинг (запущен в Docker)
|
||||||
|
- ✅ `redis_bridge.js` - Nextcloud→CRM мост (запущен)
|
||||||
|
- ✅ `.env.s3monitor` - credentials для S3
|
||||||
|
|
||||||
|
**N8N Workflows для импорта:**
|
||||||
|
- `n8n_s3_event_processor.json` - обработчик событий (НОВЫЙ!)
|
||||||
|
- `n8n_nextcloud_activity_monitor.json` - альтернатива через Activity API
|
||||||
|
- `n8n_s3_monitor_workflow.json` - альтернатива S3 Monitor (если не хочешь Docker)
|
||||||
|
|
||||||
|
**Документация:**
|
||||||
|
- `SETUP_CHECKLIST.md` - чек-лист настройки
|
||||||
|
- `S3_MONITORING_GUIDE.md` - руководство по S3
|
||||||
|
- `ARCHITECTURE.md` - схема архитектуры
|
||||||
|
- `NEXTCLOUD_API_OVERVIEW.md` - обзор Nextcloud API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 ГОТОВО!
|
||||||
|
|
||||||
|
**Система полностью работает:**
|
||||||
|
- ✅ S3 мониторинг (24,523 файла)
|
||||||
|
- ✅ Nextcloud мониторинг (с дедупликацией)
|
||||||
|
- ✅ Redis публикация
|
||||||
|
- ✅ Автоперезапуск
|
||||||
|
- ✅ Фильтрация дубликатов
|
||||||
|
|
||||||
|
**Теперь импортируй `n8n_s3_event_processor.json` в n8n и начинай обрабатывать файлы!** 🚀
|
||||||
|
|
||||||
377
crm_extensions/file_storage/NEXTCLOUD_API_OVERVIEW.md
Normal file
377
crm_extensions/file_storage/NEXTCLOUD_API_OVERVIEW.md
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
# 🌐 Nextcloud API - Обзор и возможности
|
||||||
|
|
||||||
|
## 📋 Доступные API
|
||||||
|
|
||||||
|
### 1. **WebDAV API** ✅ (РАБОТАЕТ)
|
||||||
|
**Базовый URL:** `https://office.clientright.ru:8443/remote.php/webdav/`
|
||||||
|
|
||||||
|
**Аутентификация:** Basic Auth (admin + app password)
|
||||||
|
|
||||||
|
**Возможности:**
|
||||||
|
- ✅ Список файлов и папок (PROPFIND)
|
||||||
|
- ✅ Загрузка файлов (PUT)
|
||||||
|
- ✅ Скачивание файлов (GET)
|
||||||
|
- ✅ Удаление файлов (DELETE)
|
||||||
|
- ✅ Создание папок (MKCOL)
|
||||||
|
- ✅ Перемещение/копирование (MOVE/COPY)
|
||||||
|
- ✅ Получение метаданных (PROPFIND)
|
||||||
|
|
||||||
|
**Пример - список файлов:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
-X PROPFIND \
|
||||||
|
"https://office.clientright.ru:8443/remote.php/webdav/" \
|
||||||
|
-H "Depth: 1"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример - загрузка файла:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
-T /path/to/local/file.txt \
|
||||||
|
"https://office.clientright.ru:8443/remote.php/webdav/file.txt"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример - скачивание файла:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
"https://office.clientright.ru:8443/remote.php/webdav/file.txt" \
|
||||||
|
-o downloaded.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. **OCS API (Open Collaboration Services)** ✅
|
||||||
|
|
||||||
|
**Базовый URL:** `https://office.clientright.ru:8443/ocs/v2.php/`
|
||||||
|
|
||||||
|
**Заголовки:** `OCS-APIRequest: true`
|
||||||
|
|
||||||
|
**Формат ответа:** JSON (`?format=json`)
|
||||||
|
|
||||||
|
#### 2.1 **Capabilities API** (информация о сервере)
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
"https://office.clientright.ru:8443/ocs/v1.php/cloud/capabilities?format=json" \
|
||||||
|
-H "OCS-APIRequest: true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ включает:**
|
||||||
|
- Версию Nextcloud (31.0.9)
|
||||||
|
- Доступные возможности
|
||||||
|
- Лимиты загрузки
|
||||||
|
- Настройки шаринга
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.2 **Activity API** ✅ (СОБЫТИЯ ФАЙЛОВ!)
|
||||||
|
|
||||||
|
**URL:** `https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity`
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
- `format=json` - формат ответа
|
||||||
|
- `limit=N` - количество событий
|
||||||
|
- `since=TIMESTAMP` - события после определённой даты
|
||||||
|
|
||||||
|
**Пример:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
"https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=10" \
|
||||||
|
-H "OCS-APIRequest: true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Типы событий:**
|
||||||
|
- `file_created` - файл создан
|
||||||
|
- `file_changed` - файл изменён
|
||||||
|
- `file_deleted` - файл удалён
|
||||||
|
- `file_restored` - файл восстановлен
|
||||||
|
- `file_shared` - файл расшарен
|
||||||
|
|
||||||
|
**Структура события:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"activity_id": 195,
|
||||||
|
"type": "file_created",
|
||||||
|
"subject": "Вы создали «experimental_report.xlsx»",
|
||||||
|
"message": "",
|
||||||
|
"object_type": "files",
|
||||||
|
"object_id": 73460,
|
||||||
|
"object_name": "/experimental_report.xlsx",
|
||||||
|
"datetime": "2025-10-30T12:53:40+00:00",
|
||||||
|
"user": "admin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**⚠️ Ограничения:**
|
||||||
|
- Нет real-time уведомлений (только polling)
|
||||||
|
- События агрегируются (несколько файлов в одном событии)
|
||||||
|
- Может быть задержка до минуты
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.3 **Users API**
|
||||||
|
|
||||||
|
**Список пользователей:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
"https://office.clientright.ru:8443/ocs/v1.php/cloud/users?format=json" \
|
||||||
|
-H "OCS-APIRequest: true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Информация о пользователе:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
"https://office.clientright.ru:8443/ocs/v1.php/cloud/users/admin?format=json" \
|
||||||
|
-H "OCS-APIRequest: true"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.4 **Sharing API**
|
||||||
|
|
||||||
|
**Список расшаренных файлов:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
"https://office.clientright.ru:8443/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
|
||||||
|
-H "OCS-APIRequest: true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Создать публичную ссылку:**
|
||||||
|
```bash
|
||||||
|
curl -u "admin:APP_PASSWORD" \
|
||||||
|
-X POST \
|
||||||
|
-d "path=/file.txt&shareType=3" \
|
||||||
|
"https://office.clientright.ru:8443/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
|
||||||
|
-H "OCS-APIRequest: true"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. **Direct Download URL**
|
||||||
|
|
||||||
|
Для файлов можно получить прямую ссылку скачивания:
|
||||||
|
|
||||||
|
**Формат:**
|
||||||
|
```
|
||||||
|
https://office.clientright.ru:8443/index.php/apps/files/ajax/download.php?dir=/&files=filename.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Или через WebDAV:
|
||||||
|
```
|
||||||
|
https://office.clientright.ru:8443/remote.php/webdav/filename.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Использование для мониторинга файлов
|
||||||
|
|
||||||
|
### Вариант 1: Activity API Polling (РЕКОМЕНДУЮ для Nextcloud)
|
||||||
|
|
||||||
|
**Создай n8n workflow:**
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ Schedule (каждые 30 сек) │
|
||||||
|
└─────────────────┬───────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ HTTP Request │
|
||||||
|
│ GET /ocs/v2.php/apps/activity/api/v2/ │
|
||||||
|
│ activity?format=json&limit=100 │
|
||||||
|
└─────────────────┬───────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ Code (JS) │
|
||||||
|
│ - Фильтруем file_created/changed/deleted │
|
||||||
|
│ - Сохраняем последний activity_id │
|
||||||
|
│ - Возвращаем только новые события │
|
||||||
|
└─────────────────┬───────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ Redis Publish │
|
||||||
|
│ Channel: crm:file:events │
|
||||||
|
└─────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**Преимущества:**
|
||||||
|
- ✅ Официальный API
|
||||||
|
- ✅ Надёжный
|
||||||
|
- ✅ Детальная информация о событиях
|
||||||
|
- ✅ Не требует доступа к Redis Nextcloud
|
||||||
|
|
||||||
|
**Недостатки:**
|
||||||
|
- ⚠️ Задержка 30-60 сек (polling)
|
||||||
|
- ⚠️ События агрегируются
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Вариант 2: Redis Bridge (УЖЕ РАБОТАЕТ!)
|
||||||
|
|
||||||
|
```
|
||||||
|
Nextcloud Redis (notify_storage_update) →
|
||||||
|
→ redis_bridge.js →
|
||||||
|
→ CRM Redis (crm:file:events)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Преимущества:**
|
||||||
|
- ✅ Real-time (~1-2 сек)
|
||||||
|
- ✅ Не нагружает Nextcloud API
|
||||||
|
|
||||||
|
**Недостатки:**
|
||||||
|
- ⚠️ Требует доступ к внутреннему Redis
|
||||||
|
- ⚠️ Меньше метаданных
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Сравнение подходов
|
||||||
|
|
||||||
|
| Метод | Задержка | Детали | Сложность | Надёжность |
|
||||||
|
|-------|----------|--------|-----------|------------|
|
||||||
|
| **Activity API** | 30-60с | ⭐⭐⭐ | Низкая | ⭐⭐⭐ |
|
||||||
|
| **Redis Bridge** | 1-2с | ⭐⭐ | Средняя | ⭐⭐⭐ |
|
||||||
|
| **S3 Monitor** | 0-30с | ⭐⭐ | Низкая | ⭐⭐⭐ |
|
||||||
|
| **WebDAV Poll** | 60с+ | ⭐ | Низкая | ⭐⭐ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Примеры кода
|
||||||
|
|
||||||
|
### PHP - Получение последних событий
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
$username = 'admin';
|
||||||
|
$password = 'APP_PASSWORD';
|
||||||
|
$url = 'https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=10';
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['OCS-APIRequest: true']);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$data = json_decode($response, true);
|
||||||
|
|
||||||
|
foreach ($data['ocs']['data'] as $activity) {
|
||||||
|
if (in_array($activity['type'], ['file_created', 'file_changed', 'file_deleted'])) {
|
||||||
|
echo "Event: {$activity['type']}\n";
|
||||||
|
echo "File: {$activity['object_name']}\n";
|
||||||
|
echo "Time: {$activity['datetime']}\n";
|
||||||
|
echo "---\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node.js - Activity API Monitor
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const axios = require('axios');
|
||||||
|
const Redis = require('ioredis');
|
||||||
|
|
||||||
|
const CONFIG = {
|
||||||
|
nextcloud: {
|
||||||
|
url: 'https://office.clientright.ru:8443',
|
||||||
|
username: 'admin',
|
||||||
|
password: 'APP_PASSWORD'
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
host: '147.45.146.17',
|
||||||
|
port: 6379,
|
||||||
|
password: 'CRM_Redis_Pass_2025_Secure!'
|
||||||
|
},
|
||||||
|
pollInterval: 30000 // 30 секунд
|
||||||
|
};
|
||||||
|
|
||||||
|
const redis = new Redis(CONFIG.redis);
|
||||||
|
let lastActivityId = 0;
|
||||||
|
|
||||||
|
async function checkActivities() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(
|
||||||
|
`${CONFIG.nextcloud.url}/ocs/v2.php/apps/activity/api/v2/activity`,
|
||||||
|
{
|
||||||
|
params: { format: 'json', limit: 100 },
|
||||||
|
headers: { 'OCS-APIRequest': 'true' },
|
||||||
|
auth: {
|
||||||
|
username: CONFIG.nextcloud.username,
|
||||||
|
password: CONFIG.nextcloud.password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const activities = response.data.ocs.data;
|
||||||
|
const fileEvents = activities.filter(a =>
|
||||||
|
['file_created', 'file_changed', 'file_deleted'].includes(a.type) &&
|
||||||
|
a.activity_id > lastActivityId
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const event of fileEvents.reverse()) {
|
||||||
|
const payload = {
|
||||||
|
type: event.type,
|
||||||
|
source: 'nextcloud_activity',
|
||||||
|
timestamp: event.datetime,
|
||||||
|
file_id: event.object_id,
|
||||||
|
path: event.object_name,
|
||||||
|
filename: event.object_name.split('/').pop(),
|
||||||
|
user: event.user
|
||||||
|
};
|
||||||
|
|
||||||
|
await redis.publish('crm:file:events', JSON.stringify(payload));
|
||||||
|
console.log(`📤 Published: ${event.type} - ${event.object_name}`);
|
||||||
|
|
||||||
|
lastActivityId = Math.max(lastActivityId, event.activity_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запуск
|
||||||
|
console.log('🚀 Nextcloud Activity Monitor');
|
||||||
|
setInterval(checkActivities, CONFIG.pollInterval);
|
||||||
|
checkActivities();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Рекомендации
|
||||||
|
|
||||||
|
### Для твоего use case:
|
||||||
|
|
||||||
|
**Комбинируй несколько подходов:**
|
||||||
|
|
||||||
|
1. **Nextcloud файлы (WebUI)** → **Redis Bridge** (real-time, 1-2с)
|
||||||
|
2. **S3 прямые загрузки** → **n8n S3 Monitor** (polling, 0-30с)
|
||||||
|
3. **CRM загрузки** → **Прямая публикация в Redis** (instant)
|
||||||
|
|
||||||
|
**Все события в одном канале:** `crm:file:events`
|
||||||
|
|
||||||
|
**Альтернатива (если нужна простота):**
|
||||||
|
- Используй **только Activity API** через n8n для Nextcloud событий
|
||||||
|
- Плюс **S3 Monitor** для прямых загрузок в S3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Полезные ссылки
|
||||||
|
|
||||||
|
- [Nextcloud WebDAV Documentation](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/)
|
||||||
|
- [Nextcloud OCS API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/)
|
||||||
|
- [Activity API](https://github.com/nextcloud/activity/blob/master/docs/endpoint-v2.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Безопасность
|
||||||
|
|
||||||
|
**App Password:** `tGHKS-3cC9m-7Hggb-65Awk-zxWQE`
|
||||||
|
**Пользователь:** `admin`
|
||||||
|
|
||||||
|
⚠️ **Важно:** Используй App Passwords, а не основной пароль!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Готово! Теперь ты знаешь все доступные API Nextcloud! 🎉**
|
||||||
|
|
||||||
169
crm_extensions/file_storage/NEXTCLOUD_REDIS_CREDS.md
Normal file
169
crm_extensions/file_storage/NEXTCLOUD_REDIS_CREDS.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
# 🔑 Nextcloud Redis - Креды и подключение
|
||||||
|
|
||||||
|
## 📋 Основная информация
|
||||||
|
|
||||||
|
**Контейнер:** `nextcloud-redis`
|
||||||
|
**IP внутри Docker сети:** `172.24.0.4`
|
||||||
|
**Порт:** `6379`
|
||||||
|
**Пароль:** `НЕТ` (не установлен)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔌 Варианты подключения
|
||||||
|
|
||||||
|
### **ВАРИАНТ 1: Из хоста (если проброшен порт)**
|
||||||
|
|
||||||
|
**Если пробросить порт наружу:**
|
||||||
|
```bash
|
||||||
|
# Перезапустить контейнер с проброшенным портом:
|
||||||
|
docker stop nextcloud-redis
|
||||||
|
docker start -p 6378:6379 nextcloud-redis
|
||||||
|
```
|
||||||
|
|
||||||
|
**Тогда подключаться так:**
|
||||||
|
```
|
||||||
|
Host: localhost (или 147.45.146.17)
|
||||||
|
Port: 6378
|
||||||
|
Password: (пусто)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **ВАРИАНТ 2: Через Docker network IP**
|
||||||
|
|
||||||
|
**Из другого контейнера в той же сети:**
|
||||||
|
```
|
||||||
|
Host: 172.24.0.4
|
||||||
|
Port: 6379
|
||||||
|
Password: (пусто)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **ВАРИАНТ 3: Из самого хоста (если в той же сети)**
|
||||||
|
|
||||||
|
**Если хост в той же Docker сети:**
|
||||||
|
```
|
||||||
|
Host: 172.24.0.4
|
||||||
|
Port: 6379
|
||||||
|
Password: (пусто)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Каналы Redis для подписки
|
||||||
|
|
||||||
|
### **Главный канал для файловых изменений:**
|
||||||
|
```
|
||||||
|
notify_storage_update
|
||||||
|
```
|
||||||
|
Этот канал публикует события когда:
|
||||||
|
- Файл создан/удалён/переименован
|
||||||
|
- Папка создана/удалена/переименована
|
||||||
|
|
||||||
|
### **Другие полезные каналы:**
|
||||||
|
```
|
||||||
|
notify_activity # Общая активность
|
||||||
|
notify_notification # Уведомления пользователей
|
||||||
|
notify_pre_auth # Пред-аутентификация
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Тест подключения
|
||||||
|
|
||||||
|
### **Из командной строки:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Подключиться к Redis через docker exec:
|
||||||
|
docker exec -it nextcloud-redis redis-cli
|
||||||
|
|
||||||
|
# Или если порт проброшен:
|
||||||
|
redis-cli -h localhost -p 6378
|
||||||
|
```
|
||||||
|
|
||||||
|
**Тест подписки на канал:**
|
||||||
|
```redis
|
||||||
|
SUBSCRIBE notify_storage_update
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Формат сообщений
|
||||||
|
|
||||||
|
Сообщения в канале `notify_storage_update` имеют формат:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "notify_storage_update",
|
||||||
|
"path": "/admin/files/Documents/Projects/Проект_390983/файл_395695.docx",
|
||||||
|
"user": "admin",
|
||||||
|
"action": "write" | "delete" | "rename",
|
||||||
|
"oldPath": "...", // только для rename
|
||||||
|
"timestamp": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Для n8n подключения
|
||||||
|
|
||||||
|
**Настройки в n8n:**
|
||||||
|
```
|
||||||
|
Host: 172.24.0.4 (или localhost:6378 если проброшен порт)
|
||||||
|
Port: 6379 (или 6378 если проброшен)
|
||||||
|
Password: (оставить пустым)
|
||||||
|
Database: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Триггер:**
|
||||||
|
- Использовать "Redis Trigger" ноду
|
||||||
|
- Channel: `notify_storage_update`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Для нашего Node.js listener
|
||||||
|
|
||||||
|
**Обновить `nextcloud_listener.js`:**
|
||||||
|
```javascript
|
||||||
|
const redis = new Redis({
|
||||||
|
host: '172.24.0.4', // или localhost если проброшен порт
|
||||||
|
port: 6379, // или 6378 если проброшен
|
||||||
|
password: '' // пусто
|
||||||
|
});
|
||||||
|
|
||||||
|
redis.subscribe('notify_storage_update');
|
||||||
|
redis.on('message', (channel, message) => {
|
||||||
|
const event = JSON.parse(message);
|
||||||
|
// Обработка события
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ ВАЖНО
|
||||||
|
|
||||||
|
1. **Безопасность:** Redis БЕЗ пароля доступен только из Docker сети!
|
||||||
|
2. **Если нужен доступ снаружи:** Обязательно установи пароль!
|
||||||
|
3. **Мониторинг:** Следи за нагрузкой на Redis при подписке на каналы
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Рекомендация: Установить пароль
|
||||||
|
|
||||||
|
Если планируешь пробрасывать порт наружу:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec nextcloud-redis redis-cli CONFIG SET requirepass "ваш_пароль"
|
||||||
|
```
|
||||||
|
|
||||||
|
И добавить в Nextcloud config.php:
|
||||||
|
```php
|
||||||
|
'redis' => array (
|
||||||
|
'atype' => 'redis',
|
||||||
|
'host' => 'nextcloud-redis',
|
||||||
|
'port' => 6379,
|
||||||
|
'password' => 'ваш_пароль',
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
182
crm_extensions/file_storage/PRODUCTION_READY.md
Normal file
182
crm_extensions/file_storage/PRODUCTION_READY.md
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
# 🎉 PRODUCTION READY - Мониторинг файлов
|
||||||
|
|
||||||
|
## ✅ ЧТО РАБОТАЕТ:
|
||||||
|
|
||||||
|
### 1️⃣ Nextcloud Activity Monitor
|
||||||
|
**Скрипт:** `nextcloud_activity_monitor.js`
|
||||||
|
**Запущен:** ✅ (PID: 2122)
|
||||||
|
**Лог:** `nextcloud_activity.log`
|
||||||
|
|
||||||
|
**Мониторит:**
|
||||||
|
- Файлы загруженные через Nextcloud WebUI
|
||||||
|
- Файлы созданные/изменённые в Nextcloud
|
||||||
|
|
||||||
|
**Метод:**
|
||||||
|
- Nextcloud Activity API (polling каждые 30 сек)
|
||||||
|
- Разбивает агрегированные события на отдельные файлы
|
||||||
|
- БЕЗ дубликатов!
|
||||||
|
|
||||||
|
**Формат события:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created",
|
||||||
|
"source": "nextcloud_activity",
|
||||||
|
"timestamp": "2025-10-30T12:53:40+00:00",
|
||||||
|
"file_id": 73460,
|
||||||
|
"path": "/experimental_report.xlsx",
|
||||||
|
"filename": "experimental_report.xlsx",
|
||||||
|
"user": "admin",
|
||||||
|
"action": "created"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Команды:**
|
||||||
|
```bash
|
||||||
|
# Статус
|
||||||
|
ps aux | grep nextcloud_activity_monitor
|
||||||
|
|
||||||
|
# Логи
|
||||||
|
tail -f nextcloud_activity.log
|
||||||
|
|
||||||
|
# Остановить
|
||||||
|
pkill -f nextcloud_activity_monitor.js
|
||||||
|
|
||||||
|
# Запустить
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
|
||||||
|
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2️⃣ S3 Monitor (Docker)
|
||||||
|
**Контейнер:** `s3-monitor`
|
||||||
|
**Запущен:** ✅ (Up 40 минут)
|
||||||
|
**Скрипт:** `s3_monitor_docker.js`
|
||||||
|
|
||||||
|
**Мониторит:**
|
||||||
|
- Файлы загруженные напрямую в S3
|
||||||
|
- Через S3 Browser, aws-cli, Cyberduck, скрипты
|
||||||
|
- Любые изменения в bucket
|
||||||
|
|
||||||
|
**Метод:**
|
||||||
|
- S3 ListObjectsV2 API (polling каждые 30 сек)
|
||||||
|
- Pagination - получает ВСЕ файлы (24,522 файла!)
|
||||||
|
- Сравнение по ETag
|
||||||
|
|
||||||
|
**Bucket:** `f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c`
|
||||||
|
|
||||||
|
**Формат события:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created",
|
||||||
|
"source": "s3_monitor",
|
||||||
|
"timestamp": "2025-10-30T20:49:31.593Z",
|
||||||
|
"path": "crm2/CRM_Active_Files/Documents/file.xlsx",
|
||||||
|
"filename": "file.xlsx",
|
||||||
|
"size": 8224,
|
||||||
|
"etag": "7004954627252c9d0a7e6417f8325d07",
|
||||||
|
"last_modified": "2025-10-30T20:49:14.132Z",
|
||||||
|
"action": "created"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Команды:**
|
||||||
|
```bash
|
||||||
|
# Статус
|
||||||
|
docker ps | grep s3-monitor
|
||||||
|
|
||||||
|
# Логи
|
||||||
|
docker logs s3-monitor -f
|
||||||
|
|
||||||
|
# Остановить
|
||||||
|
docker stop s3-monitor
|
||||||
|
|
||||||
|
# Запустить
|
||||||
|
docker start s3-monitor
|
||||||
|
|
||||||
|
# Перезапустить
|
||||||
|
docker restart s3-monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3️⃣ Redis Канал (центральная шина)
|
||||||
|
**Host:** `147.45.146.17`
|
||||||
|
**Port:** `6379`
|
||||||
|
**Password:** `CRM_Redis_Pass_2025_Secure!`
|
||||||
|
**Channel:** `crm:file:events`
|
||||||
|
|
||||||
|
**Подписаться:**
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚫 ЧТО ОСТАНОВЛЕНО:
|
||||||
|
|
||||||
|
### ❌ redis_bridge.js
|
||||||
|
**Причина:** Давал неполные данные, много дубликатов
|
||||||
|
**Заменён на:** Nextcloud Activity Monitor (даёт чистые данные)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 СРАВНЕНИЕ ДАННЫХ:
|
||||||
|
|
||||||
|
| Поле | Nextcloud Activity | S3 Monitor |
|
||||||
|
|------|-------------------|------------|
|
||||||
|
| **type** | ✅ file_created/changed/deleted | ✅ file_created/modified/deleted |
|
||||||
|
| **source** | nextcloud_activity | s3_monitor |
|
||||||
|
| **filename** | ✅ | ✅ |
|
||||||
|
| **path** | ✅ (Nextcloud путь) | ✅ (S3 полный путь) |
|
||||||
|
| **file_id** | ✅ | ❌ |
|
||||||
|
| **user** | ✅ | ❌ |
|
||||||
|
| **size** | ❌ | ✅ |
|
||||||
|
| **etag** | ❌ | ✅ |
|
||||||
|
| **mime_type** | ❌ | ❌ |
|
||||||
|
|
||||||
|
**Дополняют друг друга!** 🎯
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 АВТОЗАПУСК ПРИ ПЕРЕЗАГРУЗКЕ СЕРВЕРА:
|
||||||
|
|
||||||
|
### S3 Monitor:
|
||||||
|
✅ Уже настроен (`--restart unless-stopped`)
|
||||||
|
|
||||||
|
### Nextcloud Activity Monitor:
|
||||||
|
Создам systemd service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo tee /etc/systemd/system/nextcloud-activity-monitor.service << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Nextcloud Activity Monitor
|
||||||
|
After=network.target redis.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
|
||||||
|
ExecStart=/usr/bin/nodejs nextcloud_activity_monitor.js
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=append:/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/nextcloud_activity.log
|
||||||
|
StandardError=append:/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/nextcloud_activity.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable nextcloud-activity-monitor
|
||||||
|
sudo systemctl start nextcloud-activity-monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ГОТОВО!
|
||||||
|
|
||||||
|
**Система полностью работает в production режиме!** 🚀
|
||||||
|
|
||||||
|
Хочешь чтобы я создал systemd service для автозапуска Nextcloud Activity Monitor? 😊
|
||||||
104
crm_extensions/file_storage/QUICK_START.md
Normal file
104
crm_extensions/file_storage/QUICK_START.md
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# ⚡ Quick Start - Мониторинг файлов
|
||||||
|
|
||||||
|
## 🎯 Быстрая проверка системы
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash START.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Покажет статус всех компонентов и запустит остановленные.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Что работает прямо сейчас:
|
||||||
|
|
||||||
|
### ✅ Nextcloud Activity Monitor
|
||||||
|
- **PID:** 2122
|
||||||
|
- **Лог:** `nextcloud_activity.log`
|
||||||
|
- **Что делает:** Ловит файлы из Nextcloud WebUI
|
||||||
|
- **Задержка:** 30 сек
|
||||||
|
|
||||||
|
### ✅ S3 Monitor (Docker)
|
||||||
|
- **Контейнер:** `s3-monitor`
|
||||||
|
- **Uptime:** 40+ минут
|
||||||
|
- **Что делает:** Ловит файлы загруженные напрямую в S3
|
||||||
|
- **Задержка:** 30 сек
|
||||||
|
- **Файлов:** 24,522
|
||||||
|
|
||||||
|
### ✅ Redis канал
|
||||||
|
- **Адрес:** `147.45.146.17:6379`
|
||||||
|
- **Канал:** `crm:file:events`
|
||||||
|
- **Статус:** Оба монитора публикуют события ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Быстрый тест
|
||||||
|
|
||||||
|
### Тест 1: Загрузи файл в Nextcloud
|
||||||
|
```bash
|
||||||
|
# В другом терминале подпишись на события
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
Загрузи файл через Nextcloud WebUI → через 30 сек увидишь событие!
|
||||||
|
|
||||||
|
### Тест 2: Загрузи файл в S3
|
||||||
|
```bash
|
||||||
|
echo "test" > /tmp/test.txt
|
||||||
|
aws s3 cp /tmp/test.txt \
|
||||||
|
s3://f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/test_$(date +%s).txt \
|
||||||
|
--endpoint-url https://s3.twcstorage.ru
|
||||||
|
```
|
||||||
|
|
||||||
|
Через 0-30 сек увидишь событие!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Команды управления
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Проверка статуса
|
||||||
|
bash START.sh
|
||||||
|
|
||||||
|
# Логи в реальном времени
|
||||||
|
tail -f nextcloud_activity.log
|
||||||
|
docker logs s3-monitor -f
|
||||||
|
|
||||||
|
# Остановка
|
||||||
|
pkill -f nextcloud_activity_monitor.js
|
||||||
|
docker stop s3-monitor
|
||||||
|
|
||||||
|
# Запуск
|
||||||
|
bash START.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Документация
|
||||||
|
|
||||||
|
- `README.md` - обзор системы
|
||||||
|
- `PRODUCTION_READY.md` - production конфигурация
|
||||||
|
- `ARCHITECTURE.md` - архитектура
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Troubleshooting
|
||||||
|
|
||||||
|
**Нет событий?**
|
||||||
|
1. Проверь статус: `bash START.sh`
|
||||||
|
2. Проверь логи: `tail -f nextcloud_activity.log`
|
||||||
|
3. Проверь Redis: подпишись на канал
|
||||||
|
|
||||||
|
**Много дубликатов?**
|
||||||
|
- От Nextcloud: дедупликация включена (1 событие вместо 6)
|
||||||
|
- От S3: дубликатов нет
|
||||||
|
|
||||||
|
**Нужна помощь?**
|
||||||
|
- Читай `PRODUCTION_READY.md`
|
||||||
|
- Проверяй логи
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Всё готово! 🚀**
|
||||||
|
|
||||||
137
crm_extensions/file_storage/README.md
Normal file
137
crm_extensions/file_storage/README.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# 🔔 Система мониторинга файлов CRM
|
||||||
|
|
||||||
|
Автоматический мониторинг изменений файлов в S3 и Nextcloud с публикацией событий в Redis.
|
||||||
|
|
||||||
|
## 🎯 Компоненты системы
|
||||||
|
|
||||||
|
### 1. Nextcloud Activity Monitor
|
||||||
|
**Файл:** `nextcloud_activity_monitor.js`
|
||||||
|
**Назначение:** Мониторинг файлов загруженных через Nextcloud WebUI
|
||||||
|
**Метод:** Nextcloud Activity API
|
||||||
|
**Интервал:** 30 секунд
|
||||||
|
|
||||||
|
**Запуск:**
|
||||||
|
```bash
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
|
||||||
|
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
**Управление:**
|
||||||
|
```bash
|
||||||
|
ps aux | grep nextcloud_activity_monitor # Статус
|
||||||
|
tail -f nextcloud_activity.log # Логи
|
||||||
|
pkill -f nextcloud_activity_monitor.js # Остановить
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. S3 Monitor (Docker)
|
||||||
|
**Контейнер:** `s3-monitor`
|
||||||
|
**Назначение:** Мониторинг файлов загруженных напрямую в S3
|
||||||
|
**Bucket:** `f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c`
|
||||||
|
**Интервал:** 30 секунд
|
||||||
|
**Файлов:** ~24,500
|
||||||
|
|
||||||
|
**Управление:**
|
||||||
|
```bash
|
||||||
|
docker ps | grep s3-monitor # Статус
|
||||||
|
docker logs s3-monitor -f # Логи
|
||||||
|
docker stop s3-monitor # Остановить
|
||||||
|
docker start s3-monitor # Запустить
|
||||||
|
docker restart s3-monitor # Перезапустить
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Redis (центральная шина событий)
|
||||||
|
**Адрес:** `147.45.146.17:6379`
|
||||||
|
**Канал:** `crm:file:events`
|
||||||
|
**Password:** `CRM_Redis_Pass_2025_Secure!`
|
||||||
|
|
||||||
|
**Подписка:**
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Формат событий
|
||||||
|
|
||||||
|
### От Nextcloud Activity Monitor:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created",
|
||||||
|
"source": "nextcloud_activity",
|
||||||
|
"timestamp": "2025-10-30T12:53:40+00:00",
|
||||||
|
"file_id": 73460,
|
||||||
|
"path": "/experimental_report.xlsx",
|
||||||
|
"filename": "experimental_report.xlsx",
|
||||||
|
"user": "admin",
|
||||||
|
"action": "created"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### От S3 Monitor:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created",
|
||||||
|
"source": "s3_monitor",
|
||||||
|
"timestamp": "2025-10-30T20:49:31.593Z",
|
||||||
|
"path": "crm2/CRM_Active_Files/Documents/file.xlsx",
|
||||||
|
"filename": "file.xlsx",
|
||||||
|
"size": 8224,
|
||||||
|
"etag": "7004954627252c9d0a7e6417f8325d07",
|
||||||
|
"last_modified": "2025-10-30T20:49:14.132Z",
|
||||||
|
"action": "created"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Credentials
|
||||||
|
|
||||||
|
### Nextcloud API:
|
||||||
|
```
|
||||||
|
URL: https://office.clientright.ru:8443
|
||||||
|
User: admin
|
||||||
|
App Password: tGHKS-3cC9m-7Hggb-65Awk-zxWQE
|
||||||
|
```
|
||||||
|
|
||||||
|
### S3 (TWC Storage):
|
||||||
|
```
|
||||||
|
Endpoint: https://s3.twcstorage.ru
|
||||||
|
Region: ru-1
|
||||||
|
Access Key: 2OMAK5ZNM900TAXM16J7
|
||||||
|
Secret Key: f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG
|
||||||
|
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Дополнительные документы
|
||||||
|
|
||||||
|
- `PRODUCTION_READY.md` - полное описание production конфигурации
|
||||||
|
- `ARCHITECTURE.md` - схема архитектуры системы
|
||||||
|
- `S3_MONITORING_GUIDE.md` - руководство по S3 мониторингу
|
||||||
|
- `NEXTCLOUD_API_OVERVIEW.md` - обзор Nextcloud API
|
||||||
|
- `SETUP_CHECKLIST.md` - чек-лист настройки
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Для разработчиков
|
||||||
|
|
||||||
|
### n8n Workflows (готовые для импорта):
|
||||||
|
- `n8n_s3_event_processor.json` - обработчик событий из Redis
|
||||||
|
- `n8n_nextcloud_activity_monitor.json` - альтернатива через n8n
|
||||||
|
- `n8n_s3_monitor_workflow.json` - альтернатива S3 Monitor через n8n
|
||||||
|
|
||||||
|
### Утилиты:
|
||||||
|
- `get_s3_credentials.sh` - получение S3 credentials
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Дата создания:** 30 октября 2025
|
||||||
|
**Версия:** 1.0
|
||||||
|
**Статус:** Production Ready ✅
|
||||||
|
|
||||||
248
crm_extensions/file_storage/S3_MONITORING_GUIDE.md
Normal file
248
crm_extensions/file_storage/S3_MONITORING_GUIDE.md
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
# 🔍 Руководство по мониторингу S3
|
||||||
|
|
||||||
|
## Проблема
|
||||||
|
Тебе нужно ловить **любые** изменения файлов в S3 bucket, даже если они загружены:
|
||||||
|
- Вручную через S3 Browser / Cyberduck
|
||||||
|
- Из внешних скриптов
|
||||||
|
- Не через CRM или Nextcloud
|
||||||
|
|
||||||
|
## ❌ Почему не Event Notifications?
|
||||||
|
TWC Storage **не поддерживает** S3 Event Notifications официально (не документировано).
|
||||||
|
|
||||||
|
## ✅ РЕШЕНИЕ: n8n Workflow с Polling
|
||||||
|
|
||||||
|
### Как работает:
|
||||||
|
```
|
||||||
|
n8n каждые 30 сек → Список файлов в S3 → Сравнение с предыдущим состоянием →
|
||||||
|
→ Обнаружены изменения → Публикация в Redis → Твои обработчики
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Пошаговая инструкция
|
||||||
|
|
||||||
|
### Шаг 1: Импортируй workflow в n8n
|
||||||
|
|
||||||
|
1. Открой n8n: https://n8n.clientright.pro
|
||||||
|
2. Создай новый workflow
|
||||||
|
3. Нажми **Import from File**
|
||||||
|
4. Загрузи файл: `n8n_s3_monitor_workflow.json`
|
||||||
|
|
||||||
|
### Шаг 2: Настрой S3 Credentials
|
||||||
|
|
||||||
|
В n8n создай credentials:
|
||||||
|
|
||||||
|
**Тип:** AWS S3
|
||||||
|
**Имя:** `TWC S3`
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
```
|
||||||
|
Access Key ID: [твой S3 ключ из Nextcloud]
|
||||||
|
Secret Access Key: [твой S3 секрет из Nextcloud]
|
||||||
|
Region: ru-1
|
||||||
|
|
||||||
|
Custom Endpoints: ✅ (включить!)
|
||||||
|
S3 Endpoint: https://s3.twcstorage.ru
|
||||||
|
Force Path Style: ✅ (включить!)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Как получить ключи:**
|
||||||
|
```bash
|
||||||
|
docker exec nextcloud-fresh php occ files_external:list --output=json | jq -r '.[0].configuration | "Key: \(.key)\nSecret: \(.secret)\nBucket: \(.bucket)"'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 3: Настрой Redis Credentials
|
||||||
|
|
||||||
|
**Тип:** Redis
|
||||||
|
**Имя:** `CRM Redis`
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
```
|
||||||
|
Host: 147.45.146.17
|
||||||
|
Port: 6379
|
||||||
|
Password: CRM_Redis_Pass_2025_Secure!
|
||||||
|
Database: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 4: Настрой Environment Variables (если нужно)
|
||||||
|
|
||||||
|
В n8n Settings → Environment Variables:
|
||||||
|
```
|
||||||
|
S3_BUCKET=f9825c87-18698658-c378-4aa7-91cc-0c131bebccda
|
||||||
|
WEBHOOK_URL=https://твой-эндпоинт.com/webhook (опционально)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 5: Настрой Bucket и Prefix
|
||||||
|
|
||||||
|
В ноде **List S3 Files**:
|
||||||
|
- `Bucket Name`: укажи свой bucket (или используй `{{$env.S3_BUCKET}}`)
|
||||||
|
- `Prefix`: укажи папку для мониторинга (например `nextcloud/data/admin/files/`)
|
||||||
|
- Оставь пустым для мониторинга всего bucket
|
||||||
|
|
||||||
|
### Шаг 6: Активируй Workflow
|
||||||
|
|
||||||
|
1. Нажми **Active** (включи workflow)
|
||||||
|
2. Первый запуск создаст начальное состояние файлов
|
||||||
|
3. Последующие запуски будут сравнивать с предыдущим состоянием
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Тестирование
|
||||||
|
|
||||||
|
### 1. Загрузи тестовый файл в S3
|
||||||
|
|
||||||
|
Через S3 Browser, Cyberduck или aws-cli:
|
||||||
|
```bash
|
||||||
|
echo "test" > test.txt
|
||||||
|
aws s3 cp test.txt s3://твой-bucket/test.txt \
|
||||||
|
--endpoint-url https://s3.twcstorage.ru
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Подожди 30 секунд (интервал polling)
|
||||||
|
|
||||||
|
### 3. Проверь Redis
|
||||||
|
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
Должно прийти:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "file_created",
|
||||||
|
"source": "s3_monitor",
|
||||||
|
"timestamp": "2025-10-30T12:34:56Z",
|
||||||
|
"path": "test.txt",
|
||||||
|
"filename": "test.txt",
|
||||||
|
"size": 5,
|
||||||
|
"etag": "\"098f6bcd4621d373cade4e832627b4f6\"",
|
||||||
|
"last_modified": "2025-10-30T12:34:50Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Настройка интервала
|
||||||
|
|
||||||
|
Измени интервал проверки в ноде **"Каждые 30 секунд"**:
|
||||||
|
|
||||||
|
- **10 секунд** - почти реал-тайм, но больше нагрузка на S3 API
|
||||||
|
- **30 секунд** - оптимальный баланс (рекомендуется)
|
||||||
|
- **60 секунд** - экономия API запросов
|
||||||
|
|
||||||
|
**Важно:** TWC может лимитировать количество API запросов!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Типы событий
|
||||||
|
|
||||||
|
Workflow генерирует 3 типа событий:
|
||||||
|
|
||||||
|
1. **`file_created`** - новый файл появился в bucket
|
||||||
|
2. **`file_modified`** - файл изменился (другой ETag)
|
||||||
|
3. **`file_deleted`** - файл удалён из bucket
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Обработка событий в других workflows
|
||||||
|
|
||||||
|
Создай новый workflow в n8n:
|
||||||
|
|
||||||
|
### Trigger: Redis (Subscribe)
|
||||||
|
```
|
||||||
|
Host: 147.45.146.17
|
||||||
|
Port: 6379
|
||||||
|
Password: CRM_Redis_Pass_2025_Secure!
|
||||||
|
Channel: crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filter: По типу события
|
||||||
|
```javascript
|
||||||
|
// Обрабатываем только создание файлов
|
||||||
|
return $json.type === 'file_created';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Switch: По расширению файла
|
||||||
|
```javascript
|
||||||
|
const ext = $json.filename.split('.').pop().toLowerCase();
|
||||||
|
|
||||||
|
switch(ext) {
|
||||||
|
case 'pdf':
|
||||||
|
return [0]; // Обработка PDF
|
||||||
|
case 'jpg':
|
||||||
|
case 'png':
|
||||||
|
return [1]; // Обработка изображений
|
||||||
|
case 'xlsx':
|
||||||
|
case 'csv':
|
||||||
|
return [2]; // Обработка таблиц
|
||||||
|
default:
|
||||||
|
return [3]; // Остальные файлы
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Пример: Автоматическая обработка ERV файлов
|
||||||
|
|
||||||
|
```
|
||||||
|
Redis Subscribe (crm:file:events) →
|
||||||
|
→ Filter (filename contains "erv") →
|
||||||
|
→ Download from S3 →
|
||||||
|
→ Process ERV →
|
||||||
|
→ Upload to CRM →
|
||||||
|
→ Notify user
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Мониторинг нескольких buckets
|
||||||
|
|
||||||
|
Если тебе нужно мониторить несколько buckets:
|
||||||
|
|
||||||
|
1. **Вариант 1:** Создай отдельный workflow для каждого bucket
|
||||||
|
2. **Вариант 2:** Используй Loop в workflow для перебора buckets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Важные замечания
|
||||||
|
|
||||||
|
1. **State сохраняется в Static Data** - не удаляй workflow без экспорта!
|
||||||
|
2. **Первый запуск не генерирует события** - только создаёт начальное состояние
|
||||||
|
3. **ETag используется для определения изменений** - если файл перезаписан с тем же содержимым, событие не сработает
|
||||||
|
4. **Polling = задержка** - событие придёт через 0-30 секунд после реального изменения
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Troubleshooting
|
||||||
|
|
||||||
|
### Проблема: Не приходят события
|
||||||
|
- Проверь что workflow **Active** (зелёная галочка)
|
||||||
|
- Проверь логи workflow (Execute → View executions)
|
||||||
|
- Проверь credentials (S3 и Redis)
|
||||||
|
|
||||||
|
### Проблема: Слишком много событий
|
||||||
|
- Уменьши область мониторинга через `Prefix`
|
||||||
|
- Увеличь интервал polling до 60-120 секунд
|
||||||
|
|
||||||
|
### Проблема: Пропускаются изменения
|
||||||
|
- Уменьши интервал до 10-15 секунд
|
||||||
|
- Проверь что State сохраняется (Static Data)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Дополнительные материалы
|
||||||
|
|
||||||
|
- [n8n AWS S3 Node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awss3/)
|
||||||
|
- [n8n Redis Node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.redis/)
|
||||||
|
- [n8n Code Node](https://docs.n8n.io/code-examples/methods-variables-reference/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Готово!
|
||||||
|
|
||||||
|
Теперь у тебя есть полноценный мониторинг S3 bucket в реальном времени!
|
||||||
|
|
||||||
|
Все изменения файлов будут автоматически публиковаться в Redis канал `crm:file:events`,
|
||||||
|
откуда их могут подхватить другие твои системы (CRM, другие n8n workflows, и т.д.)
|
||||||
|
|
||||||
228
crm_extensions/file_storage/SETUP_CHECKLIST.md
Normal file
228
crm_extensions/file_storage/SETUP_CHECKLIST.md
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
# ✅ Чек-лист настройки S3 мониторинга
|
||||||
|
|
||||||
|
## 📋 Что нужно сделать
|
||||||
|
|
||||||
|
### Шаг 1: Получи S3 Credentials ✅
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
|
||||||
|
bash get_s3_credentials.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Сохрани куда-нибудь:**
|
||||||
|
- Access Key ID
|
||||||
|
- Secret Access Key
|
||||||
|
- Bucket name
|
||||||
|
- Endpoint: `https://s3.twcstorage.ru`
|
||||||
|
- Region: `ru-1`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 2: Импортируй workflow в n8n ⏳
|
||||||
|
|
||||||
|
1. Открой https://n8n.clientright.pro
|
||||||
|
2. Нажми **"+"** → **Import from File**
|
||||||
|
3. Выбери файл: `/var/www/.../n8n_s3_monitor_workflow.json`
|
||||||
|
4. Нажми **Import**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 3: Настрой S3 Credentials в n8n ⏳
|
||||||
|
|
||||||
|
1. В n8n иди в **Settings** (⚙️) → **Credentials**
|
||||||
|
2. Нажми **Add Credential** → выбери **AWS**
|
||||||
|
3. Заполни:
|
||||||
|
- **Name:** `TWC S3`
|
||||||
|
- **Access Key ID:** (из шага 1)
|
||||||
|
- **Secret Access Key:** (из шага 1)
|
||||||
|
- **Region:** `ru-1`
|
||||||
|
|
||||||
|
4. **Включи** `Custom Endpoints` ✅
|
||||||
|
5. **S3 Endpoint:** `https://s3.twcstorage.ru`
|
||||||
|
6. **Включи** `Force Path Style` ✅
|
||||||
|
7. Нажми **Test** → должно быть ✅
|
||||||
|
8. **Save**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 4: Настрой Redis Credentials в n8n ⏳
|
||||||
|
|
||||||
|
1. **Add Credential** → **Redis**
|
||||||
|
2. Заполни:
|
||||||
|
- **Name:** `CRM Redis`
|
||||||
|
- **Host:** `147.45.146.17`
|
||||||
|
- **Port:** `6379`
|
||||||
|
- **Password:** `CRM_Redis_Pass_2025_Secure!`
|
||||||
|
- **Database:** `0`
|
||||||
|
3. **Test** → ✅
|
||||||
|
4. **Save**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 5: Настрой workflow ⏳
|
||||||
|
|
||||||
|
1. Открой импортированный workflow **"S3 File Monitor"**
|
||||||
|
2. Кликни на ноду **"List S3 Files"**
|
||||||
|
3. В поле **Credential for AWS** выбери `TWC S3`
|
||||||
|
4. В поле **Bucket Name:**
|
||||||
|
- Вариант 1: Впиши имя bucket из шага 1
|
||||||
|
- Вариант 2: Оставь `{{$env.S3_BUCKET}}` и настрой env variable
|
||||||
|
5. В поле **Prefix** (опционально):
|
||||||
|
- Оставь пустым для мониторинга всего bucket
|
||||||
|
- Или укажи папку, например: `nextcloud/data/admin/files/`
|
||||||
|
|
||||||
|
6. Кликни на ноду **"Publish to Redis"**
|
||||||
|
7. Выбери credential: `CRM Redis`
|
||||||
|
|
||||||
|
8. **Save** workflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 6: Активируй workflow ⏳
|
||||||
|
|
||||||
|
1. Переключи тумблер **Active** в ON (вверху справа)
|
||||||
|
2. Workflow начнёт работать!
|
||||||
|
|
||||||
|
**Первый запуск:**
|
||||||
|
- Создаст начальное состояние файлов
|
||||||
|
- **НЕ** сгенерирует события (это нормально!)
|
||||||
|
|
||||||
|
**Последующие запуски (каждые 30 сек):**
|
||||||
|
- Будут сравнивать с предыдущим состоянием
|
||||||
|
- Генерировать события при изменениях
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 7: Протестируй! 🧪
|
||||||
|
|
||||||
|
#### Тест 1: Загрузи файл в S3
|
||||||
|
|
||||||
|
Через **S3 Browser** или **aws-cli**:
|
||||||
|
```bash
|
||||||
|
echo "test content" > /tmp/test-file.txt
|
||||||
|
|
||||||
|
aws s3 cp /tmp/test-file.txt s3://ИМЯ-BUCKET/test-file.txt \
|
||||||
|
--endpoint-url https://s3.twcstorage.ru
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Тест 2: Подожди 30 секунд
|
||||||
|
|
||||||
|
⏱️ Время для следующего polling цикла...
|
||||||
|
|
||||||
|
#### Тест 3: Проверь Redis
|
||||||
|
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
|
||||||
|
--csv SUBSCRIBE crm:file:events
|
||||||
|
```
|
||||||
|
|
||||||
|
Должно прийти:
|
||||||
|
```
|
||||||
|
"subscribe","crm:file:events",1
|
||||||
|
"message","crm:file:events","{\"type\":\"file_created\",\"source\":\"s3_monitor\",...}"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Тест 4: Проверь n8n executions
|
||||||
|
|
||||||
|
1. В n8n → **S3 File Monitor** workflow
|
||||||
|
2. Нажми **Executions** (внизу)
|
||||||
|
3. Посмотри последние запуски
|
||||||
|
4. Должны быть ✅ зелёные
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Шаг 8: Настрой обработчик событий (опционально) ⏳
|
||||||
|
|
||||||
|
Создай новый workflow в n8n для обработки событий:
|
||||||
|
|
||||||
|
1. **Trigger:** Redis (Subscribe)
|
||||||
|
- Channel: `crm:file:events`
|
||||||
|
- Credential: `CRM Redis`
|
||||||
|
|
||||||
|
2. **Filter** по типу файла:
|
||||||
|
```javascript
|
||||||
|
// Обрабатываем только PDF
|
||||||
|
return $json.filename.endsWith('.pdf');
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Твоя логика:**
|
||||||
|
- Download from S3
|
||||||
|
- Process
|
||||||
|
- Upload to CRM
|
||||||
|
- Notify user
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Troubleshooting
|
||||||
|
|
||||||
|
### ❌ Workflow не запускается
|
||||||
|
- Проверь что он **Active** (зелёная галочка)
|
||||||
|
- Проверь Executions → есть ли ошибки?
|
||||||
|
|
||||||
|
### ❌ S3 Connection failed
|
||||||
|
- Проверь credentials (Access Key, Secret)
|
||||||
|
- Проверь что включен `Force Path Style` ✅
|
||||||
|
- Проверь endpoint: `https://s3.twcstorage.ru`
|
||||||
|
|
||||||
|
### ❌ Redis Connection failed
|
||||||
|
- Проверь firewall: порт 6379 открыт?
|
||||||
|
- Проверь пароль: `CRM_Redis_Pass_2025_Secure!`
|
||||||
|
- Попробуй из терминала:
|
||||||
|
```bash
|
||||||
|
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' PING
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ События не приходят
|
||||||
|
- Убедись что файл добавлен **в правильный bucket**
|
||||||
|
- Убедись что файл **в нужной папке** (если указан Prefix)
|
||||||
|
- Подожди 30 секунд для polling цикла
|
||||||
|
- Проверь Static Data в workflow (сохраняется ли состояние?)
|
||||||
|
|
||||||
|
### ⚠️ Слишком много событий
|
||||||
|
- Уменьши область мониторинга через `Prefix`
|
||||||
|
- Увеличь интервал до 60-120 секунд
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Финальная проверка
|
||||||
|
|
||||||
|
После всех шагов у тебя должно быть:
|
||||||
|
|
||||||
|
- ✅ S3 credentials сохранены в n8n
|
||||||
|
- ✅ Redis credentials сохранены в n8n
|
||||||
|
- ✅ Workflow "S3 File Monitor" импортирован
|
||||||
|
- ✅ Workflow активирован (Active = ON)
|
||||||
|
- ✅ Тестовый файл загружен в S3
|
||||||
|
- ✅ Событие пришло в Redis канал `crm:file:events`
|
||||||
|
- ✅ Execution в n8n показывает ✅ success
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Готово!
|
||||||
|
|
||||||
|
Теперь **любые** изменения в твоём S3 bucket будут автоматически:
|
||||||
|
1. Обнаруживаться (каждые 30 сек)
|
||||||
|
2. Публиковаться в Redis (`crm:file:events`)
|
||||||
|
3. Доступны для обработки в n8n, CRM, и других сервисах
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Дополнительные файлы
|
||||||
|
|
||||||
|
- `S3_MONITORING_GUIDE.md` - полное руководство
|
||||||
|
- `ARCHITECTURE.md` - схема архитектуры
|
||||||
|
- `n8n_s3_monitor_workflow.json` - workflow для импорта
|
||||||
|
- `get_s3_credentials.sh` - скрипт для получения credentials
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Нужна помощь?
|
||||||
|
|
||||||
|
Если что-то не работает:
|
||||||
|
1. Проверь логи n8n executions
|
||||||
|
2. Проверь Redis подключение
|
||||||
|
3. Проверь S3 credentials
|
||||||
|
4. Перечитай `S3_MONITORING_GUIDE.md`
|
||||||
|
|
||||||
|
**Удачи!** 🚀
|
||||||
|
|
||||||
76
crm_extensions/file_storage/START.sh
Executable file
76
crm_extensions/file_storage/START.sh
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Скрипт для запуска/проверки всех компонентов мониторинга файлов
|
||||||
|
#
|
||||||
|
|
||||||
|
echo "🚀 CRM File Monitoring System"
|
||||||
|
echo "════════════════════════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
|
||||||
|
|
||||||
|
# Проверка S3 Monitor
|
||||||
|
echo "1️⃣ S3 Monitor (Docker):"
|
||||||
|
if docker ps | grep -q s3-monitor; then
|
||||||
|
echo " ✅ Работает"
|
||||||
|
docker ps --format " Статус: {{.Status}}" | grep s3-monitor
|
||||||
|
else
|
||||||
|
echo " ❌ НЕ работает"
|
||||||
|
echo " Запускаем..."
|
||||||
|
docker start s3-monitor 2>/dev/null || echo " ⚠️ Контейнер не существует, запустите вручную"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка Nextcloud Activity Monitor
|
||||||
|
echo "2️⃣ Nextcloud Activity Monitor:"
|
||||||
|
if ps aux | grep -v grep | grep -q nextcloud_activity_monitor.js; then
|
||||||
|
PID=$(ps aux | grep -v grep | grep nextcloud_activity_monitor.js | awk '{print $2}')
|
||||||
|
echo " ✅ Работает (PID: $PID)"
|
||||||
|
else
|
||||||
|
echo " ❌ НЕ работает"
|
||||||
|
echo " Запускаем..."
|
||||||
|
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
|
||||||
|
sleep 2
|
||||||
|
echo " ✅ Запущен (PID: $!)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка Redis
|
||||||
|
echo "3️⃣ Redis подключение:"
|
||||||
|
if redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' PING 2>&1 | grep -q PONG; then
|
||||||
|
echo " ✅ Redis доступен"
|
||||||
|
else
|
||||||
|
echo " ❌ Redis недоступен"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "════════════════════════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
echo "📋 СТАТУС:"
|
||||||
|
echo ""
|
||||||
|
echo "Nextcloud Activity Monitor:"
|
||||||
|
tail -3 nextcloud_activity.log 2>/dev/null | tail -1
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "S3 Monitor:"
|
||||||
|
docker logs s3-monitor 2>&1 | tail -3 | tail -1
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "════════════════════════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
echo "📚 Команды:"
|
||||||
|
echo ""
|
||||||
|
echo "Логи в реальном времени:"
|
||||||
|
echo " tail -f nextcloud_activity.log"
|
||||||
|
echo " docker logs s3-monitor -f"
|
||||||
|
echo ""
|
||||||
|
echo "Подписка на события:"
|
||||||
|
echo " redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' SUBSCRIBE crm:file:events"
|
||||||
|
echo ""
|
||||||
|
echo "Документация:"
|
||||||
|
echo " cat README.md"
|
||||||
|
echo " cat PRODUCTION_READY.md"
|
||||||
|
echo ""
|
||||||
|
|
||||||
23
crm_extensions/file_storage/api/download_s3_file.php
Normal file
23
crm_extensions/file_storage/api/download_s3_file.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ПРОСТОЙ Прокси для скачивания файла из S3
|
||||||
|
* Просто отдаём публичный URL - S3 сам разберётся
|
||||||
|
*/
|
||||||
|
|
||||||
|
$s3Path = isset($_GET['path']) ? $_GET['path'] : '';
|
||||||
|
|
||||||
|
if (empty($s3Path)) {
|
||||||
|
http_response_code(400);
|
||||||
|
die('Missing path parameter');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формируем публичный S3 URL
|
||||||
|
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||||||
|
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
|
||||||
|
|
||||||
|
error_log("download_s3_file.php: Redirecting to: $s3Url");
|
||||||
|
|
||||||
|
// РЕДИРЕКТИМ на S3 напрямую
|
||||||
|
header('Location: ' . $s3Url);
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
40
crm_extensions/file_storage/api/index_file.php
Normal file
40
crm_extensions/file_storage/api/index_file.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Быстрая индексация одного файла в Nextcloud
|
||||||
|
*/
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
$path = $input['path'] ?? '';
|
||||||
|
|
||||||
|
if (empty($path)) {
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Missing path']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формируем Nextcloud путь
|
||||||
|
$ncPath = '/admin/files/crm/' . $path;
|
||||||
|
|
||||||
|
// Запускаем сканирование
|
||||||
|
$command = "docker exec -u www-data nextcloud-fresh php occ files:scan --path=" . escapeshellarg($ncPath) . " 2>&1";
|
||||||
|
|
||||||
|
exec($command, $output, $returnCode);
|
||||||
|
|
||||||
|
if ($returnCode === 0) {
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'File indexed successfully',
|
||||||
|
'output' => implode("\n", $output)
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'Indexing failed',
|
||||||
|
'output' => implode("\n", $output)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
103
crm_extensions/file_storage/api/onlyoffice_callback.php
Normal file
103
crm_extensions/file_storage/api/onlyoffice_callback.php
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* OnlyOffice Callback для сохранения файлов в S3
|
||||||
|
*/
|
||||||
|
|
||||||
|
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', 0);
|
||||||
|
|
||||||
|
// Логируем все запросы
|
||||||
|
$input = file_get_contents('php://input');
|
||||||
|
$data = json_decode($input, true);
|
||||||
|
|
||||||
|
error_log("=== ONLYOFFICE CALLBACK ===");
|
||||||
|
error_log("Method: " . $_SERVER['REQUEST_METHOD']);
|
||||||
|
error_log("Body: " . $input);
|
||||||
|
|
||||||
|
// OnlyOffice отправляет POST с JSON данными
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($data)) {
|
||||||
|
$status = $data['status'] ?? 0;
|
||||||
|
$key = $data['key'] ?? 'unknown';
|
||||||
|
|
||||||
|
error_log("Callback Status: $status, Key: $key");
|
||||||
|
|
||||||
|
// Status 2 = файл сохранён, нужно скачать и загрузить в S3
|
||||||
|
if ($status == 2 && isset($data['url'])) {
|
||||||
|
$downloadUrl = $data['url'];
|
||||||
|
error_log("File saved! Download URL: " . $downloadUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Скачиваем изменённый файл от OnlyOffice
|
||||||
|
$fileContent = file_get_contents($downloadUrl);
|
||||||
|
|
||||||
|
if ($fileContent === false) {
|
||||||
|
error_log("Failed to download file from OnlyOffice");
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 1]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Downloaded file: " . strlen($fileContent) . " bytes");
|
||||||
|
|
||||||
|
// Извлекаем путь к файлу из documentKey
|
||||||
|
// В $key хранится md5($s3Path . '_' . $version)
|
||||||
|
// Нам нужен оригинальный путь, который мы должны хранить отдельно
|
||||||
|
|
||||||
|
// ВРЕМЕННО: Сохраняем в отдельную папку в S3 для отладки
|
||||||
|
// TODO: Нужно связать documentKey с оригинальным путём файла
|
||||||
|
|
||||||
|
// Инициализируем S3 клиент
|
||||||
|
$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';
|
||||||
|
|
||||||
|
// ВРЕМЕННОЕ РЕШЕНИЕ: Сохраняем в папку /onlyoffice_saved/
|
||||||
|
$savedPath = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
|
||||||
|
|
||||||
|
$result = $s3Client->putObject([
|
||||||
|
'Bucket' => $bucket,
|
||||||
|
'Key' => $savedPath,
|
||||||
|
'Body' => $fileContent,
|
||||||
|
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||||
|
]);
|
||||||
|
|
||||||
|
error_log("File saved to S3: " . $savedPath);
|
||||||
|
error_log("S3 Response: " . json_encode($result->toArray()));
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode(['error' => 0]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Error saving file to S3: " . $e->getMessage());
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 1, 'message' => $e->getMessage()]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Другие статусы (1 = открыт, 4 = закрыт и т.д.)
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode(['error' => 0]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для всех остальных запросов - 200 OK
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode(['error' => 0]);
|
||||||
|
?>
|
||||||
|
|
||||||
121
crm_extensions/file_storage/api/onlyoffice_callback_v2.php
Normal file
121
crm_extensions/file_storage/api/onlyoffice_callback_v2.php
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* OnlyOffice Callback v2 с сохранением в оригинальный файл S3
|
||||||
|
*/
|
||||||
|
|
||||||
|
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', 0);
|
||||||
|
|
||||||
|
$input = file_get_contents('php://input');
|
||||||
|
$data = json_decode($input, true);
|
||||||
|
|
||||||
|
error_log("=== ONLYOFFICE CALLBACK V2 ===");
|
||||||
|
error_log("Body: " . $input);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($data)) {
|
||||||
|
$status = $data['status'] ?? 0;
|
||||||
|
$key = $data['key'] ?? 'unknown';
|
||||||
|
|
||||||
|
error_log("Status: $status, Key: $key");
|
||||||
|
|
||||||
|
// Status 2 = файл сохранён, нужно скачать и загрузить в S3
|
||||||
|
if ($status == 2 && isset($data['url'])) {
|
||||||
|
$downloadUrl = $data['url'];
|
||||||
|
error_log("File saved! Downloading from: " . $downloadUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Подключаемся к Redis чтобы узнать оригинальный путь
|
||||||
|
$redis = new Predis\Client([
|
||||||
|
'scheme' => 'tcp',
|
||||||
|
'host' => EnvLoader::getRequired('REDIS_HOST'),
|
||||||
|
'port' => (int)EnvLoader::getRequired('REDIS_PORT'),
|
||||||
|
'password' => EnvLoader::getRequired('REDIS_PASSWORD')
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Получаем маппинг
|
||||||
|
$mapping = $redis->get("crm:onlyoffice:key:$key");
|
||||||
|
|
||||||
|
if (!$mapping) {
|
||||||
|
error_log("ERROR: No mapping found for key $key");
|
||||||
|
// Сохраняем в резервную папку
|
||||||
|
$s3Path = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
|
||||||
|
} else {
|
||||||
|
$mappingData = json_decode($mapping, true);
|
||||||
|
$s3Path = $mappingData['s3_path'];
|
||||||
|
error_log("Found mapping: $key → $s3Path");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Скачиваем файл от OnlyOffice
|
||||||
|
$fileContent = file_get_contents($downloadUrl);
|
||||||
|
|
||||||
|
if ($fileContent === false) {
|
||||||
|
throw new Exception("Failed to download file from OnlyOffice");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Downloaded: " . strlen($fileContent) . " bytes");
|
||||||
|
|
||||||
|
// Инициализируем S3 клиент
|
||||||
|
$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';
|
||||||
|
|
||||||
|
// Загружаем в S3 (ПЕРЕЗАПИСЫВАЕМ оригинальный файл!)
|
||||||
|
$result = $s3Client->putObject([
|
||||||
|
'Bucket' => $bucket,
|
||||||
|
'Key' => $s3Path,
|
||||||
|
'Body' => $fileContent,
|
||||||
|
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'Metadata' => [
|
||||||
|
'saved_by' => 'onlyoffice',
|
||||||
|
'saved_at' => date('Y-m-d H:i:s')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
error_log("✅ File saved to S3: $s3Path");
|
||||||
|
|
||||||
|
// Публикуем событие в Redis
|
||||||
|
$redis->publish('crm:file:events', json_encode([
|
||||||
|
'type' => 'file_modified',
|
||||||
|
'source' => 'onlyoffice',
|
||||||
|
'timestamp' => date('c'),
|
||||||
|
'path' => $s3Path,
|
||||||
|
'size' => strlen($fileContent),
|
||||||
|
'action' => 'updated_via_onlyoffice'
|
||||||
|
]));
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode(['error' => 0]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("ERROR: " . $e->getMessage());
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 1, 'message' => $e->getMessage()]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Другие статусы
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode(['error' => 0]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode(['error' => 0]);
|
||||||
|
?>
|
||||||
|
|
||||||
@@ -1,110 +1,237 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Простой редирект на файл в Nextcloud БЕЗ CSRF проверок
|
* ФИНАЛ: OnlyOffice + Pre-signed S3 URL
|
||||||
* Использует FilePathManager для новой структуры файлов
|
* Теперь с CORS и правильными настройками!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Включаем отображение ошибок
|
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);
|
error_reporting(E_ALL);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
|
|
||||||
// Подключаем конфигурацию и FilePathManager
|
|
||||||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
|
|
||||||
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/FilePathManager.php';
|
|
||||||
|
|
||||||
// Получаем параметры
|
|
||||||
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
|
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
|
||||||
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
|
|
||||||
|
|
||||||
// Если fileName содержит полный URL S3, извлекаем путь к файлу
|
if (empty($fileName)) {
|
||||||
$ncPath = '';
|
die("❌ fileName не указан");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Извлекаем S3 путь
|
||||||
|
$s3Path = '';
|
||||||
if (strpos($fileName, 'http') === 0) {
|
if (strpos($fileName, 'http') === 0) {
|
||||||
// Декодируем URL
|
|
||||||
$fileName = urldecode($fileName);
|
$fileName = urldecode($fileName);
|
||||||
|
|
||||||
// Извлекаем путь после bucket ID
|
|
||||||
// Формат: https://s3.twcstorage.ru/BUCKET_ID/crm2/CRM_Active_Files/...
|
|
||||||
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||||||
$pos = strpos($fileName, $bucketId . '/');
|
$pos = strpos($fileName, $bucketId . '/');
|
||||||
if ($pos !== false) {
|
if ($pos !== false) {
|
||||||
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
|
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
|
||||||
|
|
||||||
// Nextcloud путь = /crm/ + s3_path
|
|
||||||
$ncPath = '/crm/' . $s3Path;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($ncPath)) {
|
if (empty($s3Path)) {
|
||||||
die("❌ Ошибка: Не удалось извлечь путь из URL: $fileName");
|
die("❌ Не удалось извлечь путь из URL");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Настройки Nextcloud
|
// Извлекаем расширение файла
|
||||||
$nextcloudUrl = 'https://office.clientright.ru:8443';
|
$ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
|
||||||
$username = 'admin';
|
|
||||||
$password = 'office';
|
|
||||||
|
|
||||||
// Вспомогательная функция: кодирование пути по сегментам (WebDAV)
|
// ПРЯМОЙ S3 URL (bucket публичный, CORS настроен!)
|
||||||
$encodePath = function(array $segments) {
|
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||||||
return implode('/', array_map('rawurlencode', $segments));
|
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
|
||||||
};
|
|
||||||
|
|
||||||
// Получаем fileId через WebDAV PROPFIND
|
// Генерируем версию и ключ документа
|
||||||
$fileId = null;
|
$version = time();
|
||||||
$propfindUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . $ncPath;
|
// СЛУЧАЙНЫЙ ключ при каждом запросе, чтобы OnlyOffice не использовал кеш!
|
||||||
|
$documentKey = md5($s3Path . '_' . $version);
|
||||||
|
|
||||||
error_log("Nextcloud Editor: PROPFIND -> {$propfindUrl}");
|
// ПРЯМОЙ S3 URL (bucket публичный, поэтому pre-signed URL не нужен!)
|
||||||
|
// Bucket поддерживает Range requests и CORS из коробки
|
||||||
|
$fileUrl = $s3Url;
|
||||||
|
|
||||||
// XML запрос для получения fileid
|
// ОТЛАДКА: Логируем все параметры
|
||||||
$xmlRequest = '<?xml version="1.0"?>
|
error_log("=== OPEN FILE DEBUG ===");
|
||||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
error_log("S3 Path: " . $s3Path);
|
||||||
<d:prop>
|
error_log("File URL: " . $fileUrl);
|
||||||
<oc:fileid/>
|
error_log("File extension: " . $ext);
|
||||||
</d:prop>
|
error_log("Document Key (unique): " . $documentKey);
|
||||||
</d:propfind>';
|
error_log("Version: " . $version);
|
||||||
|
|
||||||
$ch = curl_init();
|
$fileBasename = basename($s3Path);
|
||||||
curl_setopt($ch, CURLOPT_URL, $propfindUrl);
|
$fileType = getFileType($ext);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
$officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
|
||||||
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) {
|
if (!in_array($ext, $officeFormats)) {
|
||||||
error_log("Nextcloud Editor: Ошибка cURL: " . $curlError);
|
header('Location: ' . $s3Url);
|
||||||
} else {
|
|
||||||
error_log("Nextcloud Editor: HTTP код: {$httpCode}");
|
|
||||||
|
|
||||||
if ($httpCode === 207 && preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches)) {
|
|
||||||
$fileId = (int)$matches[1];
|
|
||||||
error_log("Nextcloud Editor: Получен fileId: {$fileId}");
|
|
||||||
} else {
|
|
||||||
error_log("Nextcloud Editor: Файл не найден по пути: {$ncPath} (HTTP {$httpCode})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$fileId) {
|
|
||||||
$errorMsg = "❌ Ошибка: Не удалось получить fileId для файла {$fileName}";
|
|
||||||
error_log("Nextcloud Editor ERROR: " . $errorMsg);
|
|
||||||
die($errorMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Формируем URL для Nextcloud
|
|
||||||
// РАБОЧИЙ ФОРМАТ - редирект на файл с автооткрытием редактора!
|
|
||||||
$redirectUrl = $nextcloudUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=true&openfile=true';
|
|
||||||
|
|
||||||
// Логирование
|
|
||||||
error_log("Nextcloud Editor: Redirect to $redirectUrl for file (ID: $fileId)");
|
|
||||||
|
|
||||||
// Делаем редирект
|
|
||||||
header('Location: ' . $redirectUrl);
|
|
||||||
exit;
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
|
<meta http-equiv="Expires" content="0">
|
||||||
|
<title><?php echo htmlspecialchars($fileBasename); ?></title>
|
||||||
|
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#editor {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="editor"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Отладка в консоль
|
||||||
|
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
|
||||||
|
console.log('🔗 S3 URL:', <?php echo json_encode($fileUrl); ?>);
|
||||||
|
console.log('🔑 Document Key (unique):', <?php echo json_encode($documentKey); ?>);
|
||||||
|
console.log('✅ Standalone OnlyOffice (9443) + Direct S3 URL!');
|
||||||
|
|
||||||
|
new DocsAPI.DocEditor("editor", {
|
||||||
|
"documentType": "<?php echo $fileType; ?>",
|
||||||
|
"document": {
|
||||||
|
"fileType": "<?php echo $ext; ?>",
|
||||||
|
"key": "<?php echo $documentKey; ?>",
|
||||||
|
"title": <?php echo json_encode($fileBasename); ?>,
|
||||||
|
"url": <?php echo json_encode($fileUrl); ?>,
|
||||||
|
"permissions": {
|
||||||
|
"comment": true,
|
||||||
|
"download": true,
|
||||||
|
"edit": true,
|
||||||
|
"print": true,
|
||||||
|
"review": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"editorConfig": {
|
||||||
|
"mode": "edit",
|
||||||
|
"lang": "ru",
|
||||||
|
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php",
|
||||||
|
"user": {
|
||||||
|
"id": "user_<?php echo $recordId ?? 'guest'; ?>",
|
||||||
|
"name": "CRM User"
|
||||||
|
},
|
||||||
|
"customization": {
|
||||||
|
"autosave": true,
|
||||||
|
"chat": false,
|
||||||
|
"comments": true,
|
||||||
|
"compactHeader": false,
|
||||||
|
"compactToolbar": false,
|
||||||
|
"help": true,
|
||||||
|
"hideRightMenu": false,
|
||||||
|
"logo": {
|
||||||
|
"image": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png",
|
||||||
|
"imageEmbedded": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png"
|
||||||
|
},
|
||||||
|
"zoom": 100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"height": "100%",
|
||||||
|
"width": "100%",
|
||||||
|
"type": "desktop",
|
||||||
|
"events": {
|
||||||
|
"onReady": function() {
|
||||||
|
console.log('✅ Editor ready!');
|
||||||
|
},
|
||||||
|
"onDocumentReady": function() {
|
||||||
|
console.log('✅ Document loaded!');
|
||||||
|
},
|
||||||
|
"onError": function(event) {
|
||||||
|
console.error('❌ OnlyOffice Error FULL:', JSON.stringify(event, null, 2));
|
||||||
|
console.error('Event data:', event.data);
|
||||||
|
console.error('Error code:', event.data.errorCode);
|
||||||
|
console.error('Error description:', event.data.errorDescription);
|
||||||
|
|
||||||
|
// Тестируем доступность URL из браузера
|
||||||
|
console.log('🧪 Testing S3 URL from browser...');
|
||||||
|
fetch(<?php echo json_encode($fileUrl); ?>, { method: 'HEAD' })
|
||||||
|
.then(response => {
|
||||||
|
console.log('✅ Browser can access S3:', response.status);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('❌ Browser CANNOT access S3:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
alert('Ошибка загрузки документа:\n\n' +
|
||||||
|
'Code: ' + event.data.errorCode + '\n' +
|
||||||
|
'Description: ' + event.data.errorDescription + '\n\n' +
|
||||||
|
'Используется Pre-signed URL из S3\n\n' +
|
||||||
|
'Смотри консоль браузера (F12) для деталей!');
|
||||||
|
},
|
||||||
|
"onWarning": function(event) {
|
||||||
|
console.warn('⚠️ OnlyOffice Warning:', event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function getFileType($ext) {
|
||||||
|
if (in_array($ext, ['doc', 'docx'])) return 'word';
|
||||||
|
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
|
||||||
|
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
|
||||||
|
return 'word';
|
||||||
|
}
|
||||||
|
|
||||||
|
function generatePresignedUrl($s3Key, $expirationSeconds) {
|
||||||
|
try {
|
||||||
|
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
|
||||||
|
|
||||||
|
$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';
|
||||||
|
|
||||||
|
// КЛЮЧ: Минимальные параметры = правильная подпись!
|
||||||
|
$cmd = $s3Client->getCommand('GetObject', [
|
||||||
|
'Bucket' => $bucket,
|
||||||
|
'Key' => $s3Key
|
||||||
|
]);
|
||||||
|
|
||||||
|
$request = $s3Client->createPresignedRequest($cmd, "+{$expirationSeconds} seconds");
|
||||||
|
return (string)$request->getUri();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Pre-signed URL error: " . $e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContentType($filename) {
|
||||||
|
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||||
|
$types = [
|
||||||
|
'doc' => 'application/msword',
|
||||||
|
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'xls' => 'application/vnd.ms-excel',
|
||||||
|
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'ppt' => 'application/vnd.ms-powerpoint',
|
||||||
|
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
||||||
|
];
|
||||||
|
return $types[$ext] ?? 'application/octet-stream';
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
58
crm_extensions/file_storage/api/open_file_v3_collabora.php
Normal file
58
crm_extensions/file_storage/api/open_file_v3_collabora.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Открытие файлов через Collabora (вместо OnlyOffice)
|
||||||
|
* Collabora работает через Nextcloud WebDAV
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 path (убираем 'crm2/')
|
||||||
|
$ncPath = str_replace('crm2/', '', $s3Path);
|
||||||
|
$fileBasename = basename($ncPath);
|
||||||
|
|
||||||
|
// Nextcloud URL
|
||||||
|
$nextcloudUrl = 'https://office.clientright.ru:8443';
|
||||||
|
$webdavPath = '/crm/crm2/' . $ncPath;
|
||||||
|
|
||||||
|
// Открываем напрямую в Nextcloud Files - Collabora откроется автоматически!
|
||||||
|
$dirPath = dirname($webdavPath);
|
||||||
|
$redirectUrl = $nextcloudUrl . '/apps/files/?dir=' . urlencode($dirPath) . '&openfile=' . urlencode($fileBasename);
|
||||||
|
|
||||||
|
error_log("=== COLLABORA OPEN ===");
|
||||||
|
error_log("S3 Path: " . $s3Path);
|
||||||
|
error_log("NC WebDAV Path: " . $webdavPath);
|
||||||
|
error_log("Redirect URL: " . $redirectUrl);
|
||||||
|
|
||||||
|
// Редиректим в Nextcloud
|
||||||
|
header('Location: ' . $redirectUrl);
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
169
crm_extensions/file_storage/api/open_file_v3_standalone.php
Normal file
169
crm_extensions/file_storage/api/open_file_v3_standalone.php
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* OnlyOffice Standalone + S3 Direct URL
|
||||||
|
* С сохранением обратно в S3
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
|
||||||
|
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : 'unknown';
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Извлекаем расширение файла
|
||||||
|
$ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
|
// ПРЯМОЙ S3 URL (bucket публичный)
|
||||||
|
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||||||
|
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
|
||||||
|
|
||||||
|
// Генерируем уникальный ключ документа
|
||||||
|
$version = time();
|
||||||
|
$documentKey = md5($s3Path . '_' . $version);
|
||||||
|
|
||||||
|
// ВАЖНО: Сохраняем маппинг documentKey → S3 путь в Redis
|
||||||
|
try {
|
||||||
|
$redis = new Predis\Client([
|
||||||
|
'scheme' => 'tcp',
|
||||||
|
'host' => EnvLoader::getRequired('REDIS_HOST'),
|
||||||
|
'port' => (int)EnvLoader::getRequired('REDIS_PORT'),
|
||||||
|
'password' => EnvLoader::getRequired('REDIS_PASSWORD')
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Сохраняем на 24 часа (TTL = срок действия документа)
|
||||||
|
$redis->setex("crm:onlyoffice:key:$documentKey", 86400, json_encode([
|
||||||
|
's3_path' => $s3Path,
|
||||||
|
'record_id' => $recordId,
|
||||||
|
'created_at' => time()
|
||||||
|
]));
|
||||||
|
|
||||||
|
error_log("Redis: Saved mapping for key $documentKey → $s3Path");
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Redis error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileBasename = basename($s3Path);
|
||||||
|
$fileType = getFileType($ext);
|
||||||
|
$officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
|
||||||
|
|
||||||
|
if (!in_array($ext, $officeFormats)) {
|
||||||
|
header('Location: ' . $s3Url);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
|
<meta http-equiv="Expires" content="0">
|
||||||
|
<title><?php echo htmlspecialchars($fileBasename); ?></title>
|
||||||
|
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#editor {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="editor"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
|
||||||
|
console.log('🔗 S3 URL:', <?php echo json_encode($s3Url); ?>);
|
||||||
|
console.log('🔑 Document Key:', <?php echo json_encode($documentKey); ?>);
|
||||||
|
console.log('✅ Standalone OnlyOffice + Redis mapping!');
|
||||||
|
|
||||||
|
new DocsAPI.DocEditor("editor", {
|
||||||
|
"documentType": "<?php echo $fileType; ?>",
|
||||||
|
"document": {
|
||||||
|
"fileType": "<?php echo $ext; ?>",
|
||||||
|
"key": "<?php echo $documentKey; ?>",
|
||||||
|
"title": <?php echo json_encode($fileBasename); ?>,
|
||||||
|
"url": <?php echo json_encode($s3Url); ?>,
|
||||||
|
"permissions": {
|
||||||
|
"comment": true,
|
||||||
|
"download": true,
|
||||||
|
"edit": true,
|
||||||
|
"print": true,
|
||||||
|
"review": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"editorConfig": {
|
||||||
|
"mode": "edit",
|
||||||
|
"lang": "ru",
|
||||||
|
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback_v2.php",
|
||||||
|
"user": {
|
||||||
|
"id": "user_<?php echo $recordId; ?>",
|
||||||
|
"name": "CRM User"
|
||||||
|
},
|
||||||
|
"customization": {
|
||||||
|
"autosave": true,
|
||||||
|
"compactHeader": false,
|
||||||
|
"compactToolbar": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"height": "100%",
|
||||||
|
"width": "100%",
|
||||||
|
"type": "desktop",
|
||||||
|
"events": {
|
||||||
|
"onReady": function() {
|
||||||
|
console.log('✅ Editor ready!');
|
||||||
|
},
|
||||||
|
"onDocumentReady": function() {
|
||||||
|
console.log('✅ Document loaded!');
|
||||||
|
},
|
||||||
|
"onError": function(event) {
|
||||||
|
console.error('❌ Error:', event.data);
|
||||||
|
alert('Ошибка: ' + event.data.errorDescription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function getFileType($ext) {
|
||||||
|
if (in_array($ext, ['doc', 'docx'])) return 'word';
|
||||||
|
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
|
||||||
|
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
|
||||||
|
return 'word';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
121
crm_extensions/file_storage/api/s3_proxy.php
Normal file
121
crm_extensions/file_storage/api/s3_proxy.php
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* S3 Proxy для OnlyOffice
|
||||||
|
* Проксирует запросы к S3, чтобы 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', 0);
|
||||||
|
|
||||||
|
$path = isset($_GET['path']) ? $_GET['path'] : '';
|
||||||
|
|
||||||
|
if (empty($path)) {
|
||||||
|
http_response_code(400);
|
||||||
|
die('Path parameter is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// CORS preflight
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
|
||||||
|
header('Access-Control-Allow-Headers: *');
|
||||||
|
header('Access-Control-Max-Age: 3600');
|
||||||
|
http_response_code(200);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для HEAD запросов - только headers, без body
|
||||||
|
$isHeadRequest = ($_SERVER['REQUEST_METHOD'] === 'HEAD');
|
||||||
|
|
||||||
|
// Формируем URL к S3
|
||||||
|
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||||||
|
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $path;
|
||||||
|
|
||||||
|
// Проверяем Range header (для OnlyOffice partial requests)
|
||||||
|
$rangeHeader = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : '';
|
||||||
|
|
||||||
|
error_log("S3 Proxy: Request from: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
|
||||||
|
error_log("S3 Proxy: Downloading: " . $s3Url);
|
||||||
|
if ($rangeHeader) {
|
||||||
|
error_log("S3 Proxy: Range request: " . $rangeHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// СНАЧАЛА скачиваем в буфер
|
||||||
|
$ch = curl_init($s3Url);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // ← ВАЖНО: В БУФЕР!
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, true); // ← Получаем headers
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
|
||||||
|
|
||||||
|
// Для HEAD запросов - только headers
|
||||||
|
if ($isHeadRequest) {
|
||||||
|
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если есть Range header - передаём его в S3!
|
||||||
|
if ($rangeHeader) {
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Range: ' . $rangeHeader]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||||
|
$error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
// Проверяем ПРЕЖДЕ чем отправлять что-либо
|
||||||
|
// 200 = полный файл, 206 = частичный (Range request)
|
||||||
|
if ($response === false || ($httpCode !== 200 && $httpCode !== 206)) {
|
||||||
|
error_log("S3 Proxy ERROR: HTTP $httpCode, cURL error: $error");
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
http_response_code($httpCode ?: 500);
|
||||||
|
die('Failed to fetch file from S3');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Разделяем headers и body
|
||||||
|
$headersText = substr($response, 0, $headerSize);
|
||||||
|
$body = $isHeadRequest ? '' : substr($response, $headerSize); // Для HEAD body пустой
|
||||||
|
|
||||||
|
// Парсим headers
|
||||||
|
$headers = explode("\r\n", $headersText);
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
if (strpos($header, ':') !== false) {
|
||||||
|
list($name, $value) = explode(':', $header, 2);
|
||||||
|
$name = strtolower(trim($name));
|
||||||
|
$value = trim($value);
|
||||||
|
|
||||||
|
// Пробрасываем нужные headers
|
||||||
|
if (in_array($name, ['content-type', 'content-length', 'content-range', 'accept-ranges', 'etag', 'last-modified'])) {
|
||||||
|
header($name . ': ' . $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CORS headers
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
|
||||||
|
header('Access-Control-Allow-Headers: *');
|
||||||
|
header('Access-Control-Expose-Headers: Content-Range, Accept-Ranges');
|
||||||
|
|
||||||
|
// Устанавливаем правильный HTTP код (206 для partial content)
|
||||||
|
if ($httpCode === 206) {
|
||||||
|
http_response_code(206);
|
||||||
|
} else {
|
||||||
|
http_response_code(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправляем body только для GET запросов (не для HEAD)
|
||||||
|
if (!$isHeadRequest) {
|
||||||
|
echo $body;
|
||||||
|
error_log("S3 Proxy: Success! Sent " . strlen($body) . " bytes");
|
||||||
|
} else {
|
||||||
|
error_log("S3 Proxy: HEAD request completed");
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
onlyoffice-standalone:
|
||||||
|
image: onlyoffice/documentserver:latest
|
||||||
|
container_name: onlyoffice-standalone
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8083:80" # Новый порт (8081 и 8082 заняты)
|
||||||
|
environment:
|
||||||
|
- JWT_ENABLED=false
|
||||||
|
- JWT_SECRET=
|
||||||
|
- WOPI_ENABLED=false
|
||||||
|
volumes:
|
||||||
|
- onlyoffice-standalone-data:/var/www/onlyoffice/Data
|
||||||
|
- onlyoffice-standalone-logs:/var/log/onlyoffice
|
||||||
|
- onlyoffice-standalone-fonts:/usr/share/fonts/truetype/custom
|
||||||
|
- onlyoffice-standalone-forgotten:/var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten
|
||||||
|
networks:
|
||||||
|
- crm-network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
onlyoffice-standalone-data:
|
||||||
|
onlyoffice-standalone-logs:
|
||||||
|
onlyoffice-standalone-fonts:
|
||||||
|
onlyoffice-standalone-forgotten:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
crm-network:
|
||||||
|
name: crm-network
|
||||||
|
|
||||||
48
crm_extensions/file_storage/get_s3_credentials.sh
Executable file
48
crm_extensions/file_storage/get_s3_credentials.sh
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🔑 S3 Credentials для n8n"
|
||||||
|
echo "════════════════════════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Получаем credentials из Nextcloud
|
||||||
|
docker exec nextcloud-fresh php occ files_external:list --output=json 2>/dev/null | jq -r '
|
||||||
|
.[0].configuration |
|
||||||
|
"📦 Bucket: \(.bucket)
|
||||||
|
🔑 Access Key: \(.key)
|
||||||
|
🔐 Secret Key: \(.secret)
|
||||||
|
🌐 Endpoint: \(.hostname)
|
||||||
|
🗺️ Region: \(.region)
|
||||||
|
|
||||||
|
════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
📋 Для n8n AWS S3 Credentials:
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
Access Key ID: \(.key)
|
||||||
|
Secret Access Key: \(.secret)
|
||||||
|
Region: \(.region)
|
||||||
|
|
||||||
|
Custom Endpoints: ✅ ВКЛЮЧИТЬ
|
||||||
|
S3 Endpoint: https://\(.hostname)
|
||||||
|
Force Path Style: ✅ ВКЛЮЧИТЬ
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
📋 Для n8n Environment Variables:
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
S3_BUCKET=\(.bucket)
|
||||||
|
S3_ENDPOINT=https://\(.hostname)
|
||||||
|
S3_REGION=\(.region)
|
||||||
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
"
|
||||||
|
'
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📋 Redis Credentials для n8n:"
|
||||||
|
echo "────────────────────────────────────────────────────────────────────────────────"
|
||||||
|
echo "Host: 147.45.146.17"
|
||||||
|
echo "Port: 6379"
|
||||||
|
echo "Password: CRM_Redis_Pass_2025_Secure!"
|
||||||
|
echo "Database: 0"
|
||||||
|
echo "────────────────────────────────────────────────────────────────────────────────"
|
||||||
|
echo ""
|
||||||
|
echo "✅ Готово! Скопируй эти данные в n8n"
|
||||||
|
|
||||||
166
crm_extensions/file_storage/migrate_single_project.php
Normal file
166
crm_extensions/file_storage/migrate_single_project.php
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Простая миграция одного проекта в новую структуру
|
||||||
|
* Использование: php migrate_single_project.php PROJECT_ID
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once(__DIR__ . '/../../config.inc.php');
|
||||||
|
require_once(__DIR__ . '/../../include/database/PearDatabase.php');
|
||||||
|
|
||||||
|
$adb = PearDatabase::getInstance();
|
||||||
|
|
||||||
|
// Получаем ID проекта
|
||||||
|
$projectId = isset($argv[1]) ? (int)$argv[1] : null;
|
||||||
|
|
||||||
|
if (!$projectId) {
|
||||||
|
echo "❌ Укажите ID проекта!\n";
|
||||||
|
echo "Использование: php migrate_single_project.php PROJECT_ID\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "🔄 МИГРАЦИЯ ПРОЕКТА $projectId\n";
|
||||||
|
echo "==========================================\n\n";
|
||||||
|
|
||||||
|
// Получаем информацию о проекте
|
||||||
|
$result = $adb->pquery("SELECT p.projectname FROM vtiger_project p WHERE p.projectid = ?", [$projectId]);
|
||||||
|
|
||||||
|
if ($adb->num_rows($result) == 0) {
|
||||||
|
echo "❌ Проект не найден!\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$projectName = $adb->query_result($result, 0, 'projectname');
|
||||||
|
echo "📁 Проект: $projectName\n\n";
|
||||||
|
|
||||||
|
// Функция очистки имени файла
|
||||||
|
function sanitizeName($name) {
|
||||||
|
// Транслитерация
|
||||||
|
$translitMap = [
|
||||||
|
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
|
||||||
|
'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
|
||||||
|
'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
|
||||||
|
'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
|
||||||
|
'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch',
|
||||||
|
'Ш' => 'Sh', 'Щ' => 'Sch', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '',
|
||||||
|
'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
|
||||||
|
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
|
||||||
|
'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
|
||||||
|
'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
|
||||||
|
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
|
||||||
|
'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch',
|
||||||
|
'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
|
||||||
|
'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
|
||||||
|
];
|
||||||
|
|
||||||
|
$name = strtr($name, $translitMap);
|
||||||
|
$name = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $name);
|
||||||
|
$name = preg_replace('/_+/', '_', $name);
|
||||||
|
$name = trim($name, '_');
|
||||||
|
|
||||||
|
if (strlen($name) > 100) {
|
||||||
|
$name = substr($name, 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sanitizedName = sanitizeName($projectName);
|
||||||
|
$newFolder = "Documents/Project/{$sanitizedName}_{$projectId}";
|
||||||
|
|
||||||
|
echo "📁 Новая папка: $newFolder\n\n";
|
||||||
|
|
||||||
|
// Получаем все документы проекта
|
||||||
|
$result = $adb->pquery(
|
||||||
|
"SELECT n.notesid, n.title, n.filename, n.s3_key, n.filelocationtype
|
||||||
|
FROM vtiger_notes n
|
||||||
|
JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid
|
||||||
|
JOIN vtiger_crmentity e ON e.crmid = n.notesid
|
||||||
|
WHERE snr.crmid = ? AND e.deleted = 0 AND n.filelocationtype = 'E'
|
||||||
|
ORDER BY n.notesid",
|
||||||
|
[$projectId]
|
||||||
|
);
|
||||||
|
|
||||||
|
$total = $adb->num_rows($result);
|
||||||
|
echo "📊 Найдено документов: $total\n\n";
|
||||||
|
|
||||||
|
if ($total == 0) {
|
||||||
|
echo "✅ Нет документов для миграции\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$migrated = 0;
|
||||||
|
$errors = 0;
|
||||||
|
|
||||||
|
while ($doc = $adb->fetch_array($result)) {
|
||||||
|
$notesid = $doc['notesid'];
|
||||||
|
$title = $doc['title'];
|
||||||
|
$oldS3Key = $doc['s3_key'];
|
||||||
|
|
||||||
|
echo "[$migrated/$total] Документ: $title (ID: $notesid)\n";
|
||||||
|
echo " Старый s3_key: $oldS3Key\n";
|
||||||
|
|
||||||
|
// Извлекаем имя файла и расширение
|
||||||
|
$oldFilename = basename($oldS3Key);
|
||||||
|
$pathInfo = pathinfo($oldFilename);
|
||||||
|
$extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
|
||||||
|
|
||||||
|
// Новое имя файла: file_docID_название.ext
|
||||||
|
$newFilename = "file_{$notesid}_{$pathInfo['filename']}{$extension}";
|
||||||
|
|
||||||
|
// Новый путь в S3
|
||||||
|
$newS3Key = "{$newFolder}/{$newFilename}";
|
||||||
|
$newNcPath = "/crm/crm2/CRM_Active_Files/{$newFolder}/{$newFilename}";
|
||||||
|
|
||||||
|
// Новый URL
|
||||||
|
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
|
||||||
|
$newUrl = "https://s3.twcstorage.ru/{$bucket}/crm2/CRM_Active_Files/{$newS3Key}";
|
||||||
|
|
||||||
|
echo " Новый s3_key: $newS3Key\n";
|
||||||
|
echo " Новый nc_path: $newNcPath\n";
|
||||||
|
|
||||||
|
// Копируем файл в S3 (используем aws s3 cp)
|
||||||
|
$oldKey = "crm2/CRM_Active_Files/" . $oldS3Key;
|
||||||
|
$newKey = "crm2/CRM_Active_Files/" . $newS3Key;
|
||||||
|
|
||||||
|
$copyCmd = "aws s3 cp " .
|
||||||
|
"s3://{$bucket}/{$oldKey} " .
|
||||||
|
"s3://{$bucket}/{$newKey} " .
|
||||||
|
"--endpoint-url https://s3.twcstorage.ru " .
|
||||||
|
"--region ru-1 2>&1";
|
||||||
|
|
||||||
|
echo " Копирование в S3...\n";
|
||||||
|
exec($copyCmd, $output, $returnCode);
|
||||||
|
|
||||||
|
if ($returnCode !== 0) {
|
||||||
|
echo " ❌ ОШИБКА копирования: " . implode("\n", $output) . "\n";
|
||||||
|
$errors++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo " ✅ Скопировано в S3\n";
|
||||||
|
|
||||||
|
// Обновляем БД
|
||||||
|
$updateResult = $adb->pquery(
|
||||||
|
"UPDATE vtiger_notes
|
||||||
|
SET s3_key = ?, nc_path = ?, filename = ?
|
||||||
|
WHERE notesid = ?",
|
||||||
|
[$newS3Key, $newNcPath, $newUrl, $notesid]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($updateResult) {
|
||||||
|
echo " ✅ БД обновлена\n";
|
||||||
|
$migrated++;
|
||||||
|
} else {
|
||||||
|
echo " ❌ ОШИБКА обновления БД\n";
|
||||||
|
$errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "==========================================\n";
|
||||||
|
echo "✅ МИГРАЦИЯ ЗАВЕРШЕНА!\n";
|
||||||
|
echo "Обработано: $total\n";
|
||||||
|
echo "Мигрировано: $migrated\n";
|
||||||
|
echo "Ошибок: $errors\n";
|
||||||
|
|
||||||
170
crm_extensions/file_storage/n8n_nextcloud_activity_monitor.json
Normal file
170
crm_extensions/file_storage/n8n_nextcloud_activity_monitor.json
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
{
|
||||||
|
"name": "Nextcloud Activity Monitor",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"rule": {
|
||||||
|
"interval": [
|
||||||
|
{
|
||||||
|
"field": "seconds",
|
||||||
|
"secondsInterval": 30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "schedule",
|
||||||
|
"name": "Каждые 30 секунд",
|
||||||
|
"type": "n8n-nodes-base.scheduleTrigger",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [250, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"url": "https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity",
|
||||||
|
"authentication": "genericCredentialType",
|
||||||
|
"genericAuthType": "httpBasicAuth",
|
||||||
|
"sendQuery": true,
|
||||||
|
"queryParameters": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "format",
|
||||||
|
"value": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"value": "100"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sendHeaders": true,
|
||||||
|
"headerParameters": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "OCS-APIRequest",
|
||||||
|
"value": "true"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
"id": "http-request",
|
||||||
|
"name": "Get Nextcloud Activities",
|
||||||
|
"type": "n8n-nodes-base.httpRequest",
|
||||||
|
"typeVersion": 4,
|
||||||
|
"position": [450, 300],
|
||||||
|
"credentials": {
|
||||||
|
"httpBasicAuth": {
|
||||||
|
"id": "3",
|
||||||
|
"name": "Nextcloud Admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"jsCode": "// Получаем последний обработанный activity_id из Static Data\nconst staticData = getWorkflowStaticData('node');\nlet lastProcessedId = staticData.lastActivityId || 0;\n\nconst activities = $input.item.json.ocs.data;\nconst fileEvents = [];\n\n// Типы событий которые нас интересуют\nconst relevantTypes = ['file_created', 'file_changed', 'file_deleted', 'file_restored'];\n\n// Фильтруем и обрабатываем события\nfor (const activity of activities) {\n // Пропускаем уже обработанные\n if (activity.activity_id <= lastProcessedId) {\n continue;\n }\n \n // Только файловые события\n if (!relevantTypes.includes(activity.type)) {\n continue;\n }\n \n // РАЗБИВАЕМ агрегированные события!\n // Если есть objects - создаём событие для каждого файла\n if (activity.objects && typeof activity.objects === 'object') {\n const fileIds = Object.keys(activity.objects);\n \n for (const fileId of fileIds) {\n const filePath = activity.objects[fileId];\n \n fileEvents.push({\n json: {\n type: activity.type,\n source: 'nextcloud_activity',\n timestamp: activity.datetime,\n file_id: parseInt(fileId),\n path: filePath,\n filename: filePath ? filePath.split('/').pop() : null,\n user: activity.user,\n activity_id: activity.activity_id,\n action: activity.type.replace('file_', '')\n }\n });\n }\n } else {\n // Одиночное событие\n fileEvents.push({\n json: {\n type: activity.type,\n source: 'nextcloud_activity',\n timestamp: activity.datetime,\n file_id: activity.object_id,\n path: activity.object_name,\n filename: activity.object_name ? activity.object_name.split('/').pop() : null,\n user: activity.user,\n activity_id: activity.activity_id,\n action: activity.type.replace('file_', '')\n }\n });\n }\n \n // Обновляем последний ID\n if (activity.activity_id > lastProcessedId) {\n lastProcessedId = activity.activity_id;\n }\n}\n\n// Сохраняем последний обработанный ID\nstaticData.lastActivityId = lastProcessedId;\n\n// Если новых событий нет - возвращаем пустой массив\nif (fileEvents.length === 0) {\n return [];\n}\n\nreturn fileEvents;"
|
||||||
|
},
|
||||||
|
"id": "process-activities",
|
||||||
|
"name": "Process & Filter Events",
|
||||||
|
"type": "n8n-nodes-base.code",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [650, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.filename}}",
|
||||||
|
"operation": "isNotEmpty"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "filter",
|
||||||
|
"name": "Есть новые события?",
|
||||||
|
"type": "n8n-nodes-base.if",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [850, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "publish",
|
||||||
|
"channel": "crm:file:events",
|
||||||
|
"value": "={{JSON.stringify($json)}}",
|
||||||
|
"keyType": "automatic"
|
||||||
|
},
|
||||||
|
"id": "redis-publish",
|
||||||
|
"name": "Publish to Redis",
|
||||||
|
"type": "n8n-nodes-base.redis",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1050, 200],
|
||||||
|
"credentials": {
|
||||||
|
"redis": {
|
||||||
|
"id": "2",
|
||||||
|
"name": "CRM Redis"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"content": "=📢 Nextcloud Event:\n**Type:** {{$json.type}}\n**File:** {{$json.filename}}\n**Path:** {{$json.path}}\n**User:** {{$json.user}}\n**Time:** {{$json.timestamp}}",
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
"id": "logger",
|
||||||
|
"name": "Log Event (optional)",
|
||||||
|
"type": "n8n-nodes-base.stickyNote",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1050, 400]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": {
|
||||||
|
"schedule": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "http-request",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"http-request": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "process-activities",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"process-activities": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "filter",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "redis-publish",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
174
crm_extensions/file_storage/n8n_s3_event_processor.json
Normal file
174
crm_extensions/file_storage/n8n_s3_event_processor.json
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
{
|
||||||
|
"name": "S3 Event Processor",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "subscribe",
|
||||||
|
"channel": "crm:file:events"
|
||||||
|
},
|
||||||
|
"id": "redis-subscribe",
|
||||||
|
"name": "Redis Subscribe",
|
||||||
|
"type": "n8n-nodes-base.redis",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [250, 300],
|
||||||
|
"credentials": {
|
||||||
|
"redis": {
|
||||||
|
"id": "CRM_REDIS_ID",
|
||||||
|
"name": "CRM Redis"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"jsCode": "// Парсим JSON из Redis message\nconst items = [];\n\nfor (const item of $input.all()) {\n const message = item.json.message;\n \n // Если message это строка - парсим\n let parsedMessage = message;\n if (typeof message === 'string') {\n parsedMessage = JSON.parse(message);\n }\n \n items.push({\n json: parsedMessage\n });\n}\n\nreturn items;"
|
||||||
|
},
|
||||||
|
"id": "parse-json",
|
||||||
|
"name": "Parse Message",
|
||||||
|
"type": "n8n-nodes-base.code",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [450, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"options": {
|
||||||
|
"caseSensitive": true
|
||||||
|
},
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"id": "c1",
|
||||||
|
"leftValue": "={{ $json.type }}",
|
||||||
|
"rightValue": "file_created",
|
||||||
|
"operator": {
|
||||||
|
"type": "string",
|
||||||
|
"operation": "equals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"combinator": "and"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "filter-created",
|
||||||
|
"name": "Только новые файлы",
|
||||||
|
"type": "n8n-nodes-base.switch",
|
||||||
|
"typeVersion": 3,
|
||||||
|
"position": [650, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"options": {},
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"id": "c1",
|
||||||
|
"leftValue": "={{ $json.filename }}",
|
||||||
|
"rightValue": ".xlsx",
|
||||||
|
"operator": {
|
||||||
|
"type": "string",
|
||||||
|
"operation": "endsWith"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"combinator": "or"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "filter-xlsx",
|
||||||
|
"name": "Только XLSX",
|
||||||
|
"type": "n8n-nodes-base.switch",
|
||||||
|
"typeVersion": 3,
|
||||||
|
"position": [850, 200]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"options": {},
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"id": "c1",
|
||||||
|
"leftValue": "={{ $json.filename }}",
|
||||||
|
"rightValue": ".pdf",
|
||||||
|
"operator": {
|
||||||
|
"type": "string",
|
||||||
|
"operation": "endsWith"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"combinator": "or"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "filter-pdf",
|
||||||
|
"name": "Только PDF",
|
||||||
|
"type": "n8n-nodes-base.switch",
|
||||||
|
"typeVersion": 3,
|
||||||
|
"position": [850, 400]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"content": "=📊 **XLSX файл обнаружен!**\n\n**Имя:** {{ $json.filename }}\n**Путь:** {{ $json.path }}\n**Размер:** {{ $json.size }} bytes\n**Время:** {{ $json.timestamp }}\n\n---\n\nЗдесь можно:\n- Скачать файл из S3\n- Обработать данные\n- Загрузить в CRM\n- Отправить уведомление",
|
||||||
|
"height": 312,
|
||||||
|
"width": 389
|
||||||
|
},
|
||||||
|
"id": "process-xlsx",
|
||||||
|
"name": "Обработка XLSX",
|
||||||
|
"type": "n8n-nodes-base.stickyNote",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1050, 80]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"content": "=📄 **PDF файл обнаружен!**\n\n**Имя:** {{ $json.filename }}\n**Путь:** {{ $json.path }}\n**Размер:** {{ $json.size }} bytes\n**Время:** {{ $json.timestamp }}\n\n---\n\nЗдесь можно:\n- Скачать PDF из S3\n- OCR распознавание\n- Извлечь данные\n- Создать документ в CRM",
|
||||||
|
"height": 312,
|
||||||
|
"width": 389
|
||||||
|
},
|
||||||
|
"id": "process-pdf",
|
||||||
|
"name": "Обработка PDF",
|
||||||
|
"type": "n8n-nodes-base.stickyNote",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1050, 320]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": {
|
||||||
|
"redis-subscribe": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "parse-json",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"parse-json": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "filter-created",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filter-created": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "filter-xlsx",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "filter-pdf",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
179
crm_extensions/file_storage/n8n_s3_monitor_workflow.json
Normal file
179
crm_extensions/file_storage/n8n_s3_monitor_workflow.json
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
{
|
||||||
|
"name": "S3 File Monitor",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"rule": {
|
||||||
|
"interval": [
|
||||||
|
{
|
||||||
|
"field": "seconds",
|
||||||
|
"secondsInterval": 30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "schedule",
|
||||||
|
"name": "Каждые 30 секунд",
|
||||||
|
"type": "n8n-nodes-base.scheduleTrigger",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [250, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "getAll",
|
||||||
|
"bucketName": "={{$env.S3_BUCKET}}",
|
||||||
|
"returnAll": true,
|
||||||
|
"options": {
|
||||||
|
"prefix": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "s3-list",
|
||||||
|
"name": "List S3 Files",
|
||||||
|
"type": "n8n-nodes-base.awsS3",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [450, 300],
|
||||||
|
"credentials": {
|
||||||
|
"aws": {
|
||||||
|
"id": "1",
|
||||||
|
"name": "TWC S3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"functionCode": "// Храним состояние файлов в Static Data\nconst currentState = $node[\"s3-list\"].json;\nconst previousState = $getWorkflowStaticData('node') || {};\nconst events = [];\n\n// Проверяем новые и изменённые файлы\nfor (const file of currentState) {\n const key = file.Key;\n const etag = file.ETag;\n \n if (!previousState[key]) {\n // Новый файл\n events.push({\n type: 'file_created',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop(),\n size: file.Size,\n etag: etag,\n last_modified: file.LastModified\n });\n } else if (previousState[key].ETag !== etag) {\n // Файл изменён\n events.push({\n type: 'file_modified',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop(),\n size: file.Size,\n etag: etag,\n last_modified: file.LastModified\n });\n }\n \n previousState[key] = { ETag: etag, Size: file.Size };\n}\n\n// Проверяем удалённые файлы\nconst currentKeys = currentState.map(f => f.Key);\nfor (const key in previousState) {\n if (!currentKeys.includes(key)) {\n events.push({\n type: 'file_deleted',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop()\n });\n delete previousState[key];\n }\n}\n\n// Сохраняем новое состояние\n$setWorkflowStaticData(previousState);\n\nreturn events.map(event => ({ json: event }));"
|
||||||
|
},
|
||||||
|
"id": "detect-changes",
|
||||||
|
"name": "Detect Changes",
|
||||||
|
"type": "n8n-nodes-base.code",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [650, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"conditions": {
|
||||||
|
"options": {
|
||||||
|
"caseSensitive": true,
|
||||||
|
"leftValue": "",
|
||||||
|
"typeValidation": "strict"
|
||||||
|
},
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"id": "c1",
|
||||||
|
"leftValue": "={{ $json.type }}",
|
||||||
|
"rightValue": "",
|
||||||
|
"operator": {
|
||||||
|
"type": "string",
|
||||||
|
"operation": "notEmpty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"combinator": "and"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "filter",
|
||||||
|
"name": "Есть изменения?",
|
||||||
|
"type": "n8n-nodes-base.if",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [850, 300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"operation": "publish",
|
||||||
|
"channel": "crm:file:events",
|
||||||
|
"value": "={{JSON.stringify($json)}}",
|
||||||
|
"keyType": "automatic",
|
||||||
|
"expire": false,
|
||||||
|
"expireAfter": 86400
|
||||||
|
},
|
||||||
|
"id": "redis-publish",
|
||||||
|
"name": "Publish to Redis",
|
||||||
|
"type": "n8n-nodes-base.redis",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [1050, 200],
|
||||||
|
"credentials": {
|
||||||
|
"redis": {
|
||||||
|
"id": "2",
|
||||||
|
"name": "CRM Redis"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"url": "={{$env.WEBHOOK_URL}}",
|
||||||
|
"options": {
|
||||||
|
"bodyContentType": "json"
|
||||||
|
},
|
||||||
|
"sendBody": true,
|
||||||
|
"bodyParameters": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "event",
|
||||||
|
"value": "={{$json}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "webhook",
|
||||||
|
"name": "Send Webhook (опционально)",
|
||||||
|
"type": "n8n-nodes-base.httpRequest",
|
||||||
|
"typeVersion": 3,
|
||||||
|
"position": [1050, 400]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": {
|
||||||
|
"schedule": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "s3-list",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"s3-list": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "detect-changes",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"detect-changes": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "filter",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "redis-publish",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": "webhook",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
249
crm_extensions/file_storage/nextcloud_activity_monitor.js
Executable file
249
crm_extensions/file_storage/nextcloud_activity_monitor.js
Executable file
@@ -0,0 +1,249 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Nextcloud Activity Monitor
|
||||||
|
* Мониторит события файлов через Activity API и публикует в Redis
|
||||||
|
*/
|
||||||
|
|
||||||
|
const https = require('https');
|
||||||
|
const Redis = require('ioredis');
|
||||||
|
|
||||||
|
const CONFIG = {
|
||||||
|
nextcloud: {
|
||||||
|
host: 'office.clientright.ru',
|
||||||
|
port: 8443,
|
||||||
|
username: 'admin',
|
||||||
|
password: 'tGHKS-3cC9m-7Hggb-65Awk-zxWQE',
|
||||||
|
auth: Buffer.from('admin:tGHKS-3cC9m-7Hggb-65Awk-zxWQE').toString('base64')
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
host: '147.45.146.17',
|
||||||
|
port: 6379,
|
||||||
|
password: 'CRM_Redis_Pass_2025_Secure!'
|
||||||
|
},
|
||||||
|
pollInterval: 30000, // 30 секунд
|
||||||
|
stateKey: 'crm:nextcloud:activity:state'
|
||||||
|
};
|
||||||
|
|
||||||
|
const redis = new Redis({
|
||||||
|
host: CONFIG.redis.host,
|
||||||
|
port: CONFIG.redis.port,
|
||||||
|
password: CONFIG.redis.password
|
||||||
|
});
|
||||||
|
|
||||||
|
// Хранилище последнего обработанного activity_id
|
||||||
|
let lastActivityId = 0;
|
||||||
|
|
||||||
|
// Загрузка состояния из Redis
|
||||||
|
async function loadState() {
|
||||||
|
try {
|
||||||
|
const data = await redis.get(CONFIG.stateKey);
|
||||||
|
if (data) {
|
||||||
|
const state = JSON.parse(data);
|
||||||
|
lastActivityId = state.lastActivityId || 0;
|
||||||
|
console.log(`📥 Последний обработанный activity_id: ${lastActivityId}`);
|
||||||
|
} else {
|
||||||
|
console.log('📥 Состояние пустое (первый запуск)');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('⚠️ Ошибка загрузки состояния:', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохранение состояния в Redis
|
||||||
|
async function saveState() {
|
||||||
|
try {
|
||||||
|
await redis.set(CONFIG.stateKey, JSON.stringify({ lastActivityId }));
|
||||||
|
} catch (err) {
|
||||||
|
console.error('⚠️ Ошибка сохранения состояния:', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение активностей из Nextcloud API
|
||||||
|
function getActivities(limit = 100) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const options = {
|
||||||
|
hostname: CONFIG.nextcloud.host,
|
||||||
|
port: CONFIG.nextcloud.port,
|
||||||
|
path: `/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=${limit}`,
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Basic ${CONFIG.nextcloud.auth}`,
|
||||||
|
'OCS-APIRequest': 'true'
|
||||||
|
},
|
||||||
|
rejectUnauthorized: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = https.request(options, (res) => {
|
||||||
|
let data = '';
|
||||||
|
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(data);
|
||||||
|
resolve(json.ocs.data || []);
|
||||||
|
} catch (err) {
|
||||||
|
reject(new Error('Ошибка парсинга JSON: ' + err.message));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.setTimeout(10000, () => {
|
||||||
|
req.destroy();
|
||||||
|
reject(new Error('Timeout'));
|
||||||
|
});
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Публикация события в Redis
|
||||||
|
async function publishEvent(event) {
|
||||||
|
console.log(`\n 📢 ${event.type.toUpperCase()}: ${event.filename}`);
|
||||||
|
console.log(` 🆔 file_id: ${event.file_id}`);
|
||||||
|
console.log(` 👤 user: ${event.user}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await redis.publish('crm:file:events', JSON.stringify(event));
|
||||||
|
console.log(` ✅ Опубликовано в Redis`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(` ❌ Ошибка публикации:`, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сканирование новых активностей
|
||||||
|
async function scanActivities() {
|
||||||
|
try {
|
||||||
|
console.log(`\n🔍 Проверка новых событий... (${new Date().toISOString()})`);
|
||||||
|
|
||||||
|
const activities = await getActivities(100);
|
||||||
|
|
||||||
|
const relevantTypes = ['file_created', 'file_changed', 'file_deleted', 'file_restored'];
|
||||||
|
let newEvents = 0;
|
||||||
|
let totalFiles = 0;
|
||||||
|
|
||||||
|
// Обрабатываем активности (от новых к старым)
|
||||||
|
for (const activity of activities) {
|
||||||
|
// Пропускаем уже обработанные
|
||||||
|
if (activity.activity_id <= lastActivityId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Только файловые события
|
||||||
|
if (!relevantTypes.includes(activity.type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newEvents++;
|
||||||
|
|
||||||
|
// РАЗБИВАЕМ агрегированные события на отдельные файлы!
|
||||||
|
if (activity.objects && typeof activity.objects === 'object') {
|
||||||
|
// Множественное событие - разбиваем
|
||||||
|
const fileIds = Object.keys(activity.objects);
|
||||||
|
totalFiles += fileIds.length;
|
||||||
|
|
||||||
|
console.log(` 📦 Агрегированное событие: ${fileIds.length} файлов`);
|
||||||
|
|
||||||
|
for (const fileId of fileIds) {
|
||||||
|
const filePath = activity.objects[fileId];
|
||||||
|
|
||||||
|
const event = {
|
||||||
|
type: activity.type,
|
||||||
|
source: 'nextcloud_activity',
|
||||||
|
timestamp: activity.datetime,
|
||||||
|
file_id: parseInt(fileId),
|
||||||
|
path: filePath,
|
||||||
|
filename: filePath ? filePath.split('/').pop().replace(/^\//, '') : null,
|
||||||
|
user: activity.user,
|
||||||
|
activity_id: activity.activity_id,
|
||||||
|
action: activity.type.replace('file_', '')
|
||||||
|
};
|
||||||
|
|
||||||
|
await publishEvent(event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Одиночное событие
|
||||||
|
totalFiles++;
|
||||||
|
|
||||||
|
const event = {
|
||||||
|
type: activity.type,
|
||||||
|
source: 'nextcloud_activity',
|
||||||
|
timestamp: activity.datetime,
|
||||||
|
file_id: activity.object_id,
|
||||||
|
path: activity.object_name,
|
||||||
|
filename: activity.object_name ? activity.object_name.split('/').pop().replace(/^\//, '') : null,
|
||||||
|
user: activity.user,
|
||||||
|
activity_id: activity.activity_id,
|
||||||
|
action: activity.type.replace('file_', '')
|
||||||
|
};
|
||||||
|
|
||||||
|
await publishEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем последний ID
|
||||||
|
if (activity.activity_id > lastActivityId) {
|
||||||
|
lastActivityId = activity.activity_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем состояние
|
||||||
|
await saveState();
|
||||||
|
|
||||||
|
console.log(`\n✅ Сканирование завершено:`);
|
||||||
|
console.log(` 📊 Новых активностей: ${newEvents}`);
|
||||||
|
console.log(` 📁 Файлов обработано: ${totalFiles}`);
|
||||||
|
console.log(` 🆔 Последний activity_id: ${lastActivityId}`);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('❌ Ошибка сканирования:', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запуск
|
||||||
|
async function start() {
|
||||||
|
console.log('🚀 Nextcloud Activity Monitor');
|
||||||
|
console.log('════════════════════════════════════════════════════════════════════════════════');
|
||||||
|
console.log(`📡 Nextcloud: ${CONFIG.nextcloud.host}:${CONFIG.nextcloud.port}`);
|
||||||
|
console.log(`📡 Redis: ${CONFIG.redis.host}:${CONFIG.redis.port}`);
|
||||||
|
console.log(`🔄 Интервал: ${CONFIG.pollInterval / 1000}с`);
|
||||||
|
console.log('════════════════════════════════════════════════════════════════════════════════\n');
|
||||||
|
|
||||||
|
await loadState();
|
||||||
|
|
||||||
|
console.log('👂 Начинаем мониторинг...\n');
|
||||||
|
|
||||||
|
// Первое сканирование
|
||||||
|
await scanActivities();
|
||||||
|
|
||||||
|
// Периодическое сканирование
|
||||||
|
setInterval(scanActivities, CONFIG.pollInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запуск при подключении к Redis
|
||||||
|
redis.on('connect', () => {
|
||||||
|
console.log('✅ Подключились к Redis\n');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
redis.on('error', (err) => {
|
||||||
|
console.error('❌ Redis ошибка:', err.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
console.log('\n\n⛔ Остановка мониторинга...');
|
||||||
|
redis.disconnect();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
console.log('\n\n⛔ Получен сигнал SIGTERM, останавливаемся...');
|
||||||
|
redis.disconnect();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
123
crm_extensions/file_storage/nextcloud_cache_updater.js
Executable file
123
crm_extensions/file_storage/nextcloud_cache_updater.js
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Nextcloud Cache Updater
|
||||||
|
*
|
||||||
|
* Подписывается на Redis канал crm:file:events
|
||||||
|
* При новом файле - обновляет кеш Nextcloud для этого файла
|
||||||
|
* БЕЗ полного сканирования всей папки!
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Redis = require('ioredis');
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
const util = require('util');
|
||||||
|
const execPromise = util.promisify(exec);
|
||||||
|
|
||||||
|
const CONFIG = {
|
||||||
|
redis: {
|
||||||
|
host: '147.45.146.17',
|
||||||
|
port: 6379,
|
||||||
|
password: 'CRM_Redis_Pass_2025_Secure!'
|
||||||
|
},
|
||||||
|
channel: 'crm:file:events',
|
||||||
|
nextcloudContainer: 'nextcloud-fresh'
|
||||||
|
};
|
||||||
|
|
||||||
|
const redis = new Redis(CONFIG.redis);
|
||||||
|
|
||||||
|
console.log('🔄 Nextcloud Cache Updater');
|
||||||
|
console.log('==========================================');
|
||||||
|
console.log(`📡 Подписка на: ${CONFIG.channel}`);
|
||||||
|
console.log(`🐳 Nextcloud: ${CONFIG.nextcloudContainer}`);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// Подписка на канал
|
||||||
|
redis.subscribe(CONFIG.channel, (err, count) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('❌ Ошибка подписки:', err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`✅ Подписка активна (${count} каналов)`);
|
||||||
|
console.log('⏳ Ожидание событий...\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработка событий
|
||||||
|
redis.on('message', async (channel, message) => {
|
||||||
|
try {
|
||||||
|
const event = JSON.parse(message);
|
||||||
|
|
||||||
|
// Логируем событие
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
console.log(`[${timestamp}] 📥 Событие:`);
|
||||||
|
console.log(` Type: ${event.type}`);
|
||||||
|
console.log(` Source: ${event.source}`);
|
||||||
|
console.log(` Path: ${event.path || event.filename}`);
|
||||||
|
|
||||||
|
// Обрабатываем только создание/изменение файлов
|
||||||
|
if (!['file_created', 'file_modified', 'file_update'].includes(event.type)) {
|
||||||
|
console.log(` ⏭️ Пропуск (не файловое событие)\n`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Извлекаем путь файла
|
||||||
|
let filePath = event.path || event.filename;
|
||||||
|
|
||||||
|
// Для событий из S3 Monitor - путь уже правильный
|
||||||
|
// Для событий из Nextcloud - может быть без префикса
|
||||||
|
|
||||||
|
// Формируем путь для Nextcloud
|
||||||
|
let ncPath = filePath;
|
||||||
|
if (!ncPath.startsWith('/')) {
|
||||||
|
ncPath = '/admin/files/crm/' + ncPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` 🔄 Обновление кеша Nextcloud...`);
|
||||||
|
console.log(` Путь: ${ncPath}`);
|
||||||
|
|
||||||
|
// Обновляем кеш только для этого файла
|
||||||
|
const command = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${ncPath}" 2>&1`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { stdout, stderr } = await execPromise(command);
|
||||||
|
|
||||||
|
if (stderr && !stderr.includes('Starting scan')) {
|
||||||
|
console.log(` ⚠️ Предупреждение: ${stderr}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` ✅ Кеш обновлён`);
|
||||||
|
|
||||||
|
// Дополнительно очищаем statcache для этой папки
|
||||||
|
const dirname = ncPath.substring(0, ncPath.lastIndexOf('/'));
|
||||||
|
const clearCommand = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${dirname}" --shallow 2>&1`;
|
||||||
|
await execPromise(clearCommand);
|
||||||
|
|
||||||
|
console.log(` ✅ Родительская папка обновлена\n`);
|
||||||
|
|
||||||
|
} catch (execError) {
|
||||||
|
console.error(` ❌ Ошибка обновления: ${execError.message}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Ошибка обработки события:`, error.message);
|
||||||
|
console.error(` Сообщение:`, message.substring(0, 200));
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработка ошибок
|
||||||
|
redis.on('error', (err) => {
|
||||||
|
console.error('❌ Redis ошибка:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Graceful shutdown
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
console.log('\n\n🛑 Остановка...');
|
||||||
|
redis.disconnect();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
console.log('\n\n🛑 Остановка...');
|
||||||
|
redis.disconnect();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
130
crm_extensions/file_storage/nextcloud_fileid_indexer.js
Executable file
130
crm_extensions/file_storage/nextcloud_fileid_indexer.js
Executable file
@@ -0,0 +1,130 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Nextcloud FileID Indexer
|
||||||
|
*
|
||||||
|
* Индексирует fileId из Nextcloud БД в Redis для быстрого доступа
|
||||||
|
* Структура: crm:nc:fileid:{path} => fileId
|
||||||
|
*/
|
||||||
|
|
||||||
|
const mysql = require('mysql2/promise');
|
||||||
|
const Redis = require('ioredis');
|
||||||
|
|
||||||
|
const CONFIG = {
|
||||||
|
nextcloud_db: {
|
||||||
|
host: '192.168.128.3',
|
||||||
|
user: 'nextcloud',
|
||||||
|
password: 'nextcloud_password',
|
||||||
|
database: 'nextcloud'
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
host: '147.45.146.17',
|
||||||
|
port: 6379,
|
||||||
|
password: 'CRM_Redis_Pass_2025_Secure!'
|
||||||
|
},
|
||||||
|
// Индексируем только файлы из этих папок
|
||||||
|
pathPrefixes: [
|
||||||
|
'files/crm/crm2/',
|
||||||
|
'files/crm/erv_app/'
|
||||||
|
],
|
||||||
|
indexInterval: 60000 // Обновляем индекс каждую минуту
|
||||||
|
};
|
||||||
|
|
||||||
|
const redis = new Redis(CONFIG.redis);
|
||||||
|
let connection = null;
|
||||||
|
|
||||||
|
async function connectDB() {
|
||||||
|
try {
|
||||||
|
connection = await mysql.createConnection(CONFIG.nextcloud_db);
|
||||||
|
console.log('✅ Подключились к БД Nextcloud');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('❌ Ошибка подключения к БД:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function indexFiles() {
|
||||||
|
try {
|
||||||
|
console.log(`\n🔍 Индексация файлов... (${new Date().toISOString()})`);
|
||||||
|
|
||||||
|
let totalIndexed = 0;
|
||||||
|
|
||||||
|
for (const prefix of CONFIG.pathPrefixes) {
|
||||||
|
// Получаем все файлы из этой папки
|
||||||
|
const [rows] = await connection.execute(
|
||||||
|
'SELECT fileid, path, name, size, mtime FROM oc_filecache WHERE path LIKE ? AND mimetype != 2',
|
||||||
|
[prefix + '%']
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(` 📁 ${prefix}: найдено ${rows.length} файлов`);
|
||||||
|
|
||||||
|
// Индексируем в Redis
|
||||||
|
const pipeline = redis.pipeline();
|
||||||
|
|
||||||
|
for (const row of rows) {
|
||||||
|
const key = `crm:nc:fileid:${row.path}`;
|
||||||
|
const value = JSON.stringify({
|
||||||
|
fileId: row.fileid,
|
||||||
|
name: row.name,
|
||||||
|
size: row.size,
|
||||||
|
mtime: row.mtime
|
||||||
|
});
|
||||||
|
|
||||||
|
// Храним 24 часа (обновляется каждую минуту)
|
||||||
|
pipeline.setex(key, 86400, value);
|
||||||
|
totalIndexed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pipeline.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ Проиндексировано: ${totalIndexed} файлов`);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('❌ Ошибка индексации:', err.message);
|
||||||
|
console.error(err.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function start() {
|
||||||
|
console.log('🚀 Nextcloud FileID Indexer');
|
||||||
|
console.log('════════════════════════════════════════════════════════════════════════════════');
|
||||||
|
console.log(`🗄️ Nextcloud DB: ${CONFIG.nextcloud_db.host}/${CONFIG.nextcloud_db.database}`);
|
||||||
|
console.log(`📡 Redis: ${CONFIG.redis.host}:${CONFIG.redis.port}`);
|
||||||
|
console.log(`🔄 Интервал: ${CONFIG.indexInterval / 1000}с`);
|
||||||
|
console.log('════════════════════════════════════════════════════════════════════════════════\n');
|
||||||
|
|
||||||
|
await connectDB();
|
||||||
|
|
||||||
|
console.log('👂 Начинаем индексацию...\n');
|
||||||
|
|
||||||
|
// Первая индексация
|
||||||
|
await indexFiles();
|
||||||
|
|
||||||
|
// Периодическая индексация
|
||||||
|
setInterval(indexFiles, CONFIG.indexInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запуск
|
||||||
|
redis.on('connect', () => {
|
||||||
|
console.log('✅ Подключились к Redis\n');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
redis.on('error', (err) => {
|
||||||
|
console.error('❌ Redis ошибка:', err.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGINT', async () => {
|
||||||
|
console.log('\n\n⛔ Остановка индексатора...');
|
||||||
|
if (connection) await connection.end();
|
||||||
|
redis.disconnect();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGTERM', async () => {
|
||||||
|
console.log('\n\n⛔ Остановка индексатора...');
|
||||||
|
if (connection) await connection.end();
|
||||||
|
redis.disconnect();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
1
crm_extensions/file_storage/node_modules/.bin/fxparser
generated
vendored
Symbolic link
1
crm_extensions/file_storage/node_modules/.bin/fxparser
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../fast-xml-parser/src/cli/cli.js
|
||||||
1870
crm_extensions/file_storage/node_modules/.package-lock.json
generated
vendored
Normal file
1870
crm_extensions/file_storage/node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
100
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/CHANGELOG.md
generated
vendored
Normal file
100
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
|
||||||
|
|
||||||
|
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
|
||||||
|
|
||||||
|
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
|
||||||
|
|
||||||
|
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
- All classes that implemented `Hash` now implement `Checksum`.
|
||||||
|
|
||||||
|
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.0...v2.0.1) (2021-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
## [1.2.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.1...v1.2.2) (2021-10-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **crc32c:** ie11 does not support Array.from ([#221](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/221)) ([5f49547](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/5f495472ab8988cf203e0f2a70a51f7e1fcd7e60))
|
||||||
|
|
||||||
|
## [1.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.0...v1.2.1) (2021-09-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add AwsCrc32 Hash ([f5d7e81](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/f5d7e815fcbe0f8da1edb855fea3bd33eb1edc15))
|
||||||
|
|
||||||
|
# [1.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@1.0.0...@aws-crypto/crc32@1.1.0) (2021-08-11)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Create CRC-32C implementation ([#201](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/201)) ([e43c7ec](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e43c7ecd30d6499fa696f5839ecc30502a34b8b6))
|
||||||
|
|
||||||
|
# [1.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@1.0.0-alpha.0...@aws-crypto/crc32@1.0.0) (2020-10-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
# [1.0.0-alpha.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.4...@aws-crypto/crc32@1.0.0-alpha.0) (2020-02-07)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32
|
||||||
|
|
||||||
|
# [0.1.0-preview.4](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.2...@aws-crypto/crc32@0.1.0-preview.4) (2020-01-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Changed package.json files to point to the right Git repo ([#9](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/9)) ([028245d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/028245d72e642ca98d82226afb300eb154503c4a)), closes [#8](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/8)
|
||||||
|
- lerna version maintains package-lock ([#14](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/14)) ([2ef29e1](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/2ef29e13779703a5c9b32e93d18918fcb33b7272)), closes [#13](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/13)
|
||||||
|
|
||||||
|
# [0.1.0-preview.3](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.2...@aws-crypto/crc32@0.1.0-preview.3) (2019-11-15)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Changed package.json files to point to the right Git repo ([#9](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/9)) ([028245d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/028245d72e642ca98d82226afb300eb154503c4a)), closes [#8](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/8)
|
||||||
|
- lerna version maintains package-lock ([#14](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/14)) ([2ef29e1](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/2ef29e13779703a5c9b32e93d18918fcb33b7272)), closes [#13](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/13)
|
||||||
|
|
||||||
|
# [0.1.0-preview.2](https://github.com/aws/aws-javascript-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.1...@aws-crypto/crc32@0.1.0-preview.2) (2019-10-30)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- remove /src/ from .npmignore (for sourcemaps) ([#5](https://github.com/aws/aws-javascript-crypto-helpers/issues/5)) ([ec52056](https://github.com/aws/aws-javascript-crypto-helpers/commit/ec52056))
|
||||||
201
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/LICENSE
generated
vendored
Normal file
201
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
16
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/README.md
generated
vendored
Normal file
16
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/README.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# @aws-crypto/crc32
|
||||||
|
|
||||||
|
Pure JS implementation of CRC32 https://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
import { Crc32 } from '@aws-crypto/crc32';
|
||||||
|
|
||||||
|
const crc32Digest = (new Crc32).update(buffer).digest()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
`npm test`
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/aws_crc32.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/aws_crc32.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { SourceData, Checksum } from "@aws-sdk/types";
|
||||||
|
export declare class AwsCrc32 implements Checksum {
|
||||||
|
private crc32;
|
||||||
|
update(toHash: SourceData): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
31
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/aws_crc32.js
generated
vendored
Normal file
31
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/aws_crc32.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AwsCrc32 = void 0;
|
||||||
|
var tslib_1 = require("tslib");
|
||||||
|
var util_1 = require("@aws-crypto/util");
|
||||||
|
var index_1 = require("./index");
|
||||||
|
var AwsCrc32 = /** @class */ (function () {
|
||||||
|
function AwsCrc32() {
|
||||||
|
this.crc32 = new index_1.Crc32();
|
||||||
|
}
|
||||||
|
AwsCrc32.prototype.update = function (toHash) {
|
||||||
|
if ((0, util_1.isEmptyData)(toHash))
|
||||||
|
return;
|
||||||
|
this.crc32.update((0, util_1.convertToBuffer)(toHash));
|
||||||
|
};
|
||||||
|
AwsCrc32.prototype.digest = function () {
|
||||||
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
|
return tslib_1.__generator(this, function (_a) {
|
||||||
|
return [2 /*return*/, (0, util_1.numToUint8)(this.crc32.digest())];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
AwsCrc32.prototype.reset = function () {
|
||||||
|
this.crc32 = new index_1.Crc32();
|
||||||
|
};
|
||||||
|
return AwsCrc32;
|
||||||
|
}());
|
||||||
|
exports.AwsCrc32 = AwsCrc32;
|
||||||
|
//# sourceMappingURL=aws_crc32.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/aws_crc32.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/aws_crc32.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"aws_crc32.js","sourceRoot":"","sources":["../../src/aws_crc32.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAGtC,yCAA4E;AAC5E,iCAAgC;AAEhC;IAAA;QACU,UAAK,GAAG,IAAI,aAAK,EAAE,CAAC;IAe9B,CAAC;IAbC,yBAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,IAAA,kBAAW,EAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEK,yBAAM,GAAZ;;;gBACE,sBAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACxC;IAED,wBAAK,GAAL;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,aAAK,EAAE,CAAC;IAC3B,CAAC;IACH,eAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,4BAAQ"}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/index.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export declare function crc32(data: Uint8Array): number;
|
||||||
|
export declare class Crc32 {
|
||||||
|
private checksum;
|
||||||
|
update(data: Uint8Array): this;
|
||||||
|
digest(): number;
|
||||||
|
}
|
||||||
|
export { AwsCrc32 } from "./aws_crc32";
|
||||||
108
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/index.js
generated
vendored
Normal file
108
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/index.js
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AwsCrc32 = exports.Crc32 = exports.crc32 = void 0;
|
||||||
|
var tslib_1 = require("tslib");
|
||||||
|
var util_1 = require("@aws-crypto/util");
|
||||||
|
function crc32(data) {
|
||||||
|
return new Crc32().update(data).digest();
|
||||||
|
}
|
||||||
|
exports.crc32 = crc32;
|
||||||
|
var Crc32 = /** @class */ (function () {
|
||||||
|
function Crc32() {
|
||||||
|
this.checksum = 0xffffffff;
|
||||||
|
}
|
||||||
|
Crc32.prototype.update = function (data) {
|
||||||
|
var e_1, _a;
|
||||||
|
try {
|
||||||
|
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
|
||||||
|
var byte = data_1_1.value;
|
||||||
|
this.checksum =
|
||||||
|
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
|
||||||
|
}
|
||||||
|
finally { if (e_1) throw e_1.error; }
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
Crc32.prototype.digest = function () {
|
||||||
|
return (this.checksum ^ 0xffffffff) >>> 0;
|
||||||
|
};
|
||||||
|
return Crc32;
|
||||||
|
}());
|
||||||
|
exports.Crc32 = Crc32;
|
||||||
|
// prettier-ignore
|
||||||
|
var a_lookUpTable = [
|
||||||
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||||
|
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||||
|
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||||
|
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||||
|
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||||
|
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||||
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||||
|
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||||
|
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||||
|
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||||
|
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||||
|
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||||
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||||
|
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||||
|
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||||
|
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||||
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||||
|
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||||
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||||
|
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||||
|
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||||
|
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||||
|
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||||
|
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||||
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||||
|
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||||
|
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||||
|
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||||
|
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||||
|
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||||
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||||
|
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||||
|
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||||
|
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||||
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||||
|
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||||
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||||
|
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||||
|
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||||
|
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||||
|
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||||
|
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||||
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||||
|
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||||
|
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||||
|
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||||
|
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||||
|
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||||
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||||
|
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||||
|
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||||
|
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||||
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||||
|
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||||
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||||
|
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||||
|
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||||
|
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||||
|
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||||
|
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||||
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||||
|
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||||
|
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||||
|
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||||
|
];
|
||||||
|
var lookupTable = (0, util_1.uint32ArrayFrom)(a_lookUpTable);
|
||||||
|
var aws_crc32_1 = require("./aws_crc32");
|
||||||
|
Object.defineProperty(exports, "AwsCrc32", { enumerable: true, get: function () { return aws_crc32_1.AwsCrc32; } });
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/index.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/main/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;AAAA,yCAAiD;AAEjD,SAAgB,KAAK,CAAC,IAAgB;IACpC,OAAO,IAAI,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAFD,sBAEC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,sBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,iBAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,YAAC;AAAD,CAAC,AAfD,IAeC;AAfY,sBAAK;AAiBlB,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC;AACF,IAAM,WAAW,GAAgB,IAAA,sBAAe,EAAC,aAAa,CAAC,CAAA;AAC/D,yCAAuC;AAA9B,qGAAA,QAAQ,OAAA"}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/aws_crc32.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/aws_crc32.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { SourceData, Checksum } from "@aws-sdk/types";
|
||||||
|
export declare class AwsCrc32 implements Checksum {
|
||||||
|
private crc32;
|
||||||
|
update(toHash: SourceData): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
28
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/aws_crc32.js
generated
vendored
Normal file
28
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/aws_crc32.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
import { __awaiter, __generator } from "tslib";
|
||||||
|
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
|
||||||
|
import { Crc32 } from "./index";
|
||||||
|
var AwsCrc32 = /** @class */ (function () {
|
||||||
|
function AwsCrc32() {
|
||||||
|
this.crc32 = new Crc32();
|
||||||
|
}
|
||||||
|
AwsCrc32.prototype.update = function (toHash) {
|
||||||
|
if (isEmptyData(toHash))
|
||||||
|
return;
|
||||||
|
this.crc32.update(convertToBuffer(toHash));
|
||||||
|
};
|
||||||
|
AwsCrc32.prototype.digest = function () {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
return [2 /*return*/, numToUint8(this.crc32.digest())];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
AwsCrc32.prototype.reset = function () {
|
||||||
|
this.crc32 = new Crc32();
|
||||||
|
};
|
||||||
|
return AwsCrc32;
|
||||||
|
}());
|
||||||
|
export { AwsCrc32 };
|
||||||
|
//# sourceMappingURL=aws_crc32.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/aws_crc32.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/aws_crc32.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"aws_crc32.js","sourceRoot":"","sources":["../../src/aws_crc32.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAGtC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;IAAA;QACU,UAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAe9B,CAAC;IAbC,yBAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEK,yBAAM,GAAZ;;;gBACE,sBAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACxC;IAED,wBAAK,GAAL;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC3B,CAAC;IACH,eAAC;AAAD,CAAC,AAhBD,IAgBC"}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/index.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export declare function crc32(data: Uint8Array): number;
|
||||||
|
export declare class Crc32 {
|
||||||
|
private checksum;
|
||||||
|
update(data: Uint8Array): this;
|
||||||
|
digest(): number;
|
||||||
|
}
|
||||||
|
export { AwsCrc32 } from "./aws_crc32";
|
||||||
103
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/index.js
generated
vendored
Normal file
103
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/index.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import { __values } from "tslib";
|
||||||
|
import { uint32ArrayFrom } from "@aws-crypto/util";
|
||||||
|
export function crc32(data) {
|
||||||
|
return new Crc32().update(data).digest();
|
||||||
|
}
|
||||||
|
var Crc32 = /** @class */ (function () {
|
||||||
|
function Crc32() {
|
||||||
|
this.checksum = 0xffffffff;
|
||||||
|
}
|
||||||
|
Crc32.prototype.update = function (data) {
|
||||||
|
var e_1, _a;
|
||||||
|
try {
|
||||||
|
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
|
||||||
|
var byte = data_1_1.value;
|
||||||
|
this.checksum =
|
||||||
|
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
|
||||||
|
}
|
||||||
|
finally { if (e_1) throw e_1.error; }
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
Crc32.prototype.digest = function () {
|
||||||
|
return (this.checksum ^ 0xffffffff) >>> 0;
|
||||||
|
};
|
||||||
|
return Crc32;
|
||||||
|
}());
|
||||||
|
export { Crc32 };
|
||||||
|
// prettier-ignore
|
||||||
|
var a_lookUpTable = [
|
||||||
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||||
|
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||||
|
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||||
|
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||||
|
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||||
|
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||||
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||||
|
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||||
|
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||||
|
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||||
|
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||||
|
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||||
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||||
|
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||||
|
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||||
|
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||||
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||||
|
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||||
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||||
|
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||||
|
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||||
|
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||||
|
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||||
|
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||||
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||||
|
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||||
|
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||||
|
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||||
|
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||||
|
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||||
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||||
|
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||||
|
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||||
|
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||||
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||||
|
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||||
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||||
|
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||||
|
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||||
|
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||||
|
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||||
|
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||||
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||||
|
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||||
|
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||||
|
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||||
|
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||||
|
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||||
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||||
|
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||||
|
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||||
|
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||||
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||||
|
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||||
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||||
|
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||||
|
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||||
|
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||||
|
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||||
|
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||||
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||||
|
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||||
|
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||||
|
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||||
|
];
|
||||||
|
var lookupTable = uint32ArrayFrom(a_lookUpTable);
|
||||||
|
export { AwsCrc32 } from "./aws_crc32";
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/index.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/build/module/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,KAAK,CAAC,IAAgB;IACpC,OAAO,IAAI,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,sBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,SAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,YAAC;AAAD,CAAC,AAfD,IAeC;;AAED,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC;AACF,IAAM,WAAW,GAAgB,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
||||||
32
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/package.json
generated
vendored
Normal file
32
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/package.json
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@aws-crypto/crc32",
|
||||||
|
"version": "5.2.0",
|
||||||
|
"scripts": {
|
||||||
|
"prepublishOnly": "tsc -p tsconfig.json && tsc -p tsconfig.module.json",
|
||||||
|
"pretest": "tsc -p tsconfig.test.json",
|
||||||
|
"test": "mocha --require ts-node/register test/**/*test.ts"
|
||||||
|
},
|
||||||
|
"main": "./build/main/index.js",
|
||||||
|
"module": "./build/module/index.js",
|
||||||
|
"types": "./build/main/index.d.ts",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:aws/aws-sdk-js-crypto-helpers.git"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "AWS Crypto Tools Team",
|
||||||
|
"email": "aws-cryptools@amazon.com",
|
||||||
|
"url": "https://docs.aws.amazon.com/aws-crypto-tools/index.html?id=docs_gateway#lang/en_us"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/aws/aws-sdk-js-crypto-helpers/tree/master/packages/crc32",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-crypto/util": "^5.2.0",
|
||||||
|
"@aws-sdk/types": "^3.222.0",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
},
|
||||||
|
"gitHead": "c11b171b35ec5c093364f0e0d8dc4ab1af68e748"
|
||||||
|
}
|
||||||
24
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/src/aws_crc32.ts
generated
vendored
Normal file
24
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/src/aws_crc32.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { SourceData, Checksum } from "@aws-sdk/types";
|
||||||
|
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
|
||||||
|
import { Crc32 } from "./index";
|
||||||
|
|
||||||
|
export class AwsCrc32 implements Checksum {
|
||||||
|
private crc32 = new Crc32();
|
||||||
|
|
||||||
|
update(toHash: SourceData) {
|
||||||
|
if (isEmptyData(toHash)) return;
|
||||||
|
|
||||||
|
this.crc32.update(convertToBuffer(toHash));
|
||||||
|
}
|
||||||
|
|
||||||
|
async digest(): Promise<Uint8Array> {
|
||||||
|
return numToUint8(this.crc32.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.crc32 = new Crc32();
|
||||||
|
}
|
||||||
|
}
|
||||||
92
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/src/index.ts
generated
vendored
Normal file
92
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import {uint32ArrayFrom} from "@aws-crypto/util";
|
||||||
|
|
||||||
|
export function crc32(data: Uint8Array): number {
|
||||||
|
return new Crc32().update(data).digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Crc32 {
|
||||||
|
private checksum = 0xffffffff;
|
||||||
|
|
||||||
|
update(data: Uint8Array): this {
|
||||||
|
for (const byte of data) {
|
||||||
|
this.checksum =
|
||||||
|
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
digest(): number {
|
||||||
|
return (this.checksum ^ 0xffffffff) >>> 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const a_lookUpTable = [
|
||||||
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||||
|
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||||
|
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||||
|
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||||
|
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||||
|
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||||
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||||
|
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||||
|
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||||
|
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||||
|
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||||
|
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||||
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||||
|
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||||
|
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||||
|
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||||
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||||
|
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||||
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||||
|
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||||
|
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||||
|
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||||
|
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||||
|
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||||
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||||
|
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||||
|
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||||
|
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||||
|
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||||
|
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||||
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||||
|
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||||
|
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||||
|
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||||
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||||
|
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||||
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||||
|
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||||
|
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||||
|
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||||
|
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||||
|
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||||
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||||
|
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||||
|
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||||
|
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||||
|
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||||
|
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||||
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||||
|
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||||
|
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||||
|
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||||
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||||
|
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||||
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||||
|
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||||
|
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||||
|
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||||
|
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||||
|
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||||
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||||
|
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||||
|
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||||
|
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||||
|
];
|
||||||
|
const lookupTable: Uint32Array = uint32ArrayFrom(a_lookUpTable)
|
||||||
|
export { AwsCrc32 } from "./aws_crc32";
|
||||||
9
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/tsconfig.json
generated
vendored
Normal file
9
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/tsconfig.json
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./build/main",
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["node_modules/**"]
|
||||||
|
}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/tsconfig.module.json
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32/tsconfig.module.json
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "build/module",
|
||||||
|
"module": "esnext",
|
||||||
|
}
|
||||||
|
}
|
||||||
76
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/CHANGELOG.md
generated
vendored
Normal file
76
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
|
||||||
|
|
||||||
|
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
|
||||||
|
|
||||||
|
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32c
|
||||||
|
|
||||||
|
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32c
|
||||||
|
|
||||||
|
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
|
||||||
|
|
||||||
|
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
- All classes that implemented `Hash` now implement `Checksum`.
|
||||||
|
|
||||||
|
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.0...v2.0.1) (2021-12-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32c
|
||||||
|
|
||||||
|
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32c
|
||||||
|
|
||||||
|
## [1.2.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.1...v1.2.2) (2021-10-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **crc32c:** ie11 does not support Array.from ([#221](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/221)) ([5f49547](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/5f495472ab8988cf203e0f2a70a51f7e1fcd7e60))
|
||||||
|
|
||||||
|
## [1.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.0...v1.2.1) (2021-09-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32c
|
||||||
|
|
||||||
|
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add AwsCrc32C Hash ([4840c83](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/4840c83bdd7c461dded777ebc45a8f99258ba21c))
|
||||||
|
|
||||||
|
## [0.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32c@0.2.0...@aws-crypto/crc32c@0.2.1) (2021-08-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/crc32c
|
||||||
|
|
||||||
|
# 0.2.0 (2021-08-11)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Create CRC-32C implementation ([#201](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/201)) ([e43c7ec](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e43c7ecd30d6499fa696f5839ecc30502a34b8b6))
|
||||||
201
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/LICENSE
generated
vendored
Normal file
201
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
16
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/README.md
generated
vendored
Normal file
16
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/README.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# @aws-crypto/crc32c
|
||||||
|
|
||||||
|
Pure JS implementation of CRC32-C https://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
import { Crc32c } from '@aws-crypto/crc32c';
|
||||||
|
|
||||||
|
const crc32Digest = (new Crc32c).update(buffer).digest()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
`npm test`
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/aws_crc32c.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/aws_crc32c.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { Checksum, SourceData } from "@aws-sdk/types";
|
||||||
|
export declare class AwsCrc32c implements Checksum {
|
||||||
|
private crc32c;
|
||||||
|
update(toHash: SourceData): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
31
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/aws_crc32c.js
generated
vendored
Normal file
31
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/aws_crc32c.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AwsCrc32c = void 0;
|
||||||
|
var tslib_1 = require("tslib");
|
||||||
|
var util_1 = require("@aws-crypto/util");
|
||||||
|
var index_1 = require("./index");
|
||||||
|
var AwsCrc32c = /** @class */ (function () {
|
||||||
|
function AwsCrc32c() {
|
||||||
|
this.crc32c = new index_1.Crc32c();
|
||||||
|
}
|
||||||
|
AwsCrc32c.prototype.update = function (toHash) {
|
||||||
|
if ((0, util_1.isEmptyData)(toHash))
|
||||||
|
return;
|
||||||
|
this.crc32c.update((0, util_1.convertToBuffer)(toHash));
|
||||||
|
};
|
||||||
|
AwsCrc32c.prototype.digest = function () {
|
||||||
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
|
return tslib_1.__generator(this, function (_a) {
|
||||||
|
return [2 /*return*/, (0, util_1.numToUint8)(this.crc32c.digest())];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
AwsCrc32c.prototype.reset = function () {
|
||||||
|
this.crc32c = new index_1.Crc32c();
|
||||||
|
};
|
||||||
|
return AwsCrc32c;
|
||||||
|
}());
|
||||||
|
exports.AwsCrc32c = AwsCrc32c;
|
||||||
|
//# sourceMappingURL=aws_crc32c.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/aws_crc32c.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/aws_crc32c.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"aws_crc32c.js","sourceRoot":"","sources":["../../src/aws_crc32c.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAGtC,yCAA4E;AAC5E,iCAAiC;AAEjC;IAAA;QACU,WAAM,GAAG,IAAI,cAAM,EAAE,CAAC;IAehC,CAAC;IAbC,0BAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,IAAA,kBAAW,EAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEK,0BAAM,GAAZ;;;gBACE,sBAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACzC;IAED,yBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,cAAM,EAAE,CAAC;IAC7B,CAAC;IACH,gBAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,8BAAS"}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/index.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export declare function crc32c(data: Uint8Array): number;
|
||||||
|
export declare class Crc32c {
|
||||||
|
private checksum;
|
||||||
|
update(data: Uint8Array): this;
|
||||||
|
digest(): number;
|
||||||
|
}
|
||||||
|
export { AwsCrc32c } from "./aws_crc32c";
|
||||||
78
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/index.js
generated
vendored
Normal file
78
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/index.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
"use strict";
|
||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AwsCrc32c = exports.Crc32c = exports.crc32c = void 0;
|
||||||
|
var tslib_1 = require("tslib");
|
||||||
|
var util_1 = require("@aws-crypto/util");
|
||||||
|
function crc32c(data) {
|
||||||
|
return new Crc32c().update(data).digest();
|
||||||
|
}
|
||||||
|
exports.crc32c = crc32c;
|
||||||
|
var Crc32c = /** @class */ (function () {
|
||||||
|
function Crc32c() {
|
||||||
|
this.checksum = 0xffffffff;
|
||||||
|
}
|
||||||
|
Crc32c.prototype.update = function (data) {
|
||||||
|
var e_1, _a;
|
||||||
|
try {
|
||||||
|
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
|
||||||
|
var byte = data_1_1.value;
|
||||||
|
this.checksum =
|
||||||
|
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
|
||||||
|
}
|
||||||
|
finally { if (e_1) throw e_1.error; }
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
Crc32c.prototype.digest = function () {
|
||||||
|
return (this.checksum ^ 0xffffffff) >>> 0;
|
||||||
|
};
|
||||||
|
return Crc32c;
|
||||||
|
}());
|
||||||
|
exports.Crc32c = Crc32c;
|
||||||
|
// prettier-ignore
|
||||||
|
var a_lookupTable = [
|
||||||
|
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
|
||||||
|
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
|
||||||
|
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
|
||||||
|
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
|
||||||
|
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
|
||||||
|
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
|
||||||
|
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
|
||||||
|
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
|
||||||
|
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
|
||||||
|
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
|
||||||
|
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
|
||||||
|
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
|
||||||
|
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
|
||||||
|
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
|
||||||
|
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
|
||||||
|
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
|
||||||
|
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
|
||||||
|
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
|
||||||
|
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
|
||||||
|
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
|
||||||
|
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
|
||||||
|
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
|
||||||
|
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
|
||||||
|
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
|
||||||
|
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
|
||||||
|
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
|
||||||
|
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
|
||||||
|
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
|
||||||
|
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
|
||||||
|
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
|
||||||
|
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
|
||||||
|
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
|
||||||
|
];
|
||||||
|
var lookupTable = (0, util_1.uint32ArrayFrom)(a_lookupTable);
|
||||||
|
var aws_crc32c_1 = require("./aws_crc32c");
|
||||||
|
Object.defineProperty(exports, "AwsCrc32c", { enumerable: true, get: function () { return aws_crc32c_1.AwsCrc32c; } });
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/index.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/main/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAEtC,yCAAiD;AAEjD,SAAgB,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAFD,wBAEC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,uBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,iBAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,aAAC;AAAD,CAAC,AAfD,IAeC;AAfY,wBAAM;AAiBnB,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/F,CAAC;AAEF,IAAM,WAAW,GAAgB,IAAA,sBAAe,EAAC,aAAa,CAAC,CAAA;AAC/D,2CAAyC;AAAhC,uGAAA,SAAS,OAAA"}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/aws_crc32c.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/aws_crc32c.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { Checksum, SourceData } from "@aws-sdk/types";
|
||||||
|
export declare class AwsCrc32c implements Checksum {
|
||||||
|
private crc32c;
|
||||||
|
update(toHash: SourceData): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
28
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/aws_crc32c.js
generated
vendored
Normal file
28
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/aws_crc32c.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
import { __awaiter, __generator } from "tslib";
|
||||||
|
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
|
||||||
|
import { Crc32c } from "./index";
|
||||||
|
var AwsCrc32c = /** @class */ (function () {
|
||||||
|
function AwsCrc32c() {
|
||||||
|
this.crc32c = new Crc32c();
|
||||||
|
}
|
||||||
|
AwsCrc32c.prototype.update = function (toHash) {
|
||||||
|
if (isEmptyData(toHash))
|
||||||
|
return;
|
||||||
|
this.crc32c.update(convertToBuffer(toHash));
|
||||||
|
};
|
||||||
|
AwsCrc32c.prototype.digest = function () {
|
||||||
|
return __awaiter(this, void 0, void 0, function () {
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
return [2 /*return*/, numToUint8(this.crc32c.digest())];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
AwsCrc32c.prototype.reset = function () {
|
||||||
|
this.crc32c = new Crc32c();
|
||||||
|
};
|
||||||
|
return AwsCrc32c;
|
||||||
|
}());
|
||||||
|
export { AwsCrc32c };
|
||||||
|
//# sourceMappingURL=aws_crc32c.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/aws_crc32c.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/aws_crc32c.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"aws_crc32c.js","sourceRoot":"","sources":["../../src/aws_crc32c.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAGtC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC;IAAA;QACU,WAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAehC,CAAC;IAbC,0BAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEK,0BAAM,GAAZ;;;gBACE,sBAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACzC;IAED,yBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC7B,CAAC;IACH,gBAAC;AAAD,CAAC,AAhBD,IAgBC"}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/index.d.ts
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export declare function crc32c(data: Uint8Array): number;
|
||||||
|
export declare class Crc32c {
|
||||||
|
private checksum;
|
||||||
|
update(data: Uint8Array): this;
|
||||||
|
digest(): number;
|
||||||
|
}
|
||||||
|
export { AwsCrc32c } from "./aws_crc32c";
|
||||||
73
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/index.js
generated
vendored
Normal file
73
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/index.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
import { __values } from "tslib";
|
||||||
|
import { uint32ArrayFrom } from "@aws-crypto/util";
|
||||||
|
export function crc32c(data) {
|
||||||
|
return new Crc32c().update(data).digest();
|
||||||
|
}
|
||||||
|
var Crc32c = /** @class */ (function () {
|
||||||
|
function Crc32c() {
|
||||||
|
this.checksum = 0xffffffff;
|
||||||
|
}
|
||||||
|
Crc32c.prototype.update = function (data) {
|
||||||
|
var e_1, _a;
|
||||||
|
try {
|
||||||
|
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
|
||||||
|
var byte = data_1_1.value;
|
||||||
|
this.checksum =
|
||||||
|
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
|
||||||
|
}
|
||||||
|
finally { if (e_1) throw e_1.error; }
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
Crc32c.prototype.digest = function () {
|
||||||
|
return (this.checksum ^ 0xffffffff) >>> 0;
|
||||||
|
};
|
||||||
|
return Crc32c;
|
||||||
|
}());
|
||||||
|
export { Crc32c };
|
||||||
|
// prettier-ignore
|
||||||
|
var a_lookupTable = [
|
||||||
|
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
|
||||||
|
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
|
||||||
|
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
|
||||||
|
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
|
||||||
|
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
|
||||||
|
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
|
||||||
|
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
|
||||||
|
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
|
||||||
|
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
|
||||||
|
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
|
||||||
|
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
|
||||||
|
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
|
||||||
|
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
|
||||||
|
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
|
||||||
|
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
|
||||||
|
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
|
||||||
|
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
|
||||||
|
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
|
||||||
|
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
|
||||||
|
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
|
||||||
|
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
|
||||||
|
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
|
||||||
|
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
|
||||||
|
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
|
||||||
|
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
|
||||||
|
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
|
||||||
|
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
|
||||||
|
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
|
||||||
|
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
|
||||||
|
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
|
||||||
|
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
|
||||||
|
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
|
||||||
|
];
|
||||||
|
var lookupTable = uint32ArrayFrom(a_lookupTable);
|
||||||
|
export { AwsCrc32c } from "./aws_crc32c";
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/index.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/build/module/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAEtC,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,uBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,SAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,aAAC;AAAD,CAAC,AAfD,IAeC;;AAED,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/F,CAAC;AAEF,IAAM,WAAW,GAAgB,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
||||||
32
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/package.json
generated
vendored
Normal file
32
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/package.json
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@aws-crypto/crc32c",
|
||||||
|
"version": "5.2.0",
|
||||||
|
"scripts": {
|
||||||
|
"prepublishOnly": "tsc -p tsconfig.json && tsc -p tsconfig.module.json",
|
||||||
|
"pretest": "tsc -p tsconfig.test.json",
|
||||||
|
"test": "mocha --require ts-node/register test/**/*test.ts"
|
||||||
|
},
|
||||||
|
"main": "./build/main/index.js",
|
||||||
|
"module": "./build/module/index.js",
|
||||||
|
"types": "./build/main/index.d.ts",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:aws/aws-sdk-js-crypto-helpers.git"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "AWS Crypto Tools Team",
|
||||||
|
"email": "aws-cryptools@amazon.com",
|
||||||
|
"url": "https://docs.aws.amazon.com/aws-crypto-tools/index.html?id=docs_gateway#lang/en_us"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/aws/aws-sdk-js-crypto-helpers/tree/master/packages/crc32c",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-crypto/util": "^5.2.0",
|
||||||
|
"@aws-sdk/types": "^3.222.0",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"gitHead": "c11b171b35ec5c093364f0e0d8dc4ab1af68e748"
|
||||||
|
}
|
||||||
24
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/src/aws_crc32c.ts
generated
vendored
Normal file
24
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/src/aws_crc32c.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { Checksum, SourceData } from "@aws-sdk/types";
|
||||||
|
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
|
||||||
|
import { Crc32c } from "./index";
|
||||||
|
|
||||||
|
export class AwsCrc32c implements Checksum {
|
||||||
|
private crc32c = new Crc32c();
|
||||||
|
|
||||||
|
update(toHash: SourceData) {
|
||||||
|
if (isEmptyData(toHash)) return;
|
||||||
|
|
||||||
|
this.crc32c.update(convertToBuffer(toHash));
|
||||||
|
}
|
||||||
|
|
||||||
|
async digest(): Promise<Uint8Array> {
|
||||||
|
return numToUint8(this.crc32c.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.crc32c = new Crc32c();
|
||||||
|
}
|
||||||
|
}
|
||||||
64
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/src/index.ts
generated
vendored
Normal file
64
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import {uint32ArrayFrom} from "@aws-crypto/util";
|
||||||
|
|
||||||
|
export function crc32c(data: Uint8Array): number {
|
||||||
|
return new Crc32c().update(data).digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Crc32c {
|
||||||
|
private checksum = 0xffffffff;
|
||||||
|
|
||||||
|
update(data: Uint8Array): this {
|
||||||
|
for (const byte of data) {
|
||||||
|
this.checksum =
|
||||||
|
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
digest(): number {
|
||||||
|
return (this.checksum ^ 0xffffffff) >>> 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const a_lookupTable = [
|
||||||
|
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
|
||||||
|
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
|
||||||
|
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
|
||||||
|
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
|
||||||
|
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
|
||||||
|
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
|
||||||
|
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
|
||||||
|
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
|
||||||
|
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
|
||||||
|
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
|
||||||
|
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
|
||||||
|
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
|
||||||
|
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
|
||||||
|
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
|
||||||
|
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
|
||||||
|
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
|
||||||
|
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
|
||||||
|
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
|
||||||
|
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
|
||||||
|
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
|
||||||
|
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
|
||||||
|
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
|
||||||
|
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
|
||||||
|
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
|
||||||
|
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
|
||||||
|
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
|
||||||
|
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
|
||||||
|
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
|
||||||
|
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
|
||||||
|
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
|
||||||
|
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
|
||||||
|
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
|
||||||
|
];
|
||||||
|
|
||||||
|
const lookupTable: Uint32Array = uint32ArrayFrom(a_lookupTable)
|
||||||
|
export { AwsCrc32c } from "./aws_crc32c";
|
||||||
9
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/tsconfig.json
generated
vendored
Normal file
9
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/tsconfig.json
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./build/main",
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["node_modules/**"]
|
||||||
|
}
|
||||||
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/tsconfig.module.json
generated
vendored
Normal file
7
crm_extensions/file_storage/node_modules/@aws-crypto/crc32c/tsconfig.module.json
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "build/module",
|
||||||
|
"module": "esnext",
|
||||||
|
}
|
||||||
|
}
|
||||||
62
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/CHANGELOG.md
generated
vendored
Normal file
62
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
|
||||||
|
|
||||||
|
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
|
||||||
|
|
||||||
|
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
|
||||||
|
|
||||||
|
- feat!: drop support for IE 11 (#629) ([6c49fb6](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/6c49fb6c1b1f18bbff02dbd77a37a21bdb40c959)), closes [#629](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/629)
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
- Remove support for IE11
|
||||||
|
|
||||||
|
Co-authored-by: texastony <5892063+texastony@users.noreply.github.com>
|
||||||
|
|
||||||
|
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/sha1-browser
|
||||||
|
|
||||||
|
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
|
||||||
|
|
||||||
|
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
- All classes that implemented `Hash` now implement `Checksum`.
|
||||||
|
|
||||||
|
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
|
||||||
|
|
||||||
|
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @aws-crypto/sha1-browser
|
||||||
|
|
||||||
|
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Adding ie11-detection dependency to sha1-browser ([#213](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/213)) ([138750d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/138750d96385b8cc479b6f54c500ee1b5380648c))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add SHA1 ([#208](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/208)) ([45c50ff](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/45c50ffa3acc9e3bf4039ab59a0102e4d40455ec))
|
||||||
202
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/LICENSE
generated
vendored
Normal file
202
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
21
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/README.md
generated
vendored
Normal file
21
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/README.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# @aws-crypto/sha1-browser
|
||||||
|
|
||||||
|
SHA1 wrapper for browsers that prefers `window.crypto.subtle`.
|
||||||
|
|
||||||
|
SHA1 is **NOT** a cryptographically secure algorithm.
|
||||||
|
It should _only_ be used for non cryptographic functions like checksums.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
import {Sha1} from '@aws-crypto/sha1-browser'
|
||||||
|
|
||||||
|
const hash = new Sha1();
|
||||||
|
hash.update('some data');
|
||||||
|
const result = await hash.digest();
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
`npm test`
|
||||||
10
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/constants.d.ts
generated
vendored
Normal file
10
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/constants.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export declare const SHA_1_HASH: {
|
||||||
|
name: "SHA-1";
|
||||||
|
};
|
||||||
|
export declare const SHA_1_HMAC_ALGO: {
|
||||||
|
name: "HMAC";
|
||||||
|
hash: {
|
||||||
|
name: "SHA-1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export declare const EMPTY_DATA_SHA_1: Uint8Array;
|
||||||
31
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/constants.js
generated
vendored
Normal file
31
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/constants.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.EMPTY_DATA_SHA_1 = exports.SHA_1_HMAC_ALGO = exports.SHA_1_HASH = void 0;
|
||||||
|
exports.SHA_1_HASH = { name: "SHA-1" };
|
||||||
|
exports.SHA_1_HMAC_ALGO = {
|
||||||
|
name: "HMAC",
|
||||||
|
hash: exports.SHA_1_HASH,
|
||||||
|
};
|
||||||
|
exports.EMPTY_DATA_SHA_1 = new Uint8Array([
|
||||||
|
218,
|
||||||
|
57,
|
||||||
|
163,
|
||||||
|
238,
|
||||||
|
94,
|
||||||
|
107,
|
||||||
|
75,
|
||||||
|
13,
|
||||||
|
50,
|
||||||
|
85,
|
||||||
|
191,
|
||||||
|
239,
|
||||||
|
149,
|
||||||
|
96,
|
||||||
|
24,
|
||||||
|
144,
|
||||||
|
175,
|
||||||
|
216,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
]);
|
||||||
|
//# sourceMappingURL=constants.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/constants.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/constants.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAElD,QAAA,eAAe,GAA8C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,kBAAU;CACjB,CAAC;AAEW,QAAA,gBAAgB,GAAG,IAAI,UAAU,CAAC;IAC7C,GAAG;IACH,EAAE;IACF,GAAG;IACH,GAAG;IACH,EAAE;IACF,GAAG;IACH,EAAE;IACF,EAAE;IACF,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,CAAC;IACD,CAAC;CACF,CAAC,CAAC"}
|
||||||
8
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/crossPlatformSha1.d.ts
generated
vendored
Normal file
8
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/crossPlatformSha1.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Checksum, SourceData } from "@aws-sdk/types";
|
||||||
|
export declare class Sha1 implements Checksum {
|
||||||
|
private hash;
|
||||||
|
constructor(secret?: SourceData);
|
||||||
|
update(data: SourceData, encoding?: "utf8" | "ascii" | "latin1"): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
29
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/crossPlatformSha1.js
generated
vendored
Normal file
29
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/crossPlatformSha1.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Sha1 = void 0;
|
||||||
|
var webCryptoSha1_1 = require("./webCryptoSha1");
|
||||||
|
var supports_web_crypto_1 = require("@aws-crypto/supports-web-crypto");
|
||||||
|
var util_locate_window_1 = require("@aws-sdk/util-locate-window");
|
||||||
|
var util_1 = require("@aws-crypto/util");
|
||||||
|
var Sha1 = /** @class */ (function () {
|
||||||
|
function Sha1(secret) {
|
||||||
|
if ((0, supports_web_crypto_1.supportsWebCrypto)((0, util_locate_window_1.locateWindow)())) {
|
||||||
|
this.hash = new webCryptoSha1_1.Sha1(secret);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error("SHA1 not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sha1.prototype.update = function (data, encoding) {
|
||||||
|
this.hash.update((0, util_1.convertToBuffer)(data));
|
||||||
|
};
|
||||||
|
Sha1.prototype.digest = function () {
|
||||||
|
return this.hash.digest();
|
||||||
|
};
|
||||||
|
Sha1.prototype.reset = function () {
|
||||||
|
this.hash.reset();
|
||||||
|
};
|
||||||
|
return Sha1;
|
||||||
|
}());
|
||||||
|
exports.Sha1 = Sha1;
|
||||||
|
//# sourceMappingURL=crossPlatformSha1.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/crossPlatformSha1.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/crossPlatformSha1.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"crossPlatformSha1.js","sourceRoot":"","sources":["../../src/crossPlatformSha1.ts"],"names":[],"mappings":";;;AAAA,iDAAwD;AAExD,uEAAoE;AACpE,kEAA2D;AAC3D,yCAAmD;AAEnD;IAGE,cAAY,MAAmB;QAC7B,IAAI,IAAA,uCAAiB,EAAC,IAAA,iCAAY,GAAE,CAAC,EAAE;YACrC,IAAI,CAAC,IAAI,GAAG,IAAI,oBAAa,CAAC,MAAM,CAAC,CAAC;SACvC;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;SACvC;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB,EAAE,QAAsC;QAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,IAAI,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,qBAAM,GAAN;QACE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IACH,WAAC;AAAD,CAAC,AAtBD,IAsBC;AAtBY,oBAAI"}
|
||||||
2
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/index.d.ts
generated
vendored
Normal file
2
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./crossPlatformSha1";
|
||||||
|
export { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";
|
||||||
8
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/index.js
generated
vendored
Normal file
8
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/index.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.WebCryptoSha1 = void 0;
|
||||||
|
var tslib_1 = require("tslib");
|
||||||
|
tslib_1.__exportStar(require("./crossPlatformSha1"), exports);
|
||||||
|
var webCryptoSha1_1 = require("./webCryptoSha1");
|
||||||
|
Object.defineProperty(exports, "WebCryptoSha1", { enumerable: true, get: function () { return webCryptoSha1_1.Sha1; } });
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/index.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;AAAA,8DAAoC;AACpC,iDAAwD;AAA/C,8GAAA,IAAI,OAAiB"}
|
||||||
2
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/isEmptyData.d.ts
generated
vendored
Normal file
2
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/isEmptyData.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import { SourceData } from "@aws-sdk/types";
|
||||||
|
export declare function isEmptyData(data: SourceData): boolean;
|
||||||
11
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/isEmptyData.js
generated
vendored
Normal file
11
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/isEmptyData.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.isEmptyData = void 0;
|
||||||
|
function isEmptyData(data) {
|
||||||
|
if (typeof data === "string") {
|
||||||
|
return data.length === 0;
|
||||||
|
}
|
||||||
|
return data.byteLength === 0;
|
||||||
|
}
|
||||||
|
exports.isEmptyData = isEmptyData;
|
||||||
|
//# sourceMappingURL=isEmptyData.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/isEmptyData.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/isEmptyData.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"isEmptyData.js","sourceRoot":"","sources":["../../src/isEmptyData.ts"],"names":[],"mappings":";;;AAEA,SAAgB,WAAW,CAAC,IAAgB;IAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;KAC1B;IAED,OAAO,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC;AAC/B,CAAC;AAND,kCAMC"}
|
||||||
9
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/webCryptoSha1.d.ts
generated
vendored
Normal file
9
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/webCryptoSha1.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { Checksum, SourceData } from "@aws-sdk/types";
|
||||||
|
export declare class Sha1 implements Checksum {
|
||||||
|
private readonly key;
|
||||||
|
private toHash;
|
||||||
|
constructor(secret?: SourceData);
|
||||||
|
update(data: SourceData): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
61
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/webCryptoSha1.js
generated
vendored
Normal file
61
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/webCryptoSha1.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Sha1 = void 0;
|
||||||
|
var util_utf8_1 = require("@smithy/util-utf8");
|
||||||
|
var isEmptyData_1 = require("./isEmptyData");
|
||||||
|
var constants_1 = require("./constants");
|
||||||
|
var util_locate_window_1 = require("@aws-sdk/util-locate-window");
|
||||||
|
var Sha1 = /** @class */ (function () {
|
||||||
|
function Sha1(secret) {
|
||||||
|
this.toHash = new Uint8Array(0);
|
||||||
|
if (secret !== void 0) {
|
||||||
|
this.key = new Promise(function (resolve, reject) {
|
||||||
|
(0, util_locate_window_1.locateWindow)()
|
||||||
|
.crypto.subtle.importKey("raw", convertToBuffer(secret), constants_1.SHA_1_HMAC_ALGO, false, ["sign"])
|
||||||
|
.then(resolve, reject);
|
||||||
|
});
|
||||||
|
this.key.catch(function () { });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sha1.prototype.update = function (data) {
|
||||||
|
if ((0, isEmptyData_1.isEmptyData)(data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var update = convertToBuffer(data);
|
||||||
|
var typedArray = new Uint8Array(this.toHash.byteLength + update.byteLength);
|
||||||
|
typedArray.set(this.toHash, 0);
|
||||||
|
typedArray.set(update, this.toHash.byteLength);
|
||||||
|
this.toHash = typedArray;
|
||||||
|
};
|
||||||
|
Sha1.prototype.digest = function () {
|
||||||
|
var _this = this;
|
||||||
|
if (this.key) {
|
||||||
|
return this.key.then(function (key) {
|
||||||
|
return (0, util_locate_window_1.locateWindow)()
|
||||||
|
.crypto.subtle.sign(constants_1.SHA_1_HMAC_ALGO, key, _this.toHash)
|
||||||
|
.then(function (data) { return new Uint8Array(data); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ((0, isEmptyData_1.isEmptyData)(this.toHash)) {
|
||||||
|
return Promise.resolve(constants_1.EMPTY_DATA_SHA_1);
|
||||||
|
}
|
||||||
|
return Promise.resolve()
|
||||||
|
.then(function () { return (0, util_locate_window_1.locateWindow)().crypto.subtle.digest(constants_1.SHA_1_HASH, _this.toHash); })
|
||||||
|
.then(function (data) { return Promise.resolve(new Uint8Array(data)); });
|
||||||
|
};
|
||||||
|
Sha1.prototype.reset = function () {
|
||||||
|
this.toHash = new Uint8Array(0);
|
||||||
|
};
|
||||||
|
return Sha1;
|
||||||
|
}());
|
||||||
|
exports.Sha1 = Sha1;
|
||||||
|
function convertToBuffer(data) {
|
||||||
|
if (typeof data === "string") {
|
||||||
|
return (0, util_utf8_1.fromUtf8)(data);
|
||||||
|
}
|
||||||
|
if (ArrayBuffer.isView(data)) {
|
||||||
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
|
||||||
|
}
|
||||||
|
return new Uint8Array(data);
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=webCryptoSha1.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/webCryptoSha1.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/main/webCryptoSha1.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"webCryptoSha1.js","sourceRoot":"","sources":["../../src/webCryptoSha1.ts"],"names":[],"mappings":";;;AACA,+CAA6C;AAC7C,6CAA4C;AAC5C,yCAA4E;AAC5E,kEAA2D;AAE3D;IAIE,cAAY,MAAmB;QAFvB,WAAM,GAAe,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAG7C,IAAI,MAAM,KAAK,KAAK,CAAC,EAAE;YACrB,IAAI,CAAC,GAAG,GAAG,IAAI,OAAO,CAAC,UAAC,OAAO,EAAE,MAAM;gBACrC,IAAA,iCAAY,GAAE;qBACX,MAAM,CAAC,MAAM,CAAC,SAAS,CACtB,KAAK,EACL,eAAe,CAAC,MAAM,CAAC,EACvB,2BAAe,EACf,KAAK,EACL,CAAC,MAAM,CAAC,CACT;qBACA,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAO,CAAC,CAAC,CAAC;SAC1B;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB;QACrB,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC,EAAE;YACrB,OAAO;SACR;QAED,IAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,IAAM,UAAU,GAAG,IAAI,UAAU,CAC/B,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAC3C,CAAC;QACF,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/B,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,CAAC;IAED,qBAAM,GAAN;QAAA,iBAgBC;QAfC,IAAI,IAAI,CAAC,GAAG,EAAE;YACZ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAC,GAAG;gBACvB,OAAA,IAAA,iCAAY,GAAE;qBACX,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,2BAAe,EAAE,GAAG,EAAE,KAAI,CAAC,MAAM,CAAC;qBACrD,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,IAAI,UAAU,CAAC,IAAI,CAAC,EAApB,CAAoB,CAAC;YAFvC,CAEuC,CACxC,CAAC;SACH;QAED,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,4BAAgB,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC,OAAO,EAAE;aACrB,IAAI,CAAC,cAAM,OAAA,IAAA,iCAAY,GAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAU,EAAE,KAAI,CAAC,MAAM,CAAC,EAA5D,CAA4D,CAAC;aACxE,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,OAAO,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAArC,CAAqC,CAAC,CAAC;IAC3D,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACH,WAAC;AAAD,CAAC,AAxDD,IAwDC;AAxDY,oBAAI;AA0DjB,SAAS,eAAe,CAAC,IAAgB;IACvC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC;KACvB;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QAC5B,OAAO,IAAI,UAAU,CACnB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAC/C,CAAC;KACH;IAED,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}
|
||||||
10
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/constants.d.ts
generated
vendored
Normal file
10
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/constants.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export declare const SHA_1_HASH: {
|
||||||
|
name: "SHA-1";
|
||||||
|
};
|
||||||
|
export declare const SHA_1_HMAC_ALGO: {
|
||||||
|
name: "HMAC";
|
||||||
|
hash: {
|
||||||
|
name: "SHA-1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export declare const EMPTY_DATA_SHA_1: Uint8Array;
|
||||||
28
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/constants.js
generated
vendored
Normal file
28
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/constants.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
export var SHA_1_HASH = { name: "SHA-1" };
|
||||||
|
export var SHA_1_HMAC_ALGO = {
|
||||||
|
name: "HMAC",
|
||||||
|
hash: SHA_1_HASH,
|
||||||
|
};
|
||||||
|
export var EMPTY_DATA_SHA_1 = new Uint8Array([
|
||||||
|
218,
|
||||||
|
57,
|
||||||
|
163,
|
||||||
|
238,
|
||||||
|
94,
|
||||||
|
107,
|
||||||
|
75,
|
||||||
|
13,
|
||||||
|
50,
|
||||||
|
85,
|
||||||
|
191,
|
||||||
|
239,
|
||||||
|
149,
|
||||||
|
96,
|
||||||
|
24,
|
||||||
|
144,
|
||||||
|
175,
|
||||||
|
216,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
]);
|
||||||
|
//# sourceMappingURL=constants.js.map
|
||||||
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/constants.js.map
generated
vendored
Normal file
1
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/constants.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,UAAU,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAE/D,MAAM,CAAC,IAAM,eAAe,GAA8C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,IAAM,gBAAgB,GAAG,IAAI,UAAU,CAAC;IAC7C,GAAG;IACH,EAAE;IACF,GAAG;IACH,GAAG;IACH,EAAE;IACF,GAAG;IACH,EAAE;IACF,EAAE;IACF,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,CAAC;IACD,CAAC;CACF,CAAC,CAAC"}
|
||||||
8
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/crossPlatformSha1.d.ts
generated
vendored
Normal file
8
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/crossPlatformSha1.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Checksum, SourceData } from "@aws-sdk/types";
|
||||||
|
export declare class Sha1 implements Checksum {
|
||||||
|
private hash;
|
||||||
|
constructor(secret?: SourceData);
|
||||||
|
update(data: SourceData, encoding?: "utf8" | "ascii" | "latin1"): void;
|
||||||
|
digest(): Promise<Uint8Array>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
26
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/crossPlatformSha1.js
generated
vendored
Normal file
26
crm_extensions/file_storage/node_modules/@aws-crypto/sha1-browser/build/module/crossPlatformSha1.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";
|
||||||
|
import { supportsWebCrypto } from "@aws-crypto/supports-web-crypto";
|
||||||
|
import { locateWindow } from "@aws-sdk/util-locate-window";
|
||||||
|
import { convertToBuffer } from "@aws-crypto/util";
|
||||||
|
var Sha1 = /** @class */ (function () {
|
||||||
|
function Sha1(secret) {
|
||||||
|
if (supportsWebCrypto(locateWindow())) {
|
||||||
|
this.hash = new WebCryptoSha1(secret);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error("SHA1 not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sha1.prototype.update = function (data, encoding) {
|
||||||
|
this.hash.update(convertToBuffer(data));
|
||||||
|
};
|
||||||
|
Sha1.prototype.digest = function () {
|
||||||
|
return this.hash.digest();
|
||||||
|
};
|
||||||
|
Sha1.prototype.reset = function () {
|
||||||
|
this.hash.reset();
|
||||||
|
};
|
||||||
|
return Sha1;
|
||||||
|
}());
|
||||||
|
export { Sha1 };
|
||||||
|
//# sourceMappingURL=crossPlatformSha1.js.map
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user