From b651191fdb114d13e523ddd6a58ecb27c300d6a0 Mon Sep 17 00:00:00 2001 From: Dusan Vojacek Date: Fri, 12 Jun 2026 13:44:30 +0200 Subject: [PATCH] =?UTF-8?q?FIX:=20Discord=20notifikace=20se=20od=20za?= =?UTF-8?q?=C4=8D=C3=A1tku=20ti=C5=A1e=20zahazovaly=20=E2=80=94=20bot=20RE?= =?UTF-8?q?ST=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Všechny site webhook URL jsou NULL a env DISCORD_WEBHOOK_URL nebyl nastaven → send_discord vždy skončil na 'not configured, skipping' (uživatel: 'nikdy mi nic nepřišlo'). Fix: fallback přes bota (REST POST do DISCORD_EV_CHANNEL_ID — token už v .env, žádný webhook netřeba); webhook má přednost, kdyby ho uživatel později nastavil per site. Bot navíc při startu pošle '✅ online' (viditelný důkaz, 1× per deploy). Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/services/discord_bot.py | 7 +++++ backend/services/notification_service.py | 39 +++++++++++++++++------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/backend/services/discord_bot.py b/backend/services/discord_bot.py index 83832e3..7870c12 100644 --- a/backend/services/discord_bot.py +++ b/backend/services/discord_bot.py @@ -193,6 +193,13 @@ async def run_discord_bot() -> None: @client.event async def on_ready() -> None: logger.info("Discord bot připojen jako %s", client.user) + try: + channel_id = int(getattr(get_settings(), "discord_ev_channel_id", 0) or 0) + ch = client.get_channel(channel_id) if channel_id else None + if ch is not None: + await ch.send("✅ EMS bot online — notifikace aktivní") + except Exception: + logger.exception("Discord on_ready ping failed") @client.event async def on_interaction(interaction: discord.Interaction) -> None: diff --git a/backend/services/notification_service.py b/backend/services/notification_service.py index d2e5f00..6ce38af 100644 --- a/backend/services/notification_service.py +++ b/backend/services/notification_service.py @@ -195,24 +195,41 @@ async def send_discord( """ kind = "daily" if level == "info" else "error" webhook_url = await _get_site_webhook_url(conn, site_id, kind) - if not webhook_url: - logger.debug("Discord webhook not configured, skipping notification") - return False - emoji = {"info": "ℹ️", "warning": "⚠️", "error": "❌", "critical": "🚨"}.get(level, "ℹ️") + content = f"{emoji} **EMS** [{level.upper()}]\n{message}" + if webhook_url: + try: + async with httpx.AsyncClient(timeout=10) as client: + resp = await client.post(webhook_url, json={"content": content}) + resp.raise_for_status() + return True + except Exception as e: + logger.warning("Discord webhook failed: %s — zkouším bot fallback", e) + + # Fallback: bot REST (kanál z DISCORD_EV_CHANNEL_ID) — webhooky per site + # nebyly nikdy nastavené, takže bez fallbacku se notifikace tiše zahazovaly. + return await _send_via_bot(content) + + +async def _send_via_bot(content: str) -> bool: + s = get_settings() + token = (getattr(s, "discord_bot_token", "") or "").strip() + channel = (getattr(s, "discord_ev_channel_id", "") or "").strip() + if not token or not channel: + logger.debug("Discord: žádný webhook ani bot — notifikace zahozena") + return False try: async with httpx.AsyncClient(timeout=10) as client: - resp = await client.post( - webhook_url, - json={ - "content": f"{emoji} **EMS Alert** [{level.upper()}]\n{message}", - }, + r = await client.post( + f"https://discord.com/api/v10/channels/{channel}/messages", + headers={"Authorization": f"Bot {token}"}, + json={"content": content[:1900]}, ) - resp.raise_for_status() + r.raise_for_status() return True except Exception as e: - logger.warning("Discord notification failed: %s", e) + logger.warning("Discord bot fallback failed: %s", e) return False