- register_max_webhook.py, fetch_schema.py - n8n-code-node-max-normalize.js (max_id, callback из callback.user, contact из vcf_info) - n8n-code-add-menu-buttons.js (меню с callback, request_contact, Главное меню) - docs: max-webhook, max-curl-http-request, max-api (форматы, кнопки, контакт), clpr vs sprf - README, SITUATION, схемы sprf_ и clpr_, .gitignore Co-authored-by: Cursor <cursoragent@cursor.com>
76 lines
3.0 KiB
Python
76 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Регистрация Webhook бота MAX на URL n8n.
|
||
Вызов: python3 register_max_webhook.py
|
||
|
||
Перед запуском:
|
||
1. В n8n создан воркфлоу с нодой Webhook (Production), путь = последняя часть N8N_MAX_WORKFLOW
|
||
(например, для https://n8n.clientright.pro/webhook/sprf_max путь в ноде = sprf_max).
|
||
2. В .env заданы MAX_BOT_TOKEN, N8N_MAX_WORKFLOW (полный HTTPS URL webhook).
|
||
3. По желанию задан MAX_WEBHOOK_SECRET — тогда MAX будет присылать его в заголовке X-Max-Bot-Api-Secret.
|
||
"""
|
||
import os
|
||
import json
|
||
import urllib.request
|
||
from pathlib import Path
|
||
|
||
# Загрузка .env
|
||
env_path = Path(__file__).parent / ".env"
|
||
for line in env_path.read_text().splitlines():
|
||
line = line.strip()
|
||
if not line or line.startswith("#"):
|
||
continue
|
||
if "=" in line:
|
||
k, v = line.split("=", 1)
|
||
os.environ[k.strip()] = v.strip()
|
||
|
||
MAX_API_BASE = os.environ.get("MAX_API_BASE", "https://platform-api.max.ru").rstrip("/")
|
||
MAX_BOT_TOKEN = os.environ.get("MAX_BOT_TOKEN", "").strip()
|
||
N8N_MAX_WORKFLOW = os.environ.get("N8N_MAX_WORKFLOW", "").strip()
|
||
MAX_WEBHOOK_SECRET = os.environ.get("MAX_WEBHOOK_SECRET", "").strip()
|
||
|
||
if not MAX_BOT_TOKEN:
|
||
print("Ошибка: в .env не задан MAX_BOT_TOKEN")
|
||
exit(1)
|
||
if not N8N_MAX_WORKFLOW or not N8N_MAX_WORKFLOW.startswith("https://"):
|
||
print("Ошибка: в .env задайте N8N_MAX_WORKFLOW — полный HTTPS URL webhook (например https://n8n.clientright.pro/webhook/sprf_max)")
|
||
exit(1)
|
||
|
||
# Типы событий, которые бот будет получать
|
||
update_types = ["message_created", "message_callback", "bot_started"]
|
||
body = {"url": N8N_MAX_WORKFLOW, "update_types": update_types}
|
||
if MAX_WEBHOOK_SECRET:
|
||
body["secret"] = MAX_WEBHOOK_SECRET
|
||
print("Секрет для проверки в n8n (X-Max-Bot-Api-Secret): задан в .env")
|
||
else:
|
||
print("Секрет не задан (MAX_WEBHOOK_SECRET в .env). Рекомендуется задать для проверки запросов в n8n.")
|
||
|
||
req = urllib.request.Request(
|
||
f"{MAX_API_BASE}/subscriptions",
|
||
data=json.dumps(body).encode("utf-8"),
|
||
headers={
|
||
"Authorization": MAX_BOT_TOKEN,
|
||
"Content-Type": "application/json",
|
||
},
|
||
method="POST",
|
||
)
|
||
try:
|
||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||
data = resp.read().decode()
|
||
out = json.loads(data) if data else {}
|
||
if out.get("success") is True:
|
||
print("Webhook зарегистрирован успешно.")
|
||
print("URL:", N8N_MAX_WORKFLOW)
|
||
print("Типы событий:", ", ".join(update_types))
|
||
else:
|
||
print("Ответ API:", data)
|
||
exit(1)
|
||
except urllib.error.HTTPError as e:
|
||
body = e.read().decode()
|
||
print(f"Ошибка HTTP {e.code}: {e.reason}")
|
||
print("Тело ответа:", body)
|
||
exit(1)
|
||
except Exception as e:
|
||
print("Ошибка:", e)
|
||
exit(1)
|