This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
description: Поддерживать VERSION и docs/CHANGELOG при изменениях проекта
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Версионирование и документация
|
||||||
|
|
||||||
|
При **значимых** изменениях кода или поведения:
|
||||||
|
|
||||||
|
1. Обновить [`VERSION`](../VERSION) (SemVer):
|
||||||
|
- **PATCH** — исправления, мелкие правки без смены API/поведения
|
||||||
|
- **MINOR** — новая функциональность, обратно совместимая
|
||||||
|
- **MAJOR** — ломающие изменения (формат ссылок, схема БД, API)
|
||||||
|
|
||||||
|
2. Добавить запись в [`docs/CHANGELOG.md`](../docs/CHANGELOG.md) под новой версией (Added / Changed / Fixed / Removed).
|
||||||
|
|
||||||
|
3. При изменении архитектуры, пайплайна, режимов ZILANT/VOLK или карты файлов — обновить [`docs/ARCHITECTURE.md`](../docs/ARCHITECTURE.md) и при необходимости [`README.md`](../README.md), [`docs/volk-mode.md`](../docs/volk-mode.md).
|
||||||
|
|
||||||
|
4. Перенос скриптов в `tools/` — обновить [`tools/README.md`](../tools/README.md).
|
||||||
|
|
||||||
|
5. Не поднимать версию за косметические правки без изменения поведения.
|
||||||
|
|
||||||
|
Текущая базовая версия: **1.0.1**.
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
__pycache__/season_links.cpython-314.pyc
|
|
||||||
|
|||||||
@@ -1,4 +1,66 @@
|
|||||||
# Zilant2025
|
# Zilant / VOLK — Telegram poster и подписки
|
||||||
|
|
||||||
Zilantkon bot testarea
|
**Версия:** 1.0.1 ([`VERSION`](VERSION))
|
||||||
test update #8
|
|
||||||
|
Автоматическая публикация постов и событий в Telegram-канал, веб-редактор, бот подписок с сезонными deep link.
|
||||||
|
|
||||||
|
## Режимы
|
||||||
|
|
||||||
|
| `WORKMODE` | Описание |
|
||||||
|
|------------|----------|
|
||||||
|
| `ZILANT` | VK + Zilant JSON → канал (основной пайплайн) |
|
||||||
|
| `VOLK` | VOLK API → категории и события → канал |
|
||||||
|
|
||||||
|
Подробнее: [`docs/volk-mode.md`](docs/volk-mode.md).
|
||||||
|
|
||||||
|
## Быстрый старт (сервер)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Deploy через Woodpecker → rsync + post-deploy.sh
|
||||||
|
# Сервисы:
|
||||||
|
sudo systemctl status testbot-git.service # бот :5005
|
||||||
|
sudo systemctl status testedit-git.service # UI :5006
|
||||||
|
sudo systemctl status runner.timer # hourly pipeline
|
||||||
|
```
|
||||||
|
|
||||||
|
Конфигурация — `.env` (не коммитится). Ключевые переменные: `RELAY_URL`, `WEBHOOK_URL`, `SEASON`, `MDB_*`.
|
||||||
|
|
||||||
|
## Пайплайн (ZILANT)
|
||||||
|
|
||||||
|
`runner.sh` по расписанию:
|
||||||
|
|
||||||
|
`vk_load` → `zk_load` → `db_update_shortname` → `tg_publish` → `evtg_publish`
|
||||||
|
|
||||||
|
Настройка timer: [`docs/runner-setup.md`](docs/runner-setup.md).
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
|
||||||
|
| Документ | О чём |
|
||||||
|
|----------|--------|
|
||||||
|
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Компоненты, карта файлов, deploy |
|
||||||
|
| [`docs/volk-mode.md`](docs/volk-mode.md) | Режим VOLK |
|
||||||
|
| [`docs/telegram-messaging.md`](docs/telegram-messaging.md) | API отправки сообщений пользователям |
|
||||||
|
| [`docs/runner-setup.md`](docs/runner-setup.md) | Systemd timer / cron для runner |
|
||||||
|
| [`docs/CHANGELOG.md`](docs/CHANGELOG.md) | История версий |
|
||||||
|
| [`tools/README.md`](tools/README.md) | Вспомогательные и legacy-скрипты |
|
||||||
|
|
||||||
|
## Версионирование
|
||||||
|
|
||||||
|
SemVer в [`VERSION`](VERSION). При изменениях обновлять `VERSION` и [`docs/CHANGELOG.md`](docs/CHANGELOG.md).
|
||||||
|
|
||||||
|
## Структура каталогов
|
||||||
|
|
||||||
|
```
|
||||||
|
├── tg_mainbot.py, wsgi_bot.py # responder-бот
|
||||||
|
├── db_edit.py, wsgi_edit.py # веб-UI
|
||||||
|
├── tg_publish.py, evtg_publish.py # публикация (ZILANT)
|
||||||
|
├── volk_load.py, volk_cat_publish.py # VOLK
|
||||||
|
├── runner.sh, backupdb.sh
|
||||||
|
├── services/ # systemd units, post-deploy
|
||||||
|
├── templates/ # HTML UI
|
||||||
|
├── docs/ # документация
|
||||||
|
└── tools/
|
||||||
|
├── ops/ # genkey, register_tg_webhook, copy_databases
|
||||||
|
├── dev/ # send_telegram_example, volk_*_testing
|
||||||
|
└── legacy/ # evt_prefetch
|
||||||
|
```
|
||||||
|
|||||||
+2
-204
@@ -1,205 +1,3 @@
|
|||||||
# Отправка сообщений через Telegram бота
|
# Перенесено
|
||||||
|
|
||||||
## Описание
|
Документация: [`docs/telegram-messaging.md`](docs/telegram-messaging.md)
|
||||||
|
|
||||||
В проект добавлена возможность отправки сообщений пользователям Telegram через бота по их ID. Функциональность включает:
|
|
||||||
|
|
||||||
1. **API endpoint** для отправки сообщений из других скриптов
|
|
||||||
2. **Интерфейс в веб-приложении** для отправки сообщений через браузер
|
|
||||||
3. **Обработку ошибок** и логирование всех операций
|
|
||||||
|
|
||||||
## Архитектура системы
|
|
||||||
|
|
||||||
Система состоит из двух основных компонентов:
|
|
||||||
|
|
||||||
- **Веб-интерфейс** (`db_edit.py`) - работает на порту **5006** (WEBCTRL_PORT)
|
|
||||||
- **Telegram бот** (`tg_mainbot.py`) - работает на порту **5005** (WEBHOOK_PORT)
|
|
||||||
|
|
||||||
API endpoint `/send_message` находится в Telegram боте, поэтому все запросы должны отправляться на порт **5005**.
|
|
||||||
|
|
||||||
### Конфигурация портов
|
|
||||||
|
|
||||||
Порты и URL настраиваются в файле `.env`:
|
|
||||||
- `RELAY_URL` - базовый URL **internal_relay** (все исходящие вызовы Bot API идут только через него)
|
|
||||||
- `WEBHOOK_PORT` - порт для Telegram бота (по умолчанию 5005)
|
|
||||||
- `WEBHOOK_URL` - URL доставки апдейтов от internal_relay к боту (доступен с машины relay; не URL, который видит Telegram напрямую)
|
|
||||||
- `WEBCTRL_PORT` - порт для веб-интерфейса (по умолчанию 5006)
|
|
||||||
|
|
||||||
Веб-интерфейс автоматически читает URL и порт бота из переменных окружения и использует их для отправки запросов.
|
|
||||||
|
|
||||||
## Использование через веб-интерфейс
|
|
||||||
|
|
||||||
В заголовке страницы "Управление постами VK и событиями" добавлены два поля:
|
|
||||||
|
|
||||||
- **ID пользователя** - числовой ID пользователя в Telegram
|
|
||||||
- **Сообщение** - текст сообщения для отправки
|
|
||||||
- **Кнопка "Отправить"** - отправляет сообщение через бота
|
|
||||||
|
|
||||||
### Особенности интерфейса:
|
|
||||||
|
|
||||||
- Поля проверяются на заполненность перед отправкой
|
|
||||||
- ID пользователя проверяется на корректность (должен быть числом)
|
|
||||||
- Поддержка отправки по клавише Enter
|
|
||||||
- Индикатор загрузки во время отправки
|
|
||||||
- Автоматическая очистка полей после успешной отправки
|
|
||||||
|
|
||||||
## Использование через API
|
|
||||||
|
|
||||||
### Endpoint
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /send_message
|
|
||||||
POST {WEBHOOK_PATH}/send_message
|
|
||||||
```
|
|
||||||
|
|
||||||
Где `WEBHOOK_PATH` - путь из переменной окружения `WEBHOOK_URL` (например, `/testbot`).
|
|
||||||
|
|
||||||
### Примеры URL:
|
|
||||||
|
|
||||||
- **Локально:** `http://localhost:5005/send_message`
|
|
||||||
- **Через reverse proxy:** `https://bot.aabpro.ru/testbot/send_message`
|
|
||||||
|
|
||||||
### Заголовки запроса
|
|
||||||
|
|
||||||
```
|
|
||||||
Content-Type: application/json
|
|
||||||
X-API-Secret-Token: <секретный_токен>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Параметры запроса
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"user_id": 123456789,
|
|
||||||
"message": "Текст сообщения"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Аутентификация
|
|
||||||
|
|
||||||
API защищен секретным токеном, который передается в заголовке `X-API-Secret-Token`. Токен берется из переменной окружения `WEBHOOK_SECRET`.
|
|
||||||
|
|
||||||
### Ответы
|
|
||||||
|
|
||||||
**Успешная отправка (200):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"message": "Сообщение отправлено успешно"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ошибка (400):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"error": "Описание ошибки"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Пример использования из Python
|
|
||||||
|
|
||||||
```python
|
|
||||||
import requests
|
|
||||||
|
|
||||||
def send_telegram_message(user_id, message):
|
|
||||||
# Используем внешний URL через reverse proxy
|
|
||||||
url = "https://bot.aabpro.ru/testbot/send_message"
|
|
||||||
data = {
|
|
||||||
"user_id": user_id,
|
|
||||||
"message": message
|
|
||||||
}
|
|
||||||
headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-API-Secret-Token': 'ваш_секретный_токен'
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, json=data, headers=headers)
|
|
||||||
result = response.json()
|
|
||||||
|
|
||||||
if result["success"]:
|
|
||||||
print("Сообщение отправлено успешно!")
|
|
||||||
else:
|
|
||||||
print(f"Ошибка: {result['error']}")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Пример использования из командной строки
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Используя curl (через reverse proxy)
|
|
||||||
curl -X POST https://bot.aabpro.ru/testbot/send_message \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "X-API-Secret-Token: ваш_секретный_токен" \
|
|
||||||
-d '{"user_id": 123456789, "message": "Привет!"}'
|
|
||||||
|
|
||||||
# Используя curl (локально)
|
|
||||||
curl -X POST http://localhost:5005/send_message \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "X-API-Secret-Token: ваш_секретный_токен" \
|
|
||||||
-d '{"user_id": 123456789, "message": "Привет!"}'
|
|
||||||
|
|
||||||
# Используя примерный скрипт
|
|
||||||
python send_telegram_example.py 123456789 "Привет! Это тестовое сообщение."
|
|
||||||
```
|
|
||||||
|
|
||||||
## Обработка ошибок
|
|
||||||
|
|
||||||
Система обрабатывает следующие типы ошибок:
|
|
||||||
|
|
||||||
### HTTP ошибки:
|
|
||||||
1. **401 Unauthorized** - Неверный или отсутствующий API токен
|
|
||||||
2. **400 Bad Request** - Неверный ID пользователя или отсутствующие данные
|
|
||||||
3. **500 Internal Server Error** - Внутренняя ошибка сервера
|
|
||||||
|
|
||||||
### Коды ошибок API:
|
|
||||||
- `INVALID_TOKEN` - Неверный токен аутентификации
|
|
||||||
- `NO_DATA` - Отсутствуют данные в запросе
|
|
||||||
- `NO_USER_ID` - Не указан ID пользователя
|
|
||||||
- `NO_MESSAGE` - Не указан текст сообщения
|
|
||||||
- `INVALID_USER_ID` - user_id не является числом
|
|
||||||
- `TELEGRAM_ERROR` - Ошибка Telegram API
|
|
||||||
- `INTERNAL_ERROR` - Внутренняя ошибка сервера
|
|
||||||
|
|
||||||
### Ошибки Telegram API:
|
|
||||||
1. **403 Forbidden** - Пользователь заблокировал бота или не начал с ним диалог
|
|
||||||
2. **400 Bad Request** - Неверный ID пользователя
|
|
||||||
3. **429 Too Many Requests** - Превышен лимит отправки сообщений
|
|
||||||
4. **404 Not Found** - Пользователь не найден
|
|
||||||
|
|
||||||
### Диагностика в веб-интерфейсе
|
|
||||||
|
|
||||||
Веб-интерфейс предоставляет подробную диагностику ошибок:
|
|
||||||
- **Время ответа** сервера
|
|
||||||
- **HTTP статус** код
|
|
||||||
- **Код ошибки** API
|
|
||||||
- **Конкретные предложения** по решению проблемы
|
|
||||||
- **Автоматическое скрытие** уведомлений
|
|
||||||
|
|
||||||
Все ошибки логируются в файл логов с указанием типа ошибки и ID пользователя.
|
|
||||||
|
|
||||||
## Логирование
|
|
||||||
|
|
||||||
Все операции отправки сообщений записываются в лог с указанием:
|
|
||||||
|
|
||||||
- Времени операции
|
|
||||||
- ID пользователя
|
|
||||||
- Статуса отправки (успех/ошибка)
|
|
||||||
- Краткого описания ошибки (при наличии)
|
|
||||||
|
|
||||||
Пример записи в логе:
|
|
||||||
```
|
|
||||||
[2024-01-15 10:30:45] [TG_bot] ИНФО: Сообщение отправлено: Привет! Это тестовое сообщение... (Пользователь user_123456789)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Требования
|
|
||||||
|
|
||||||
- Telegram бот должен быть запущен и подключен через webhook
|
|
||||||
- Пользователь должен начать диалог с ботом (отправить команду /start)
|
|
||||||
- Пользователь не должен заблокировать бота
|
|
||||||
|
|
||||||
## Безопасность
|
|
||||||
|
|
||||||
- API endpoint доступен только для POST запросов
|
|
||||||
- Проверка корректности входных данных
|
|
||||||
- Логирование всех попыток отправки для аудита
|
|
||||||
- Обработка ошибок без раскрытия внутренней информации системы
|
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
# Архитектура проекта
|
||||||
|
|
||||||
|
Версия: см. [`VERSION`](../VERSION). История изменений: [`docs/CHANGELOG.md`](CHANGELOG.md).
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Система загружает посты и события из внешних источников, хранит их в MariaDB, публикует анонсы в Telegram-канал и даёт веб-интерфейс для редактирования и управления подписками через responder-бота.
|
||||||
|
|
||||||
|
Поддерживаются два режима работы (`WORKMODE` в `.env`):
|
||||||
|
|
||||||
|
| Режим | Источники данных | Публикация |
|
||||||
|
|-------|------------------|------------|
|
||||||
|
| **ZILANT** | VK (`vk_load.py`), JSON Zilant (`zk_load.py`) | `tg_publish.py`, `evtg_publish.py` |
|
||||||
|
| **VOLK** | VOLK API (`volk_load.py`) | `volk_cat_publish.py` |
|
||||||
|
|
||||||
|
Подробнее о VOLK: [`docs/volk-mode.md`](volk-mode.md).
|
||||||
|
|
||||||
|
## Компоненты runtime
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐ rsync ┌──────────────────┐
|
||||||
|
│ Woodpecker CI │ ─────────────► │ /opt/testbot-git │
|
||||||
|
└─────────────────┘ └────────┬─────────┘
|
||||||
|
│
|
||||||
|
┌──────────────────────────────────┼──────────────────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
runner.timer testbot-git.service testedit-git.service
|
||||||
|
→ runner.sh gunicorn :5005 gunicorn :5006
|
||||||
|
vk_load, zk_load, wsgi_bot → tg_mainbot wsgi_edit → db_edit
|
||||||
|
db_update_shortname,
|
||||||
|
tg_publish, evtg_publish
|
||||||
|
```
|
||||||
|
|
||||||
|
### Responder-бот (подписки)
|
||||||
|
|
||||||
|
- **`tg_mainbot.py`** — Flask + webhook, обработка `/start`, callback-кнопок подписки.
|
||||||
|
- **`wsgi_bot.py`** — точка входа gunicorn; однократная регистрация webhook с file lock.
|
||||||
|
- **`season_links.py`** — сезонные payload (`zk2026_post_*`, `subscribe_zk2026_*` и т.д.).
|
||||||
|
- Старые ссылки без префикса сезона → сообщение «сезон завершён» + кнопка в канал.
|
||||||
|
|
||||||
|
### Poster (публикация в канал)
|
||||||
|
|
||||||
|
- **`tg_publish.py`** — посты VK → Telegram.
|
||||||
|
- **`evtg_publish.py`** — события → Telegram.
|
||||||
|
- **`volk_cat_publish.py`** — категории VOLK → Telegram (режим VOLK).
|
||||||
|
- Все исходящие вызовы Bot API — через **`telegram_relay.py`** (`RELAY_URL`).
|
||||||
|
|
||||||
|
### Веб-интерфейс
|
||||||
|
|
||||||
|
- **`db_edit.py`** — CRUD постов/событий, кнопки рескана, публикации, «Назвать» (AI shortname).
|
||||||
|
- **`db_update_shortname.py`** — генерация коротких названий через RouterAI.
|
||||||
|
- **`test_tg_poster.py`** — тестовый пост в канал (кнопка «Тест» в UI).
|
||||||
|
- Шаблоны: `templates/`.
|
||||||
|
|
||||||
|
### База данных
|
||||||
|
|
||||||
|
- **`ensure_db.py`** — создание/миграция схемы (вызывается из loader-скриптов).
|
||||||
|
- **`backupdb.sh`** — дамп БД при deploy (`post-deploy.sh`).
|
||||||
|
|
||||||
|
## Пайплайн runner.sh (ZILANT)
|
||||||
|
|
||||||
|
Порядок выполнения (systemd timer `runner.timer`):
|
||||||
|
|
||||||
|
1. `vk_load.py` — загрузка постов из VK
|
||||||
|
2. `zk_load.py` — загрузка событий из JSON
|
||||||
|
3. `db_update_shortname.py` — AI shortname для новых записей
|
||||||
|
4. `tg_publish.py` — публикация постов
|
||||||
|
5. `evtg_publish.py` — публикация событий
|
||||||
|
|
||||||
|
> **`tools/legacy/evt_prefetch.py`** раньше стоял перед `evtg_publish.py`; с 1.0.0 снят с пайплайна.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
- **`.woodpecker.yml`** — rsync на сервер, затем `services/post-deploy.sh`.
|
||||||
|
- **`post-deploy.sh`** — venv, pip, backup БД, обновление systemd units, restart сервисов.
|
||||||
|
|
||||||
|
## Конфигурация (.env)
|
||||||
|
|
||||||
|
| Переменная | Назначение |
|
||||||
|
|------------|------------|
|
||||||
|
| `WORKMODE` | `ZILANT` или `VOLK` |
|
||||||
|
| `SEASON` | Префикс сезона для deep link (`zk2026`) |
|
||||||
|
| `RELAY_URL` | Internal relay для Bot API |
|
||||||
|
| `WEBHOOK_URL`, `WEBHOOK_SECRET` | Доставка апдейтов боту |
|
||||||
|
| `MDB_*`, `MDBASE` | MariaDB |
|
||||||
|
| `POSTER_BOT_TOKEN`, `RESPONDER_BOT_TOKEN` | Токены ботов |
|
||||||
|
|
||||||
|
## Карта файлов
|
||||||
|
|
||||||
|
### Ядро (runtime)
|
||||||
|
|
||||||
|
| Файл | Роль |
|
||||||
|
|------|------|
|
||||||
|
| `tg_mainbot.py` | Responder-бот, webhook |
|
||||||
|
| `wsgi_bot.py` | Gunicorn entry (бот) |
|
||||||
|
| `db_edit.py` | Веб-UI |
|
||||||
|
| `wsgi_edit.py` | Gunicorn entry (UI) |
|
||||||
|
| `tg_publish.py` | Публикация постов |
|
||||||
|
| `evtg_publish.py` | Публикация событий |
|
||||||
|
| `vk_load.py` | Загрузка VK |
|
||||||
|
| `zk_load.py` | Загрузка Zilant JSON |
|
||||||
|
| `volk_load.py` | Загрузка VOLK (режим VOLK) |
|
||||||
|
| `volk_cat_publish.py` | Публикация VOLK (режим VOLK) |
|
||||||
|
| `db_update_shortname.py` | AI shortname |
|
||||||
|
| `formatter.py` | Форматирование текста постов/событий |
|
||||||
|
| `ensure_db.py` | Схема БД |
|
||||||
|
| `telegram_relay.py` | Relay для Bot API |
|
||||||
|
| `season_links.py` | Сезонные ссылки и callback |
|
||||||
|
| `test_tg_poster.py` | Тестовая публикация (UI) |
|
||||||
|
| `runner.sh` | Пайплайн по расписанию |
|
||||||
|
| `backupdb.sh` | Бэкап БД |
|
||||||
|
| `gunicorn_bot.conf.py` | Stub-конфиг gunicorn (бот) |
|
||||||
|
|
||||||
|
### Инфраструктура
|
||||||
|
|
||||||
|
| Путь | Роль |
|
||||||
|
|------|------|
|
||||||
|
| `services/testbot-git.service` | systemd: бот :5005 |
|
||||||
|
| `services/testedit-git.service` | systemd: UI :5006 |
|
||||||
|
| `services/runner.service`, `runner.timer` | systemd: hourly runner |
|
||||||
|
| `services/post-deploy.sh` | Post-deploy |
|
||||||
|
| `.woodpecker.yml` | CI deploy |
|
||||||
|
|
||||||
|
### Вспомогательные (`tools/`)
|
||||||
|
|
||||||
|
| Путь | Роль |
|
||||||
|
|------|------|
|
||||||
|
| `tools/ops/genkey.py` | Генерация секретов |
|
||||||
|
| `tools/ops/register_tg_webhook.py` | Ручная регистрация webhook |
|
||||||
|
| `tools/ops/copy_databases.sh` | Клонирование MariaDB |
|
||||||
|
| `tools/dev/send_telegram_example.py` | CLI-пример `/send_message` |
|
||||||
|
| `tools/dev/volk_telegram_testing.py` | Отладка публикации в Telegram |
|
||||||
|
| `tools/dev/volk_category_testing.py` | Отладка загрузки категории VOLK |
|
||||||
|
| `tools/legacy/evt_prefetch.py` | Legacy: prefetch событий |
|
||||||
|
|
||||||
|
См. [`tools/README.md`](../tools/README.md).
|
||||||
|
|
||||||
|
### Документация
|
||||||
|
|
||||||
|
| Файл | Содержание |
|
||||||
|
|------|------------|
|
||||||
|
| `README.md` | Быстрый старт |
|
||||||
|
| `docs/ARCHITECTURE.md` | Этот файл |
|
||||||
|
| `docs/volk-mode.md` | Режим VOLK |
|
||||||
|
| `docs/telegram-messaging.md` | API `/send_message` |
|
||||||
|
| `docs/runner-setup.md` | Настройка runner timer |
|
||||||
|
| `docs/CHANGELOG.md` | История версий |
|
||||||
|
|
||||||
|
## Версионирование
|
||||||
|
|
||||||
|
- Версия в корне: **`VERSION`** (SemVer: `MAJOR.MINOR.PATCH`).
|
||||||
|
- При каждом значимом изменении обновлять `VERSION` и запись в `docs/CHANGELOG.md`.
|
||||||
|
- Правило для агентов: `.cursor/rules/version-and-docs.mdc`.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/).
|
||||||
|
Версия проекта — в файле [`VERSION`](../VERSION) (SemVer).
|
||||||
|
|
||||||
|
## [1.0.1] - 2026-08-30
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Утилиты перенесены в `tools/`:
|
||||||
|
- `tools/ops/` — `register_tg_webhook.py`, `copy_databases.sh` (рядом с `genkey.py`)
|
||||||
|
- `tools/dev/` — `send_telegram_example.py`, `volk_telegram_testing.py`, `volk_category_testing.py`
|
||||||
|
- Скрипты в `tools/` загружают `.env` из корня проекта и добавляют корень в `sys.path` при импорте модулей ядра.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Обновлены `tools/README.md`, `docs/ARCHITECTURE.md`, `docs/volk-mode.md`, `docs/telegram-messaging.md`, `README.md`.
|
||||||
|
|
||||||
|
## [1.0.0] - 2026-08-30
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Файл версии `VERSION` (SemVer).
|
||||||
|
- Документация: `README.md`, `docs/ARCHITECTURE.md`, `docs/volk-mode.md`.
|
||||||
|
- Каталог `tools/` с README; `tools/ops/genkey.py`, `tools/legacy/evt_prefetch.py`.
|
||||||
|
- Сезонные deep link и callback с префиксом `SEASON` (`season_links.py`, по умолчанию `zk2026`).
|
||||||
|
- Интеграция Telegram Bot API через internal relay (`telegram_relay.py`, `RELAY_URL`).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `evt_prefetch.py` перенесён в `tools/legacy/` — не входит в `runner.sh`.
|
||||||
|
- `genkey.py` перенесён в `tools/ops/`.
|
||||||
|
- Документация по runner и отправке сообщений — в `docs/`.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Правило Cursor `.cursor/rules/version-and-docs.mdc` — поддержка версии и changelog при изменениях.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Настройка автоматического запуска runner.sh
|
||||||
|
|
||||||
|
См. также [`docs/ARCHITECTURE.md`](ARCHITECTURE.md) — состав пайплайна.
|
||||||
|
|
||||||
|
Есть два способа настроить запуск `runner.sh` каждый час:
|
||||||
|
|
||||||
|
## Вариант 1: Systemd Timer (рекомендуется)
|
||||||
|
|
||||||
|
В проекте уже используются systemd-сервисы.
|
||||||
|
|
||||||
|
### Установка
|
||||||
|
|
||||||
|
1. Скопируйте файлы в systemd:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cp services/runner.service /etc/systemd/system/
|
||||||
|
sudo cp services/runner.timer /etc/systemd/system/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Или используйте скрипт установки:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x services/install_runner_timer.sh
|
||||||
|
sudo bash services/install_runner_timer.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Вручную:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable runner.timer
|
||||||
|
sudo systemctl start runner.timer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Управление
|
||||||
|
|
||||||
|
- Статус: `sudo systemctl status runner.timer`
|
||||||
|
- Остановить: `sudo systemctl stop runner.timer`
|
||||||
|
- Запустить: `sudo systemctl start runner.timer`
|
||||||
|
- Отключить: `sudo systemctl disable runner.timer`
|
||||||
|
- Логи: `sudo journalctl -u runner.service -f`
|
||||||
|
- Список timers: `sudo systemctl list-timers`
|
||||||
|
|
||||||
|
### Расписание
|
||||||
|
|
||||||
|
Файл `/etc/systemd/system/runner.timer`:
|
||||||
|
|
||||||
|
- `OnCalendar=hourly` — каждый час
|
||||||
|
- `OnCalendar=*-*-* *:00:00` — в начале каждого часа
|
||||||
|
- `OnCalendar=*-*-* 0,6,12,18:00:00` — в 0, 6, 12, 18 часов
|
||||||
|
- `OnCalendar=Mon..Fri 09:00:00` — будни в 9:00
|
||||||
|
|
||||||
|
После изменения: `sudo systemctl daemon-reload`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Вариант 2: Cron
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo crontab -e
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
0 * * * * /bin/bash /opt/testbot-git/runner.sh >> /opt/testbot-git/runner_cron.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
Другие варианты: `30 * * * *`, `*/30 * * * *`, `0 9-17 * * *`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Состав runner.sh (ZILANT)
|
||||||
|
|
||||||
|
`vk_load.py` → `zk_load.py` → `db_update_shortname.py` → `tg_publish.py` → `evtg_publish.py`
|
||||||
|
|
||||||
|
Legacy `tools/legacy/evt_prefetch.py` в пайплайн не входит (с 1.0.0).
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# Отправка сообщений через Telegram бота
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
В проект добавлена возможность отправки сообщений пользователям Telegram через бота по их ID. Функциональность включает:
|
||||||
|
|
||||||
|
1. **API endpoint** для отправки сообщений из других скриптов
|
||||||
|
2. **Интерфейс в веб-приложении** для отправки сообщений через браузер
|
||||||
|
3. **Обработку ошибок** и логирование всех операций
|
||||||
|
|
||||||
|
## Архитектура системы
|
||||||
|
|
||||||
|
Система состоит из двух основных компонентов:
|
||||||
|
|
||||||
|
- **Веб-интерфейс** (`db_edit.py`) - работает на порту **5006** (WEBCTRL_PORT)
|
||||||
|
- **Telegram бот** (`tg_mainbot.py`) - работает на порту **5005** (WEBHOOK_PORT)
|
||||||
|
|
||||||
|
API endpoint `/send_message` находится в Telegram боте, поэтому все запросы должны отправляться на порт **5005**.
|
||||||
|
|
||||||
|
### Конфигурация портов
|
||||||
|
|
||||||
|
Порты и URL настраиваются в файле `.env`:
|
||||||
|
|
||||||
|
- `RELAY_URL` - базовый URL **internal_relay** (все исходящие вызовы Bot API идут только через него)
|
||||||
|
- `WEBHOOK_PORT` - порт для Telegram бота (по умолчанию 5005)
|
||||||
|
- `WEBHOOK_URL` - URL доставки апдейтов от internal_relay к боту
|
||||||
|
- `WEBCTRL_PORT` - порт для веб-интерфейса (по умолчанию 5006)
|
||||||
|
|
||||||
|
## Использование через веб-интерфейс
|
||||||
|
|
||||||
|
В заголовке страницы добавлены поля **ID пользователя**, **Сообщение** и кнопка **Отправить**.
|
||||||
|
|
||||||
|
## Использование через API
|
||||||
|
|
||||||
|
### Endpoint
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /send_message
|
||||||
|
POST {WEBHOOK_PATH}/send_message
|
||||||
|
```
|
||||||
|
|
||||||
|
### Заголовки
|
||||||
|
|
||||||
|
```
|
||||||
|
Content-Type: application/json
|
||||||
|
X-API-Secret-Token: <WEBHOOK_SECRET>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Тело запроса
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user_id": 123456789,
|
||||||
|
"message": "Текст сообщения"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пример (Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
|
||||||
|
def send_telegram_message(user_id, message):
|
||||||
|
url = "http://192.168.0.109:5005/testbot/send_message"
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-API-Secret-Token": "ваш_секретный_токен",
|
||||||
|
}
|
||||||
|
response = requests.post(url, json={"user_id": user_id, "message": message}, headers=headers)
|
||||||
|
return response.json()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пример (curl)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5005/testbot/send_message \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-API-Secret-Token: ваш_секретный_токен" \
|
||||||
|
-d '{"user_id": 123456789, "message": "Привет!"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Опционально: CLI-скрипт `tools/dev/send_telegram_example.py`.
|
||||||
|
|
||||||
|
## Коды ошибок API
|
||||||
|
|
||||||
|
- `INVALID_TOKEN`, `NO_DATA`, `NO_USER_ID`, `NO_MESSAGE`, `INVALID_USER_ID`
|
||||||
|
- `TELEGRAM_ERROR`, `INTERNAL_ERROR`
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- Бот запущен (webhook через `wsgi_bot.py`)
|
||||||
|
- Пользователь начал диалог с ботом (`/start`)
|
||||||
|
|
||||||
|
См. также [`ARCHITECTURE.md`](ARCHITECTURE.md).
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Режим VOLK
|
||||||
|
|
||||||
|
Режим включается в `.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
WORKMODE = "VOLK"
|
||||||
|
```
|
||||||
|
|
||||||
|
Проект поддерживает оба режима — **ZILANT** и **VOLK**; переключение только через `WORKMODE`, без смены кодовой базы.
|
||||||
|
|
||||||
|
## Отличия от ZILANT
|
||||||
|
|
||||||
|
| Аспект | ZILANT | VOLK |
|
||||||
|
|--------|--------|------|
|
||||||
|
| Загрузка данных | `vk_load.py`, `zk_load.py` | `volk_load.py` |
|
||||||
|
| Публикация | `tg_publish.py`, `evtg_publish.py` | `volk_cat_publish.py` |
|
||||||
|
| Runner | Полный пайплайн ZILANT | Отдельные кнопки рескана в UI |
|
||||||
|
| UI | Посты + события VK/Zilant | Категории (площадки) + события VOLK |
|
||||||
|
|
||||||
|
## Модули VOLK
|
||||||
|
|
||||||
|
### `volk_load.py`
|
||||||
|
|
||||||
|
- Загружает список категорий и событий с VOLK API.
|
||||||
|
- Переменные: `VOLK_CATEGORY_LIST`, `VOLK_CATEGORY_DESC_PREFIX`, `VOLK_EVENT_LIST_PREFIX`, `VOLK_API_VERSION`.
|
||||||
|
- Вызывается из `db_edit.py` (API `/api/run_volk_rescan`, кнопка «Рескан ВОЛК»).
|
||||||
|
|
||||||
|
### `volk_cat_publish.py`
|
||||||
|
|
||||||
|
- Публикует категории (площадки) в Telegram-канал.
|
||||||
|
- Функции `tg_post_category_by_id`, `tg_post_all_categories` — из веб-UI.
|
||||||
|
|
||||||
|
### Шаблоны
|
||||||
|
|
||||||
|
- `templates/edit_category.html` — редактирование площадки (только VOLK).
|
||||||
|
- Блоки `{% if g.workmode == 'VOLK' %}` в `templates/index.html`.
|
||||||
|
|
||||||
|
## Отладочные скрипты (не в production-пайплайне)
|
||||||
|
|
||||||
|
| Файл | Запуск |
|
||||||
|
|------|--------|
|
||||||
|
| `tools/dev/volk_category_testing.py` | `python tools/dev/volk_category_testing.py <category_id>` |
|
||||||
|
| `tools/dev/volk_telegram_testing.py` | `python tools/dev/volk_telegram_testing.py` |
|
||||||
|
|
||||||
|
См. [`tools/README.md`](../tools/README.md).
|
||||||
|
|
||||||
|
## Переключение режима на сервере
|
||||||
|
|
||||||
|
1. Изменить `WORKMODE` в `/opt/testbot-git/.env`.
|
||||||
|
2. Перезапустить UI: `sudo systemctl restart testedit-git.service`.
|
||||||
|
3. Responder-бот (`testbot-git`) от режима не зависит; сезонные ссылки общие (`SEASON`).
|
||||||
|
|
||||||
|
При смене режима проверьте переменные VOLK/ZILANT в `.env` (префиксы URL, API, `LOG_FILE`).
|
||||||
@@ -6,7 +6,8 @@ SCRIPTS_DIR="/opt/testbot-git"
|
|||||||
VENV_ACTIVATE="$SCRIPTS_DIR/venv/bin/activate"
|
VENV_ACTIVATE="$SCRIPTS_DIR/venv/bin/activate"
|
||||||
|
|
||||||
# Список скриптов для запуска в порядке выполнения
|
# Список скриптов для запуска в порядке выполнения
|
||||||
# SCRIPTS=("vk_load.py" "zk_load.py" "db_update_shortname.py" "evt_prefetch.py" "tg_publish.py" "evtg_publish.py")
|
# Legacy prefetch (не в пайплайне): tools/legacy/evt_prefetch.py
|
||||||
|
# SCRIPTS=("vk_load.py" "zk_load.py" "db_update_shortname.py" "tools/legacy/evt_prefetch.py" "tg_publish.py" "evtg_publish.py")
|
||||||
SCRIPTS=("vk_load.py" "zk_load.py" "db_update_shortname.py" "tg_publish.py" "evtg_publish.py")
|
SCRIPTS=("vk_load.py" "zk_load.py" "db_update_shortname.py" "tg_publish.py" "evtg_publish.py")
|
||||||
|
|
||||||
# Интервалы между скриптами (в секундах)
|
# Интервалы между скриптами (в секундах)
|
||||||
|
|||||||
@@ -1,87 +1,3 @@
|
|||||||
# Настройка автоматического запуска runner.sh каждый час
|
# Перенесено
|
||||||
|
|
||||||
Есть два способа настроить запуск `runner.sh` каждый час:
|
|
||||||
|
|
||||||
## Вариант 1: Systemd Timer (Рекомендуется)
|
|
||||||
|
|
||||||
Этот вариант рекомендуется, так как в проекте уже используются systemd сервисы.
|
|
||||||
|
|
||||||
### Установка:
|
|
||||||
|
|
||||||
1. Скопируйте файлы в systemd:
|
|
||||||
```bash
|
|
||||||
sudo cp services/runner.service /etc/systemd/system/
|
|
||||||
sudo cp services/runner.timer /etc/systemd/system/
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Или используйте скрипт установки:
|
|
||||||
```bash
|
|
||||||
chmod +x services/install_runner_timer.sh
|
|
||||||
sudo bash services/install_runner_timer.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Вручную:
|
|
||||||
```bash
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
sudo systemctl enable runner.timer
|
|
||||||
sudo systemctl start runner.timer
|
|
||||||
```
|
|
||||||
|
|
||||||
### Управление:
|
|
||||||
|
|
||||||
- Проверить статус: `sudo systemctl status runner.timer`
|
|
||||||
- Остановить: `sudo systemctl stop runner.timer`
|
|
||||||
- Запустить: `sudo systemctl start runner.timer`
|
|
||||||
- Отключить: `sudo systemctl disable runner.timer`
|
|
||||||
- Просмотр логов: `sudo journalctl -u runner.service -f`
|
|
||||||
- Список всех timers: `sudo systemctl list-timers`
|
|
||||||
|
|
||||||
### Настройка расписания:
|
|
||||||
|
|
||||||
Отредактируйте файл `/etc/systemd/system/runner.timer`:
|
|
||||||
|
|
||||||
- `OnCalendar=hourly` - каждый час
|
|
||||||
- `OnCalendar=*-*-* *:00:00` - каждый час в начале часа
|
|
||||||
- `OnCalendar=*-*-* 0,6,12,18:00:00` - в 0, 6, 12, 18 часов
|
|
||||||
- `OnCalendar=Mon..Fri 09:00:00` - каждый будний день в 9:00
|
|
||||||
|
|
||||||
После изменения: `sudo systemctl daemon-reload`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Вариант 2: Cron
|
|
||||||
|
|
||||||
Классический способ для периодических задач.
|
|
||||||
|
|
||||||
### Установка:
|
|
||||||
|
|
||||||
1. Откройте crontab для редактирования:
|
|
||||||
```bash
|
|
||||||
sudo crontab -e
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Добавьте строку:
|
|
||||||
```bash
|
|
||||||
0 * * * * /bin/bash /opt/testbot-git/runner.sh >> /opt/testbot-git/runner_cron.log 2>&1
|
|
||||||
```
|
|
||||||
|
|
||||||
Это запустит скрипт в начале каждого часа (0 минут каждого часа).
|
|
||||||
|
|
||||||
### Альтернативные варианты расписания:
|
|
||||||
|
|
||||||
- `0 * * * *` - каждый час в начале часа (00:00, 01:00, 02:00...)
|
|
||||||
- `30 * * * *` - каждый час в 30 минут (00:30, 01:30, 02:30...)
|
|
||||||
- `*/30 * * * *` - каждые 30 минут
|
|
||||||
- `0 9-17 * * *` - каждый час с 9:00 до 17:00
|
|
||||||
|
|
||||||
### Просмотр логов:
|
|
||||||
|
|
||||||
Логи будут записываться в `/opt/testbot-git/runner_cron.log` (если указан в crontab).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Рекомендации
|
|
||||||
|
|
||||||
- **Systemd Timer** - лучше для интеграции с существующими сервисами, более гибкое управление, лучшие логи
|
|
||||||
- **Cron** - проще для простых задач, не требует root прав (можно использовать `crontab -e` без sudo)
|
|
||||||
|
|
||||||
|
Документация: [`docs/runner-setup.md`](../docs/runner-setup.md)
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Вспомогательные скрипты
|
||||||
|
|
||||||
|
Скрипты вне основного пайплайна (`runner.sh`) и systemd-сервисов. Запускать из **корня проекта** с активированным venv.
|
||||||
|
|
||||||
|
## ops/ — эксплуатация
|
||||||
|
|
||||||
|
| Файл | Назначение |
|
||||||
|
|------|------------|
|
||||||
|
| `genkey.py` | Генерация hex-ключа для `SECRET_KEY` / `WEBHOOK_SECRET` |
|
||||||
|
| `register_tg_webhook.py` | Ручная регистрация webhook (в норме — `wsgi_bot.py` при старте) |
|
||||||
|
| `copy_databases.sh` | Клонирование MariaDB между базами |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python tools/ops/genkey.py
|
||||||
|
./venv/bin/python tools/ops/register_tg_webhook.py
|
||||||
|
bash tools/ops/copy_databases.sh <source_db> <target_db> <username>
|
||||||
|
```
|
||||||
|
|
||||||
|
## dev/ — отладка и примеры
|
||||||
|
|
||||||
|
| Файл | Назначение |
|
||||||
|
|------|------------|
|
||||||
|
| `send_telegram_example.py` | CLI-пример API `/send_message` |
|
||||||
|
| `volk_telegram_testing.py` | Отладочный тест публикации в Telegram |
|
||||||
|
| `volk_category_testing.py` | Отладочный тест загрузки категории VOLK |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python tools/dev/send_telegram_example.py <user_id> "<message>"
|
||||||
|
python tools/dev/volk_telegram_testing.py
|
||||||
|
python tools/dev/volk_category_testing.py <category_id>
|
||||||
|
```
|
||||||
|
|
||||||
|
## legacy/ — снятые с пайплайна
|
||||||
|
|
||||||
|
| Файл | Назначение |
|
||||||
|
|------|------------|
|
||||||
|
| `evt_prefetch.py` | Массовая пометка видимых событий `marked_to_publication=1`. Убран из `runner.sh` в 1.0.0 |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./venv/bin/python tools/legacy/evt_prefetch.py
|
||||||
|
```
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Пример скрипта для отправки сообщений через Telegram бота
|
Пример скрипта для отправки сообщений через Telegram бота.
|
||||||
Использование: python send_telegram_example.py <user_id> <message>
|
|
||||||
|
Использование (из корня проекта):
|
||||||
|
python tools/dev/send_telegram_example.py <user_id> <message>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@@ -9,6 +11,12 @@ import requests
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
_PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
load_dotenv(os.path.join(_PROJECT_ROOT, ".env"))
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
def send_message(user_id, message_text, bot_url=None, api_token=None):
|
def send_message(user_id, message_text, bot_url=None, api_token=None):
|
||||||
"""
|
"""
|
||||||
Отправляет сообщение пользователю через Telegram бота
|
Отправляет сообщение пользователю через Telegram бота
|
||||||
@@ -64,8 +72,8 @@ def send_message(user_id, message_text, bot_url=None, api_token=None):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) != 3:
|
if len(sys.argv) != 3:
|
||||||
print("Использование: python send_telegram_example.py <user_id> <message>")
|
print("Использование: python tools/dev/send_telegram_example.py <user_id> <message>")
|
||||||
print("Пример: python send_telegram_example.py 123456789 'Привет! Это тестовое сообщение.'")
|
print("Пример: python tools/dev/send_telegram_example.py 123456789 'Привет! Это тестовое сообщение.'")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Тестовый модуль для проверки загрузки описания категории.
|
Тестовый модуль для проверки загрузки описания категории.
|
||||||
Использование: python volk_category_testing.py <category_id>
|
|
||||||
|
Использование (из корня проекта):
|
||||||
|
python tools/dev/volk_category_testing.py <category_id>
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@@ -15,7 +17,8 @@ from urllib.request import urlopen, Request
|
|||||||
from urllib.error import URLError, HTTPError
|
from urllib.error import URLError, HTTPError
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# Загрузка переменных окружения
|
_PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
load_dotenv(os.path.join(_PROJECT_ROOT, ".env"))
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
# Параметры из .env
|
# Параметры из .env
|
||||||
@@ -260,8 +263,8 @@ def main():
|
|||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
epilog="""
|
epilog="""
|
||||||
Примеры использования:
|
Примеры использования:
|
||||||
python volk_category_testing.py volk26_nri
|
python tools/dev/volk_category_testing.py volk26_nri
|
||||||
python volk_category_testing.py volk26_nri volk26_other volk26_third
|
python tools/dev/volk_category_testing.py volk26_nri volk26_other volk26_third
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -7,12 +7,17 @@ import sys
|
|||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
_PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
if _PROJECT_ROOT not in sys.path:
|
||||||
|
sys.path.insert(0, _PROJECT_ROOT)
|
||||||
|
|
||||||
|
load_dotenv(os.path.join(_PROJECT_ROOT, ".env"))
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
from telegram_relay import bot_api_method_url, get_relay_url
|
from telegram_relay import bot_api_method_url, get_relay_url
|
||||||
from season_links import subscription_start_link
|
from season_links import subscription_start_link
|
||||||
|
|
||||||
# Загрузка переменных окружения
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
# Настройки из переменных окружения
|
# Настройки из переменных окружения
|
||||||
POSTER_BOT_TOKEN = os.getenv('POSTER_BOT_TOKEN')
|
POSTER_BOT_TOKEN = os.getenv('POSTER_BOT_TOKEN')
|
||||||
RESPONDER_BOT_NAME = os.getenv('RESPONDER_BOT_NAME')
|
RESPONDER_BOT_NAME = os.getenv('RESPONDER_BOT_NAME')
|
||||||
@@ -1,10 +1,19 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""LEGACY — не входит в пайплайн runner.sh с версии 1.0.0.
|
||||||
|
|
||||||
|
Проставляет marked_to_publication = 1 видимым событиям (is_visible = 1),
|
||||||
|
у которых флаг ещё не установлен.
|
||||||
|
|
||||||
|
Запуск вручную из корня проекта:
|
||||||
|
./venv/bin/python tools/legacy/evt_prefetch.py
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
from mysql.connector import Error
|
from mysql.connector import Error
|
||||||
from datetime import datetime, timezone
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# Загрузка переменных окружения
|
_PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
load_dotenv(os.path.join(_PROJECT_ROOT, ".env"))
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
MDB_HOST = os.getenv('MDB_HOST')
|
MDB_HOST = os.getenv('MDB_HOST')
|
||||||
@@ -12,6 +21,7 @@ MDB_USER = os.getenv('MDB_USER')
|
|||||||
MDB_PW = os.getenv('MDB_PW')
|
MDB_PW = os.getenv('MDB_PW')
|
||||||
MDBASE = os.getenv('MDBASE')
|
MDBASE = os.getenv('MDBASE')
|
||||||
|
|
||||||
|
|
||||||
def prefetch_all_events():
|
def prefetch_all_events():
|
||||||
"""
|
"""
|
||||||
Проверяет записи в таблице events и устанавливает флаг marked_to_publication
|
Проверяет записи в таблице events и устанавливает флаг marked_to_publication
|
||||||
@@ -20,40 +30,33 @@ def prefetch_all_events():
|
|||||||
- не имеют флага marked_to_publication = 1
|
- не имеют флага marked_to_publication = 1
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Подключение к базе данных
|
|
||||||
connection = mysql.connector.connect(
|
connection = mysql.connector.connect(
|
||||||
host=MDB_HOST,
|
host=MDB_HOST,
|
||||||
user=MDB_USER,
|
user=MDB_USER,
|
||||||
password=MDB_PW,
|
password=MDB_PW,
|
||||||
database=MDBASE
|
database=MDBASE
|
||||||
)
|
)
|
||||||
|
|
||||||
# Установка временной зоны соединения в UTC
|
|
||||||
cursor_temp = connection.cursor()
|
cursor_temp = connection.cursor()
|
||||||
cursor_temp.execute("SET time_zone = '+00:00'")
|
cursor_temp.execute("SET time_zone = '+00:00'")
|
||||||
cursor_temp.close()
|
cursor_temp.close()
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
# SQL запрос для обновления записей
|
|
||||||
update_query = """
|
update_query = """
|
||||||
UPDATE events
|
UPDATE events
|
||||||
SET marked_to_publication = 1
|
SET marked_to_publication = 1
|
||||||
WHERE is_visible = 1
|
WHERE is_visible = 1
|
||||||
AND marked_to_publication = 0
|
AND marked_to_publication = 0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Выполнение запроса
|
|
||||||
cursor.execute(update_query)
|
cursor.execute(update_query)
|
||||||
updated_count = cursor.rowcount
|
updated_count = cursor.rowcount
|
||||||
|
|
||||||
# Фиксация изменений
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
print(f"Обновлено записей: {updated_count}")
|
print(f"Обновлено записей: {updated_count}")
|
||||||
|
|
||||||
return updated_count
|
return updated_count
|
||||||
|
|
||||||
except Error as e:
|
except Error as e:
|
||||||
print(f"Ошибка базы данных: {e}")
|
print(f"Ошибка базы данных: {e}")
|
||||||
if 'connection' in locals() and connection.is_connected():
|
if 'connection' in locals() and connection.is_connected():
|
||||||
@@ -67,5 +70,6 @@ def prefetch_all_events():
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
prefetch_all_events()
|
prefetch_all_events()
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Использование: ./copy_db.sh <source_db> <target_db> <username>
|
# Использование (из корня проекта):
|
||||||
# Пример: ./copy_db.sh old_db new_db appuser
|
# bash tools/ops/copy_databases.sh <source_db> <target_db> <username>
|
||||||
|
# Пример:
|
||||||
|
# bash tools/ops/copy_databases.sh old_db new_db appuser
|
||||||
|
|
||||||
set -e # Завершать выполнение при любой ошибке
|
set -e # Завершать выполнение при любой ошибке
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Генерация случайного hex-ключа для SECRET_KEY или WEBHOOK_SECRET.
|
||||||
|
|
||||||
|
Запуск из корня проекта:
|
||||||
|
python tools/ops/genkey.py
|
||||||
|
"""
|
||||||
|
import secrets
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(secrets.token_hex(32))
|
||||||
@@ -2,21 +2,24 @@
|
|||||||
"""
|
"""
|
||||||
Ручная регистрация Telegram webhook через internal_relay (с secret_token).
|
Ручная регистрация Telegram webhook через internal_relay (с secret_token).
|
||||||
|
|
||||||
Запуск на сервере бота:
|
Запуск из корня проекта:
|
||||||
cd /opt/testbot-git
|
./venv/bin/python tools/ops/register_tg_webhook.py
|
||||||
./venv/bin/python register_tg_webhook.py
|
|
||||||
|
|
||||||
Печатает полный ответ setWebhook — по нему видно, принял ли Telegram секрет.
|
Печатает полный ответ setWebhook — по нему видно, принял ли Telegram секрет.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
_PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
if _PROJECT_ROOT not in sys.path:
|
||||||
|
sys.path.insert(0, _PROJECT_ROOT)
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import os
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
|
load_dotenv(os.path.join(_PROJECT_ROOT, ".env"))
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
from telegram_relay import bot_api_method_url, get_relay_url
|
from telegram_relay import bot_api_method_url, get_relay_url
|
||||||
Reference in New Issue
Block a user