From 4787a1a761128b1d506358d932dfcbeca7f70f5b Mon Sep 17 00:00:00 2001 From: "s.zotov" Date: Sun, 12 Apr 2026 20:46:39 +0000 Subject: [PATCH] Add "FTP" --- FTP.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 FTP.md diff --git a/FTP.md b/FTP.md new file mode 100644 index 0000000..262b494 --- /dev/null +++ b/FTP.md @@ -0,0 +1,64 @@ +# FTP/SFTP Галерея + +## Настройка + +В settings.json → `ftpConfig`: + +```json +{ + "protocol": "sftp", // "ftp" или "sftp" + "host": "212.113.122.5", + "port": 22, // 21 для FTP, 22 для SFTP + "user": "reaspekt", + "password": "...", // маскируется в API-ответе + "remotePath": "public/newsletter_2026", + "baseUrl": "https://email-files.vipavenue.ru/newsletter_2026" +} +``` + +Библиотеки: `basic-ftp` (FTP), `ssh2-sftp-client` (SFTP). + +## Загрузка картинок + +### Из конструктора (drag-and-drop) +1. Перетаскиваешь картинку на поле `src` блока +2. `handleImageDrop()` → если FTP настроен и у письма есть дата → загружает на FTP +3. Иначе → загружает локально (`/api/upload-image`) +4. URL подставляется в поле блока + +### Из галереи (модал) +1. Кнопка FTP-галереи на поле картинки +2. Открывается модал с миниатюрами из папки `{remotePath}/{дата-письма}/` +3. Можно выбрать существующую картинку или загрузить новую + +### Пакетная загрузка +- `` — выбор нескольких файлов +- Загрузка последовательная (`for...of` с await), не параллельная +- `event.target.value = ''` после загрузки — для повторного выбора тех же файлов +- Прогресс: `ftpUploadProgress` / `ftpUploadPercent` + +## Безопасность FTP + +- **Path traversal**: `folder` проверяется на `..` и абсолютные пути +- **Имя файла**: `fileName.replace(/[^a-zA-Z0-9а-яА-ЯёЁ_-]/g, '_')` +- **Макс размер**: 20 МБ (base64 в body) +- **Типы файлов**: png, jpg, gif, webp + +## Автонумерация картинок + +Функция `applyAutoImageNumbers()`: +1. Берёт `imageBaseUrl` и `imageExt` из настроек +2. Проходит по всем блокам с пустыми полями `src` +3. Присваивает последовательные номера: `{baseUrl}image__01_.png`, `image__02_.png`, ... + +## Кэширование галереи + +`ftpGalleryCache` — Map `{folder: files[]}` в памяти клиента. При загрузке новой картинки — файл добавляется в кэш без повторного запроса к FTP. + +## Модал галереи + +- Размер: `max-width: 1100px` +- Сетка миниатюр: `max-height: 55vh`, миниатюры `height: 100px` +- Клик на миниатюру → копирует URL в поле блока +- Кнопка удаления на каждой миниатюре (с подтверждением) +- Кнопка "Обновить" для перезагрузки списка