mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat: Telegram messages get real formatting + push DMs at draft origination (#568)
* feat(telegram): HTML-styled bot messages + push DMs at held-draft origination * fix(telegram): attr-context escaping, balance-aware truncation, send observability; docs --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
@@ -290,8 +290,10 @@ async def test_notify_telegram_send_deferred_to_after_commit(
|
||||
*,
|
||||
reply_markup: dict | None = None,
|
||||
reply_to_message_id: int | None = None,
|
||||
parse_mode: str | None = None,
|
||||
disable_link_preview: bool = False,
|
||||
) -> TelegramSendResult:
|
||||
_ = (reply_markup, reply_to_message_id)
|
||||
_ = (reply_markup, reply_to_message_id, parse_mode, disable_link_preview)
|
||||
sent.append(text)
|
||||
return TelegramSendResult(sent=True)
|
||||
|
||||
@@ -312,7 +314,73 @@ async def test_notify_telegram_send_deferred_to_after_commit(
|
||||
await db_session.commit()
|
||||
await _await_drain(db_session)
|
||||
|
||||
assert sent == ["Hello CEO"]
|
||||
assert sent == ["<b>Hello CEO</b>"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_notify_ceo_of_queue_item_deferred_escaped_and_keyboarded(
|
||||
db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""The origination-time push DM (release/xpost/video/roadmap drafts)
|
||||
reuses the exact ``/queue`` item renderer + keyboard, rides the same
|
||||
after-commit outbox as ``_notify_telegram``, and escapes a malicious
|
||||
title before it ever reaches the Bot API payload."""
|
||||
monkeypatch.setattr(settings, "telegram_enabled", True)
|
||||
|
||||
creds = TelegramCredentialsData(bot_token="t", chat_id="1")
|
||||
|
||||
class _FakeCredsService:
|
||||
async def get_decrypted(self) -> TelegramCredentialsData:
|
||||
return creds
|
||||
|
||||
monkeypatch.setattr(
|
||||
"roboco.services.telegram_credentials.get_telegram_credentials_service",
|
||||
lambda _session: _FakeCredsService(),
|
||||
)
|
||||
|
||||
sent: list[tuple[str, dict | None, str | None]] = []
|
||||
|
||||
class _FakeTelegramClient:
|
||||
async def send_message(
|
||||
self,
|
||||
text: str,
|
||||
*,
|
||||
reply_markup: dict | None = None,
|
||||
reply_to_message_id: int | None = None,
|
||||
parse_mode: str | None = None,
|
||||
disable_link_preview: bool = False,
|
||||
) -> TelegramSendResult:
|
||||
_ = (reply_to_message_id, disable_link_preview)
|
||||
sent.append((text, reply_markup, parse_mode))
|
||||
return TelegramSendResult(sent=True)
|
||||
|
||||
async def close(self) -> None:
|
||||
pass
|
||||
|
||||
monkeypatch.setattr(
|
||||
"roboco.services.telegram_client.build_telegram_client",
|
||||
lambda _creds, **_kwargs: _FakeTelegramClient(),
|
||||
)
|
||||
|
||||
service = get_notification_delivery_service(db_session)
|
||||
await service.notify_ceo_of_queue_item(
|
||||
kind="release", id8="a1b2c3d4", title="<b>v1.0.0</b> ready"
|
||||
)
|
||||
|
||||
assert sent == [] # deferred — nothing before commit
|
||||
|
||||
await db_session.commit()
|
||||
await _await_drain(db_session)
|
||||
|
||||
assert len(sent) == 1
|
||||
text, reply_markup, parse_mode = sent[0]
|
||||
assert "<b>v1.0.0</b> ready" in text
|
||||
assert "<b>v1.0.0</b> ready" not in text # never unescaped
|
||||
assert text.startswith("🚀 <b>Release</b>")
|
||||
assert parse_mode == "HTML"
|
||||
assert reply_markup is not None
|
||||
row = reply_markup["inline_keyboard"][0]
|
||||
assert row[0]["callback_data"] == "apv:release:a1b2c3d4"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -344,8 +412,10 @@ async def test_notify_telegram_rollback_drops_send(
|
||||
*,
|
||||
reply_markup: dict | None = None,
|
||||
reply_to_message_id: int | None = None,
|
||||
parse_mode: str | None = None,
|
||||
disable_link_preview: bool = False,
|
||||
) -> TelegramSendResult:
|
||||
_ = (reply_markup, reply_to_message_id)
|
||||
_ = (reply_markup, reply_to_message_id, parse_mode, disable_link_preview)
|
||||
sent.append(text)
|
||||
return TelegramSendResult(sent=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user