Приветствие снова читается одним блоком: фото с короткой подписью и одно сообщение
Первая строка welcome.text уходит подписью к фото, остальное вместе с text2 и text3 — одним сообщением с кнопкой. Так текст не разбит на три части и не упирается в лимит подписи к фото (1024 символа). В редакторе welcome.text появилась подсказка, что первая строка — подпись. Если понадобится больше гибкости, следующим шагом можно сделать последовательность сообщений с картинками.
This commit is contained in:
parent
8ae4e8bb6c
commit
34b6574e43
|
|
@ -151,7 +151,7 @@ make backup E=test # на домашнем сервере: ./scripts/clickho
|
|||
|
||||
## Версионирование
|
||||
|
||||
- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.4.14`.
|
||||
- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.4.15`.
|
||||
- Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`).
|
||||
- Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3).
|
||||
- Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`.
|
||||
|
|
@ -180,6 +180,13 @@ git tag -a vX.Y -m "Release vX.Y"
|
|||
git push origin master --tags
|
||||
```
|
||||
|
||||
## Приветствие новых участников
|
||||
|
||||
Бот отправляет фото с короткой персональной подписью (первая строка шаблона `welcome.text`),
|
||||
а затем одно сообщение со всем остальным текстом (`welcome.text` без первой строки +
|
||||
`welcome.text2` + `welcome.text3`) и кнопкой на канал. Так приветствие остаётся одним
|
||||
смысловым блоком, но не упирается в лимит подписи к фото (1024 символа).
|
||||
|
||||
## Пасхальное событие «Яички»
|
||||
|
||||
`/яички` работает только в сезон: по умолчанию с **1 апреля по православную Пасху**
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@
|
|||
<p class="mt-1 text-xs text-slate-500">
|
||||
Лимит Telegram — {{ max_length }} символов. Теги подставляет рендерер бота; неизвестный тег — ошибка.
|
||||
</p>
|
||||
{% if template.key == 'welcome.text' %}
|
||||
<p class="mt-2 rounded border border-sky-200 bg-sky-50 p-2 text-xs text-sky-800">
|
||||
Первая строка этого шаблона уходит подписью к фото, остальное — одним сообщением
|
||||
вместе с <span class="font-mono">welcome.text2</span> и <span class="font-mono">welcome.text3</span>.
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
|
|
|
|||
|
|
@ -52,18 +52,39 @@ async def welcome_handler(event: ChatMemberUpdated) -> None:
|
|||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text=welcome.MSG_WELCOME_BUTTON_CAPTION, url=welcome.MSG_WELCOME_BUTTON_URL)
|
||||
markup = builder.as_markup()
|
||||
|
||||
await event.bot.send_photo(
|
||||
chat_id=event.chat.id,
|
||||
photo=FSInputFile("images/welcome_image.jpg"),
|
||||
caption=render(await get_text("welcome.text"), {"username": user.username}),
|
||||
caption, body = welcome.split_welcome(
|
||||
await get_text("welcome.text"),
|
||||
await get_text("welcome.text2"),
|
||||
await get_text("welcome.text3"),
|
||||
)
|
||||
await event.bot.send_message(
|
||||
chat_id=event.chat.id,
|
||||
text=await get_text("welcome.text2"),
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
await event.bot.send_message(chat_id=event.chat.id, text=await get_text("welcome.text3"))
|
||||
caption = render(caption, {"username": user.username})
|
||||
body = render(body, {"username": user.username})
|
||||
|
||||
# Подпись к фото ограничена 1024 символами; если не влезла — уйдёт в тело.
|
||||
if len(caption) > 1024:
|
||||
body = caption + (f"\n\n{body}" if body else "")
|
||||
caption = ""
|
||||
|
||||
if body:
|
||||
await event.bot.send_photo(
|
||||
chat_id=event.chat.id,
|
||||
photo=FSInputFile("images/welcome_image.jpg"),
|
||||
caption=caption or None,
|
||||
)
|
||||
await event.bot.send_message(
|
||||
chat_id=event.chat.id,
|
||||
text=body,
|
||||
reply_markup=markup,
|
||||
)
|
||||
else:
|
||||
await event.bot.send_photo(
|
||||
chat_id=event.chat.id,
|
||||
photo=FSInputFile("images/welcome_image.jpg"),
|
||||
caption=caption or None,
|
||||
reply_markup=markup,
|
||||
)
|
||||
|
||||
|
||||
@router.chat_member(ChatMemberUpdatedFilter(member_status_changed=LEAVE_TRANSITION))
|
||||
|
|
|
|||
|
|
@ -36,3 +36,18 @@ MSG_WELCOME_TEXT3 = """❗️<b>По игре</b>:
|
|||
MSG_WELCOME_BUTTON_CAPTION = "Канал"
|
||||
|
||||
MSG_WELCOME_BUTTON_URL = "https://t.me/+DQk8MyN2y6QzNTM6"
|
||||
|
||||
|
||||
def split_welcome(*parts: str) -> tuple[str, str]:
|
||||
"""Разделить приветствие на подпись к фото и одно общее сообщение.
|
||||
|
||||
Первая строка первого шаблона становится подписью (персональное приветствие),
|
||||
всё остальное (включая ``text2``/``text3``) — одним сообщением по порядку.
|
||||
"""
|
||||
if not parts:
|
||||
return "", ""
|
||||
|
||||
caption, _, rest = parts[0].partition("\n")
|
||||
body_parts = [rest.rstrip(), *parts[1:]]
|
||||
body = "\n\n".join(part.strip() for part in body_parts if part and part.strip())
|
||||
return caption.strip(), body
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
__version__ = "0.4.14"
|
||||
__version__ = "0.4.15"
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ from common import __version__
|
|||
|
||||
def test_version_is_set():
|
||||
assert __version__
|
||||
assert __version__ == "0.4.14"
|
||||
assert __version__ == "0.4.15"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
"""Тесты сборки приветствия: подпись к фото + одно общее сообщение."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from common.texts.welcome import split_welcome
|
||||
|
||||
|
||||
def test_first_line_is_caption_rest_joins_body() -> None:
|
||||
caption, body = split_welcome(
|
||||
"💠{username}, добро пожаловать в Dispel Evil!\n\n❗️Правила клана\n1. …",
|
||||
"Часть 2",
|
||||
"Часть 3",
|
||||
)
|
||||
|
||||
assert caption == "💠{username}, добро пожаловать в Dispel Evil!"
|
||||
assert body == "❗️Правила клана\n1. …\n\nЧасть 2\n\nЧасть 3"
|
||||
|
||||
|
||||
def test_without_newline_all_text_is_caption() -> None:
|
||||
caption, body = split_welcome("Привет", "Второй", "Третий")
|
||||
|
||||
assert caption == "Привет"
|
||||
assert body == "Второй\n\nТретий"
|
||||
|
||||
|
||||
def test_empty_parts_are_skipped() -> None:
|
||||
caption, body = split_welcome("Привет\n\nТело", "", " ")
|
||||
|
||||
assert caption == "Привет"
|
||||
assert body == "Тело"
|
||||
|
||||
|
||||
def test_no_parts() -> None:
|
||||
assert split_welcome() == ("", "")
|
||||
Loading…
Reference in New Issue