feat: подпись имени пользователя на сообщении в топике

В топике было непонятно, от кого сообщение: текст приходил без автора.

- Текст уходит в топик как «<Имя>:\n<текст>»; имени нет — «<id>:\n<текст>»
  (user_signature()).
- Caption медиа уходит текстом с той же подписью, само медиа копируется.
- Всё остальное (фото, документы, голосовые без подписи) копируется как есть,
  без подписи — как и просили «если не текст, то пофиг».

Симметрично подписи оператора «Оператор поддержки:» на ответах.

Тесты: 244 OK (8 новых — подпись имени, fallback на id, медиа с caption,
медиа без текста копируется без подписи).

VERSION: 0.1.0+57 -> 0.1.0+58
This commit is contained in:
hermes committed 2026-10-11 20:22:34 +02:00
1 parent 6938c1d0f3
commit 175d618d62
5 files changed
+130 -7

No files matched your search

+84
View File
@@ -345,6 +345,90 @@ class SupportStartTextTests(unittest.TestCase):
self.assertNotIn("оператор", rendered.lower())
class UserSignatureTests(unittest.IsolatedAsyncioTestCase):
"""Сообщение пользователя в топике подписывается его именем или id."""
def _user(self, first_name="Иван", last_name=None, user_id=42):
return SimpleNamespace(
id=user_id, first_name=first_name, last_name=last_name, is_bot=False
)
def test_signature_uses_first_and_last_name(self):
self.assertEqual(
support.user_signature(self._user("Иван", "Петров")), "Иван Петров"
)
def test_signature_uses_first_name_only(self):
self.assertEqual(support.user_signature(self._user("Иван")), "Иван")
def test_signature_falls_back_to_id(self):
self.assertEqual(support.user_signature(self._user(None, None, 42)), "42")
def test_signature_ignores_blank_name(self):
self.assertEqual(support.user_signature(self._user(" ", None, 42)), "42")
class UserMessageToTopicTests(unittest.IsolatedAsyncioTestCase):
"""Сообщение пользователя уходит в топик с подписью; медиа — как есть."""
def _user(self, first_name="Иван", last_name=None, user_id=42):
return SimpleNamespace(
id=user_id, first_name=first_name, last_name=last_name, is_bot=False
)
async def test_text_is_sent_with_signature(self):
bot = AsyncMock()
message = SimpleNamespace(
text="не работает оплата", caption=None,
chat=SimpleNamespace(id=555), message_id=10,
)
await support._send_user_message_to_topic(bot, message, -100123, 14, self._user())
bot.send_message.assert_awaited_once()
kwargs = bot.send_message.await_args.kwargs
self.assertEqual(kwargs["chat_id"], -100123)
self.assertEqual(kwargs["message_thread_id"], 14)
self.assertEqual(kwargs["text"], "Иван:\nне работает оплата")
bot.copy_message.assert_not_awaited()
async def test_media_without_text_is_copied_as_is(self):
bot = AsyncMock()
message = SimpleNamespace(
text=None, caption=None,
chat=SimpleNamespace(id=555), message_id=11,
)
await support._send_user_message_to_topic(bot, message, -100123, 14, self._user())
bot.send_message.assert_not_awaited()
bot.copy_message.assert_awaited_once_with(
chat_id=-100123, from_chat_id=555, message_id=11, message_thread_id=14
)
async def test_caption_is_sent_as_text_then_media_copied(self):
bot = AsyncMock()
message = SimpleNamespace(
text=None, caption="вот скриншот",
chat=SimpleNamespace(id=555), message_id=12,
)
await support._send_user_message_to_topic(bot, message, -100123, 14, self._user())
self.assertEqual(bot.send_message.await_args.kwargs["text"], "Иван:\nвот скриншот")
bot.copy_message.assert_awaited_once_with(
chat_id=-100123, from_chat_id=555, message_id=12, message_thread_id=14
)
async def test_signature_falls_back_to_user_id(self):
bot = AsyncMock()
message = SimpleNamespace(
text="привет", caption=None,
chat=SimpleNamespace(id=555), message_id=13,
)
await support._send_user_message_to_topic(
bot, message, -100123, 14, self._user(None, None, 99)
)
self.assertEqual(bot.send_message.await_args.kwargs["text"], "99:\nпривет")
class OperatorSignatureTests(unittest.IsolatedAsyncioTestCase):
"""Ответ оператора приходит пользователю с подписью «Оператор поддержки:»."""