feat: подпись «Оператор поддержки» на ответе оператора

Ответ из топика приходил пользователю без подписи, и было непонятно, кто
пишет — бот или человек.

- Текст уходит одним сообщением: «Оператор поддержки:\n<текст>».
- У медиа copy_message не позволяет подменить caption, поэтому подпись
  отправляется отдельным сообщением перед копией; caption медиа, если был,
  попадает в то же сообщение.
- Подпись задаётся SUPPORT_OPERATOR_SIGNATURE (default «Оператор поддержки»).
- Заметки с префиксом // по-прежнему не уходят пользователю.

Тесты: 236 OK (6 новых — текст, медиа с caption, медиа без caption,
переопределение подписи через env).

VERSION: 0.1.0+56 -> 0.1.0+57
This commit is contained in:
hermes committed 2026-10-11 19:59:34 +02:00
1 parent 3dd2924d5e
commit 6938c1d0f3
5 files changed
+109 -10

No files matched your search

+39 -5
View File
@@ -64,6 +64,19 @@ def note_prefix() -> str:
return raw or NOTE_PREFIX_DEFAULT
DEFAULT_OPERATOR_SIGNATURE = "Оператор поддержки"
def operator_signature() -> str:
"""Подпись, с которой ответ оператора приходит пользователю в личку.
Задаётся переменной `SUPPORT_OPERATOR_SIGNATURE`; по умолчанию —
«Оператор поддержки». Формат сообщения: «<подпись>:\n<текст>».
"""
raw = os.getenv("SUPPORT_OPERATOR_SIGNATURE", "").strip()
return raw or DEFAULT_OPERATOR_SIGNATURE
def topic_icon_emoji_id() -> str | None:
raw = os.getenv("SUPPORT_TOPIC_EMOJI_ID", "").strip()
return raw or None
@@ -383,6 +396,31 @@ async def start_support(message: Message) -> None:
# Топик → пользователь
# --------------------------------------------------------------------------- #
async def _deliver_operator_reply(bot: Bot, message: Message, user_id: int) -> None:
"""Доставляет ответ оператора пользователю, добавляя подпись.
Текст уходит одним сообщением с подписью в начале. Медиа копируется
`copy_message` (caption у копии задать нельзя), поэтому подпись отправляется
отдельным сообщением перед ним.
"""
signature = operator_signature()
text = (message.text or "").strip()
if text:
await bot.send_message(chat_id=user_id, text=f"{signature}:\n{text}")
return
caption = (message.caption or "").strip()
if caption:
# У медиа есть подпись — пересылаем её текстом, само медиа копируем ниже.
await bot.send_message(chat_id=user_id, text=f"{signature}:\n{caption}")
else:
await bot.send_message(chat_id=user_id, text=f"{signature}:")
await bot.copy_message(
chat_id=user_id,
from_chat_id=message.chat.id,
message_id=message.message_id,
)
def _is_service_message(message: Message) -> bool:
text = (message.text or message.caption or "").strip()
prefix = note_prefix()
@@ -413,11 +451,7 @@ async def handle_support_group_message(message: Message) -> None:
if bot is None:
return
try:
await bot.copy_message(
chat_id=user_id,
from_chat_id=message.chat.id,
message_id=message.message_id,
)
await _deliver_operator_reply(bot, message, user_id)
except Exception as exc:
logger.error("Support reply delivery failed user=%s (%s)", user_id, type(exc).__name__)
try: