fix: показывать причину сбоя поддержки в development

Создание топика падало с «not enough rights to create a topic» (бот был
обычным участником группы, а не администратором), но пользователь видел
только «Поддержка временно недоступна. Попробуй позже» — по такому сообщению
невозможно понять, что чинить.

- ensure_topic возвращает (thread_id, причина) вместо одного thread_id.
- Текст Telegram логируется на ERROR: по типу исключения причина нечитаема.
- В DEPLOY_ENV=development причина добавляется в сообщение пользователю;
  в production остаётся общая заглушка. HTML экранируется.

Проверено: 214 тестов OK (7 новых на причину и её выдачу).
Живая проверка на dev: после выдачи боту прав администратора с «Управление
темами» create_forum_topic создал топик (thread_id 18, пробный удалён).

VERSION: 0.1.0+52 -> 0.1.0+53
This commit is contained in:
hermes committed 2026-10-11 17:04:33 +02:00
1 parent 21db563f28
commit 4076765618
5 files changed
+107 -18

No files matched your search

+56 -2
View File
@@ -249,10 +249,64 @@ class SupportTopicTests(_TempDbCase):
first = asyncio.run(support.ensure_topic(bot, user))
second = asyncio.run(support.ensure_topic(bot, user))
self.assertEqual(first, 777)
self.assertEqual(second, 777)
self.assertEqual(first[0], 777)
self.assertIsNone(first[1])
self.assertEqual(second[0], 777)
bot.create_forum_topic.assert_awaited_once()
def test_topic_creation_failure_returns_reason(self):
with patch.dict("os.environ", {"SUPPORT_GROUP_ID": "-100123"}, clear=False):
bot = AsyncMock()
bot.create_forum_topic = AsyncMock(
side_effect=RuntimeError("Bad Request: not enough rights to create a topic")
)
thread_id, reason = asyncio.run(support.ensure_topic(bot, self._tg_user()))
self.assertIsNone(thread_id)
self.assertIn("not enough rights", reason)
def test_topic_creation_failure_logs_telegram_reason(self):
with patch.dict("os.environ", {"SUPPORT_GROUP_ID": "-100123"}, clear=False):
bot = AsyncMock()
bot.create_forum_topic = AsyncMock(
side_effect=RuntimeError("Bad Request: not enough rights to create a topic")
)
with self.assertLogs("support", level="ERROR") as captured:
asyncio.run(support.ensure_topic(bot, self._tg_user()))
self.assertIn("not enough rights", "\n".join(captured.output))
def test_unavailable_text_hides_reason_outside_development(self):
with patch.dict("os.environ", {"DEPLOY_ENV": "production"}, clear=False):
text = support._unavailable_text("not enough rights to create a topic")
self.assertNotIn("not enough rights", text)
self.assertIn("временно недоступна", text)
def test_unavailable_text_shows_reason_in_development(self):
with patch.dict("os.environ", {"DEPLOY_ENV": "development"}, clear=False):
text = support._unavailable_text("not enough rights to create a topic")
self.assertIn("not enough rights", text)
self.assertIn("Dev-диагностика", text)
def test_unavailable_text_without_reason_is_plain(self):
with patch.dict("os.environ", {"DEPLOY_ENV": "development"}, clear=False):
text = support._unavailable_text(None)
self.assertEqual(text, support.SUPPORT_UNAVAILABLE_TEXT)
def test_unavailable_text_escapes_html(self):
with patch.dict("os.environ", {"DEPLOY_ENV": "development"}, clear=False):
text = support._unavailable_text("<b>x</b> & y")
self.assertNotIn("<b>x</b>", text)
self.assertIn("&lt;b&gt;x&lt;/b&gt;", text)
def test_topic_creation_is_skipped_when_disabled(self):
with patch.dict("os.environ", {"SUPPORT_GROUP_ID": ""}, clear=False):
bot = AsyncMock()
thread_id, reason = asyncio.run(support.ensure_topic(bot, self._tg_user()))
self.assertIsNone(thread_id)
self.assertIsNone(reason)
bot.create_forum_topic.assert_not_awaited()
def test_profile_card_is_sent_only_on_topic_creation(self):
with patch.dict("os.environ", {"SUPPORT_GROUP_ID": "-100123"}, clear=False):
bot = AsyncMock()