From d85bc5b0f43076b9e3ff4cb69b2beb4e87a77448 Mon Sep 17 00:00:00 2001 From: MpakobecEx Date: Mon, 26 Oct 2026 00:31:27 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9E=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B1=D0=B5=D0=B7=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=B4=D0=B0=D0=B5=D1=82=20=D0=BD=D0=B0=20reply=5Fm?= =?UTF-8?q?arkup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit При пустом списке кнопок в Bot API уходило поле reply_markup: null, а Telegram ждёт объект или отсутствие поля. Теперь поле не передаётся, если кнопок нет — и для текста, и для фото. --- README.md | 2 +- admin/telegram.py | 36 ++++++++++++++---------------- common/version.py | 2 +- tests/test_admin_send.py | 48 ++++++++++++++++++++++++++++++++++++++++ tests/test_version.py | 2 +- 5 files changed, 67 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 63f70bc..8a77cc4 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ make backup E=test # на домашнем сервере: ./scripts/clickho ## Версионирование -- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.6.2`. +- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.6.3`. - Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`). - Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3). - Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`. diff --git a/admin/telegram.py b/admin/telegram.py index 98cfc4c..4b13aa0 100644 --- a/admin/telegram.py +++ b/admin/telegram.py @@ -123,16 +123,14 @@ async def send_to_chat( markup = {"inline_keyboard": rows} if rows else None if photo is None: - await _call( - settings, - "sendMessage", - { - "chat_id": settings.chat_id, - "text": text, - "parse_mode": "HTML", - "reply_markup": markup, - }, - ) + payload = { + "chat_id": settings.chat_id, + "text": text, + "parse_mode": "HTML", + } + if markup: + payload["reply_markup"] = markup + await _call(settings, "sendMessage", payload) return data, mime, filename = photo @@ -146,13 +144,11 @@ async def send_to_chat( await _call_multipart(settings, "sendPhoto", fields, {"photo": (filename, data, mime)}) if text and not caption: - await _call( - settings, - "sendMessage", - { - "chat_id": settings.chat_id, - "text": text, - "parse_mode": "HTML", - "reply_markup": markup, - }, - ) + payload = { + "chat_id": settings.chat_id, + "text": text, + "parse_mode": "HTML", + } + if markup: + payload["reply_markup"] = markup + await _call(settings, "sendMessage", payload) diff --git a/common/version.py b/common/version.py index c48b447..a0d7363 100644 --- a/common/version.py +++ b/common/version.py @@ -7,4 +7,4 @@ from __future__ import annotations -__version__ = "0.6.2" +__version__ = "0.6.3" diff --git a/tests/test_admin_send.py b/tests/test_admin_send.py index 5275bdc..f19cc65 100644 --- a/tests/test_admin_send.py +++ b/tests/test_admin_send.py @@ -8,6 +8,7 @@ import pytest from fastapi.testclient import TestClient from admin import telegram +from common.config import AdminSettings from common.repositories import admin_messages_repo @@ -116,3 +117,50 @@ def test_send_telegram_error( assert "chat not found" in response.text assert fake_send["audit"]["success"] is False assert fake_send["audit"]["error"] == "chat not found" + + +async def test_telegram_omits_reply_markup_without_buttons(monkeypatch: pytest.MonkeyPatch) -> None: + calls: list[dict[str, Any]] = [] + + async def fake_call(settings: Any, method: str, payload: dict[str, Any]) -> None: + calls.append(payload) + + monkeypatch.setattr(telegram, "_call", fake_call) + settings = AdminSettings(_env_file=None, bot_token="1:a", chat_id=-100) + + await telegram.send_to_chat(settings, text="Привет", buttons=[], photo=None) + + assert "reply_markup" not in calls[0] + + +async def test_telegram_adds_reply_markup_with_buttons(monkeypatch: pytest.MonkeyPatch) -> None: + calls: list[dict[str, Any]] = [] + + async def fake_call(settings: Any, method: str, payload: dict[str, Any]) -> None: + calls.append(payload) + + monkeypatch.setattr(telegram, "_call", fake_call) + settings = AdminSettings(_env_file=None, bot_token="1:a", chat_id=-100) + + await telegram.send_to_chat(settings, text="Привет", buttons=[("Канал", "https://t.me/x")], photo=None) + + assert calls[0]["reply_markup"]["inline_keyboard"][0][0]["url"] == "https://t.me/x" + + +async def test_telegram_photo_omits_reply_markup_without_buttons(monkeypatch: pytest.MonkeyPatch) -> None: + fields: list[dict[str, str]] = [] + + async def fake_multipart(settings: Any, method: str, data: dict[str, str], files: dict[str, Any]) -> None: + fields.append(data) + + monkeypatch.setattr(telegram, "_call_multipart", fake_multipart) + settings = AdminSettings(_env_file=None, bot_token="1:a", chat_id=-100) + + await telegram.send_to_chat( + settings, + text="Подпись", + buttons=[], + photo=(b"data", "image/png", "pic.png"), + ) + + assert "reply_markup" not in fields[0] diff --git a/tests/test_version.py b/tests/test_version.py index 2f8b8df..2b6b99a 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -7,4 +7,4 @@ from common import __version__ def test_version_is_set(): assert __version__ - assert __version__ == "0.6.2" + assert __version__ == "0.6.3"