Упрощение для балбесов
This commit is contained in:
@@ -13,13 +13,12 @@ from aiogram.types import CallbackQuery, Message
|
||||
from glitchup_bot.bot.keyboards import (
|
||||
admin_home_keyboard,
|
||||
admin_overview_keyboard,
|
||||
admin_recipient_group_keyboard,
|
||||
admin_recipients_keyboard,
|
||||
admin_result_keyboard,
|
||||
admin_sync_keyboard,
|
||||
help_home_keyboard,
|
||||
help_monitoring_keyboard,
|
||||
help_releases_keyboard,
|
||||
help_result_keyboard,
|
||||
help_subscriptions_keyboard,
|
||||
)
|
||||
from glitchup_bot.services.admins import (
|
||||
add_admin,
|
||||
@@ -30,8 +29,6 @@ from glitchup_bot.services.admins import (
|
||||
from glitchup_bot.services.digest_builder import (
|
||||
build_digest,
|
||||
build_project_summary,
|
||||
build_release_detail,
|
||||
build_release_summary,
|
||||
build_stale_issues,
|
||||
build_sync_status,
|
||||
build_today_summary,
|
||||
@@ -52,12 +49,14 @@ from glitchup_bot.services.routing import (
|
||||
set_project_group,
|
||||
set_topic_override,
|
||||
)
|
||||
from glitchup_bot.services.sync_service import get_last_sync_state
|
||||
|
||||
router = Router()
|
||||
logger = logging.getLogger(__name__)
|
||||
MAX_PAGE_CHARS = 3000
|
||||
MAX_PAGE_LINES = 18
|
||||
MAX_PAGINATION_SESSIONS = 200
|
||||
PENDING_RECIPIENT_ACTIONS: dict[int, tuple[str, str]] = {}
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -148,97 +147,46 @@ def _result_keyboard(
|
||||
|
||||
|
||||
def _help_text(is_admin: bool) -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>GlitchUp Bot</b>",
|
||||
"",
|
||||
"Выберите нужную сводку кнопками ниже.",
|
||||
"Пользователю доступны только базовые экраны.",
|
||||
"",
|
||||
"• Сегодня",
|
||||
"• Неделя",
|
||||
"• Самые шумные",
|
||||
"• Давно висят",
|
||||
*(["", "• Для управления откройте админ-панель"] if is_admin else []),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
async def _start_text(is_admin: bool) -> str:
|
||||
state = await get_last_sync_state("api_sync")
|
||||
sync_value = (
|
||||
state.last_successful_at.astimezone().strftime("%Y-%m-%d %H:%M")
|
||||
if state and state.last_successful_at
|
||||
else "ещё не было"
|
||||
)
|
||||
lines = [
|
||||
"<b>GlitchUp Bot</b>",
|
||||
f"Синхронизация: {escape(sync_value)}",
|
||||
"",
|
||||
"Понятное меню для просмотра ошибок, релизов и подписок.",
|
||||
"",
|
||||
"<b>Что можно сделать:</b>",
|
||||
"• открыть сводку за неделю или за сегодня",
|
||||
"• посмотреть топ самых шумных и старых issues",
|
||||
"• проверить последние релизы",
|
||||
"• включить или отключить личные уведомления",
|
||||
"• узнать статус последней синхронизации",
|
||||
"",
|
||||
"<b>Быстрые команды:</b>",
|
||||
"• /week, /today, /top, /stale",
|
||||
"• /releases, /release <version>",
|
||||
"• /project <slug>",
|
||||
"• /subscribe backend|frontend",
|
||||
"• /unsubscribe backend|frontend",
|
||||
"Откройте нужную сводку кнопками ниже.",
|
||||
]
|
||||
|
||||
if is_admin:
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"<b>Для админа:</b>",
|
||||
"• /admin — панель управления",
|
||||
"• /sync — принудительная синхронизация",
|
||||
"• /admins — список администраторов",
|
||||
"• /admin_add <user_id> или reply на сообщение",
|
||||
"• /admin_del <user_id>",
|
||||
"• /ownership — текущее распределение routing-настроек",
|
||||
"• /mute_list — список mute rules",
|
||||
]
|
||||
)
|
||||
|
||||
lines.extend(["", "Администрирование доступно через кнопку ниже."])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _help_monitoring_text() -> str:
|
||||
def _admin_overview_text() -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>Обзор и мониторинг</b>",
|
||||
"<b>Сводки</b>",
|
||||
"",
|
||||
"Здесь собраны основные срезы по состоянию проектов.",
|
||||
"",
|
||||
"• <b>Сводка за неделю</b> — общая картина по новым issues и regressions",
|
||||
"• <b>Сегодня</b> — свежие проблемы за текущий день",
|
||||
"• <b>Топ issues</b> — самые шумные ошибки по числу событий",
|
||||
"• <b>Старые issues</b> — незакрытые проблемы, которые давно висят",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _help_releases_text() -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>Релизы и версии</b>",
|
||||
"",
|
||||
"Раздел помогает быстро понять, после каких релизов появились незакрытые issues.",
|
||||
"",
|
||||
"• <b>Список релизов</b> покажет версии, у которых есть активные проблемы",
|
||||
"• <b>Как открыть релиз</b> подскажет, как перейти к деталям по конкретной версии",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _help_release_guide_text() -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>Как смотреть детали релиза</b>",
|
||||
"",
|
||||
"1. Открой <b>Список релизов</b> и скопируй нужную версию.",
|
||||
"2. Выполни команду <code>/release <version></code>.",
|
||||
"3. Бот покажет issues, связанные именно с этим релизом.",
|
||||
"",
|
||||
"Пример: <code>/release 2026.03.27</code>",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _help_subscriptions_text() -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>Подписки</b>",
|
||||
"",
|
||||
"Здесь можно управлять личными уведомлениями в DM.",
|
||||
"",
|
||||
"• <b>backend</b> — проблемы серверной части",
|
||||
"• <b>frontend</b> — проблемы клиентских приложений и web",
|
||||
"",
|
||||
"Подписка добавляет вас в runtime-настройки без редактирования `.env`.",
|
||||
"Быстрый доступ к основным экранам без лишних разделов.",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -248,13 +196,12 @@ def _admin_text() -> str:
|
||||
[
|
||||
"<b>Админ-панель GlitchUp Bot</b>",
|
||||
"",
|
||||
"Панель разделена на понятные зоны, чтобы не искать нужное действие в длинном списке.",
|
||||
"",
|
||||
"• <b>Центр синхронизации</b> — запуск sync и проверка статуса",
|
||||
"• <b>Сводки и мониторинг</b> — основные обзорные экраны",
|
||||
"• <b>Администраторы</b> — список и управление доступом",
|
||||
"• <b>Ownership и topics</b> — текущая маршрутизация",
|
||||
"• <b>Mute rules</b> — правила скрытия шумных событий",
|
||||
"Здесь только практичные разделы:",
|
||||
"• синхронизация",
|
||||
"• основные сводки",
|
||||
"• получатели по backend/frontend",
|
||||
"• администраторы",
|
||||
"• routing и mute rules",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -262,20 +209,31 @@ def _admin_text() -> str:
|
||||
def _admin_sync_text() -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>Центр синхронизации</b>",
|
||||
"<b>Синхронизация</b>",
|
||||
"",
|
||||
"Отсюда удобно запускать ручной sync и смотреть, "
|
||||
"Отсюда удобно запускать ручной sync и проверять, "
|
||||
"когда данные обновлялись в последний раз.",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _admin_overview_text() -> str:
|
||||
def _admin_recipients_text() -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
"<b>Сводки и мониторинг</b>",
|
||||
"<b>Получатели уведомлений</b>",
|
||||
"",
|
||||
"Быстрый доступ к основным обзорным экранам для ручной проверки состояния проектов.",
|
||||
"Выберите группу и назначайте Telegram ID через кнопки.",
|
||||
"Самоподписка пользователей отключена.",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _recipient_group_text(group_name: str) -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
f"<b>{escape(group_name.capitalize())} получатели</b>",
|
||||
"",
|
||||
"Можно посмотреть список, добавить новый Telegram ID или удалить существующий.",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -285,8 +243,7 @@ def _admin_guide_text() -> str:
|
||||
[
|
||||
"<b>Подсказка по админке</b>",
|
||||
"",
|
||||
"Через кнопки удобно смотреть состояние системы, "
|
||||
"а точечные настройки меняются командами.",
|
||||
"Почти всё вынесено в кнопки и короткие сценарии.",
|
||||
"",
|
||||
"• <code>/admin_add 123456</code> — добавить администратора",
|
||||
"• <code>/admin_add</code> ответом на сообщение — добавить автора сообщения",
|
||||
@@ -344,6 +301,18 @@ def _extract_target_user_id(message: Message) -> int | None:
|
||||
return None
|
||||
|
||||
|
||||
async def _recipients_text(group_name: str) -> str:
|
||||
subscribers = await resolve_subscribers(group_name)
|
||||
title = "Backend" if group_name == "backend" else "Frontend"
|
||||
if not subscribers:
|
||||
return f"<b>{title} получатели</b>\n\nСписок пуст."
|
||||
|
||||
lines = [f"<b>{title} получатели</b>", ""]
|
||||
for user_id in subscribers:
|
||||
lines.append(f"• <code>{user_id}</code>")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
async def _require_admin(message: Message) -> bool:
|
||||
if await _is_admin_user(_sender_id(message)):
|
||||
return True
|
||||
@@ -594,7 +563,7 @@ async def _mute_rules_text() -> str:
|
||||
async def cmd_start(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await message.answer(
|
||||
_help_text(is_admin),
|
||||
await _start_text(is_admin),
|
||||
reply_markup=help_home_keyboard(is_admin),
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
@@ -636,100 +605,38 @@ async def cb_help_actions(callback: CallbackQuery) -> None:
|
||||
reply_markup=help_home_keyboard(is_admin),
|
||||
)
|
||||
return
|
||||
if action == "menu:monitoring":
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
_help_monitoring_text(),
|
||||
reply_markup=help_monitoring_keyboard(is_admin),
|
||||
)
|
||||
return
|
||||
if action == "menu:releases":
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
_help_releases_text(),
|
||||
reply_markup=help_releases_keyboard(is_admin),
|
||||
)
|
||||
return
|
||||
if action == "menu:subscriptions":
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
_help_subscriptions_text(),
|
||||
reply_markup=help_subscriptions_keyboard(is_admin),
|
||||
)
|
||||
return
|
||||
if action == "release_guide":
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
_help_release_guide_text(),
|
||||
reply_markup=help_result_keyboard("help:menu:releases", is_admin),
|
||||
)
|
||||
return
|
||||
if action == "week":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_digest(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
lambda: build_digest(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
return
|
||||
if action == "today":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_today_summary(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
lambda: build_today_summary(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
return
|
||||
if action == "top":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_top_issues(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
lambda: build_top_issues(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
return
|
||||
if action == "stale":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_stale_issues(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
return
|
||||
if action == "releases":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_release_summary(refresh=True),
|
||||
back_callback="help:menu:releases",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
return
|
||||
if action == "sync_status":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
build_sync_status,
|
||||
lambda: build_stale_issues(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
return
|
||||
if action.startswith("sub:"):
|
||||
await _handle_subscription_action(
|
||||
callback,
|
||||
action.split(":", 1)[1],
|
||||
"subscribe",
|
||||
_callback_sender_id(callback),
|
||||
reply_markup=help_result_keyboard("help:menu:subscriptions", is_admin),
|
||||
)
|
||||
return
|
||||
if action.startswith("unsub:"):
|
||||
await _handle_subscription_action(
|
||||
callback,
|
||||
action.split(":", 1)[1],
|
||||
"unsubscribe",
|
||||
_callback_sender_id(callback),
|
||||
reply_markup=help_result_keyboard("help:menu:subscriptions", is_admin),
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
@router.callback_query(F.data == "admin:open")
|
||||
@@ -767,6 +674,65 @@ async def cb_admin_actions(callback: CallbackQuery) -> None:
|
||||
reply_markup=admin_overview_keyboard(),
|
||||
)
|
||||
return
|
||||
if action == "menu:recipients":
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
_admin_recipients_text(),
|
||||
reply_markup=admin_recipients_keyboard(),
|
||||
)
|
||||
return
|
||||
if action in {"recipients:backend", "recipients:frontend"}:
|
||||
group_name = action.split(":", 1)[1]
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
_recipient_group_text(group_name),
|
||||
reply_markup=admin_recipient_group_keyboard(group_name),
|
||||
)
|
||||
return
|
||||
if action.startswith("recipients:list:"):
|
||||
group_name = action.rsplit(":", 1)[1]
|
||||
await _deliver_result(
|
||||
callback,
|
||||
await _recipients_text(group_name),
|
||||
back_callback=f"admin:recipients:{group_name}",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
)
|
||||
return
|
||||
if action.startswith("recipients:add:"):
|
||||
group_name = action.rsplit(":", 1)[1]
|
||||
admin_id = _callback_sender_id(callback)
|
||||
if admin_id is not None:
|
||||
PENDING_RECIPIENT_ACTIONS[admin_id] = ("add", group_name)
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
"\n".join(
|
||||
[
|
||||
f"<b>{escape(group_name.capitalize())}</b>",
|
||||
"",
|
||||
"Отправьте следующим сообщением Telegram ID, который нужно добавить.",
|
||||
]
|
||||
),
|
||||
reply_markup=admin_result_keyboard(f"admin:recipients:{group_name}"),
|
||||
)
|
||||
return
|
||||
if action.startswith("recipients:del:"):
|
||||
group_name = action.rsplit(":", 1)[1]
|
||||
admin_id = _callback_sender_id(callback)
|
||||
if admin_id is not None:
|
||||
PENDING_RECIPIENT_ACTIONS[admin_id] = ("del", group_name)
|
||||
await _show_callback_screen(
|
||||
callback,
|
||||
"\n".join(
|
||||
[
|
||||
f"<b>{escape(group_name.capitalize())}</b>",
|
||||
"",
|
||||
"Отправьте следующим сообщением Telegram ID, который нужно удалить.",
|
||||
]
|
||||
),
|
||||
reply_markup=admin_result_keyboard(f"admin:recipients:{group_name}"),
|
||||
)
|
||||
return
|
||||
if action == "admins":
|
||||
await _deliver_result(
|
||||
callback,
|
||||
@@ -813,19 +779,10 @@ async def cb_admin_actions(callback: CallbackQuery) -> None:
|
||||
admin_mode=True,
|
||||
)
|
||||
return
|
||||
if action == "releases":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_release_summary(refresh=True),
|
||||
back_callback="admin:menu:overview",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
)
|
||||
return
|
||||
if action == "today":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_today_summary(refresh=True),
|
||||
lambda: build_today_summary(refresh=False),
|
||||
back_callback="admin:menu:overview",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
@@ -834,7 +791,7 @@ async def cb_admin_actions(callback: CallbackQuery) -> None:
|
||||
if action == "week":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_digest(refresh=True),
|
||||
lambda: build_digest(refresh=False),
|
||||
back_callback="admin:menu:overview",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
@@ -843,7 +800,7 @@ async def cb_admin_actions(callback: CallbackQuery) -> None:
|
||||
if action == "top":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_top_issues(refresh=True),
|
||||
lambda: build_top_issues(refresh=False),
|
||||
back_callback="admin:menu:overview",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
@@ -852,7 +809,7 @@ async def cb_admin_actions(callback: CallbackQuery) -> None:
|
||||
if action == "stale":
|
||||
await _run_summary_action(
|
||||
callback,
|
||||
lambda: build_stale_issues(refresh=True),
|
||||
lambda: build_stale_issues(refresh=False),
|
||||
back_callback="admin:menu:overview",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
@@ -916,8 +873,8 @@ async def cmd_week(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_digest(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
await build_digest(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
|
||||
@@ -927,8 +884,8 @@ async def cmd_today(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_today_summary(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
await build_today_summary(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
|
||||
@@ -943,8 +900,8 @@ async def cmd_project(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_project_summary(args[1].strip(), refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
await build_project_summary(args[1].strip(), refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
|
||||
@@ -954,8 +911,8 @@ async def cmd_top(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_top_issues(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
await build_top_issues(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
|
||||
@@ -965,37 +922,20 @@ async def cmd_stale(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_stale_issues(refresh=True),
|
||||
back_callback="help:menu:monitoring",
|
||||
await build_stale_issues(refresh=False),
|
||||
back_callback="help:open",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
|
||||
|
||||
@router.message(Command("releases"))
|
||||
async def cmd_releases(message: Message) -> None:
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_release_summary(refresh=True),
|
||||
back_callback="help:menu:releases",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
await message.answer("Раздел релизов скрыт из упрощённого интерфейса.")
|
||||
|
||||
|
||||
@router.message(Command("release"))
|
||||
async def cmd_release(message: Message) -> None:
|
||||
args = message.text.split(maxsplit=1) if message.text else []
|
||||
if len(args) < 2:
|
||||
await message.answer("Использование: /release <version>")
|
||||
return
|
||||
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _deliver_result(
|
||||
message,
|
||||
await build_release_detail(args[1].strip(), refresh=True),
|
||||
back_callback="help:menu:releases",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
await message.answer("Раздел релизов скрыт из упрощённого интерфейса.")
|
||||
|
||||
|
||||
@router.message(Command("sync_status"))
|
||||
@@ -1090,38 +1030,57 @@ async def cmd_admin_del(message: Message) -> None:
|
||||
)
|
||||
|
||||
|
||||
@router.message(Command("subscribe"))
|
||||
async def cmd_subscribe(message: Message) -> None:
|
||||
args = message.text.split(maxsplit=1) if message.text else []
|
||||
if len(args) < 2:
|
||||
await message.answer("Использование: /subscribe <backend|frontend>")
|
||||
@router.message(F.text)
|
||||
async def cmd_pending_recipient_input(message: Message) -> None:
|
||||
user_id = _sender_id(message)
|
||||
if user_id is None or user_id not in PENDING_RECIPIENT_ACTIONS:
|
||||
return
|
||||
if not await _require_admin(message):
|
||||
return
|
||||
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _handle_subscription_action(
|
||||
raw_value = (message.text or "").strip()
|
||||
if raw_value.startswith("/"):
|
||||
return
|
||||
if not raw_value.lstrip("-").isdigit():
|
||||
await message.answer("Нужен числовой Telegram ID.")
|
||||
return
|
||||
|
||||
action, group_name = PENDING_RECIPIENT_ACTIONS.pop(user_id)
|
||||
target_id = int(raw_value)
|
||||
|
||||
if action == "add":
|
||||
await add_subscriber(group_name, target_id)
|
||||
text = (
|
||||
f"Telegram ID <code>{target_id}</code> добавлен в группу "
|
||||
f"<b>{escape(group_name)}</b>."
|
||||
)
|
||||
else:
|
||||
removed = await remove_subscriber(group_name, target_id)
|
||||
text = (
|
||||
f"Telegram ID <code>{target_id}</code> удалён из группы "
|
||||
f"<b>{escape(group_name)}</b>."
|
||||
if removed
|
||||
else f"Telegram ID <code>{target_id}</code> не найден в группе "
|
||||
f"<b>{escape(group_name)}</b>."
|
||||
)
|
||||
|
||||
await _deliver_result(
|
||||
message,
|
||||
args[1].strip().lower(),
|
||||
"subscribe",
|
||||
_sender_id(message),
|
||||
reply_markup=help_result_keyboard("help:menu:subscriptions", is_admin),
|
||||
text,
|
||||
back_callback=f"admin:recipients:{group_name}",
|
||||
is_admin=True,
|
||||
admin_mode=True,
|
||||
)
|
||||
|
||||
|
||||
@router.message(Command("subscribe"))
|
||||
async def cmd_subscribe(message: Message) -> None:
|
||||
await message.answer("Самоподписка отключена. Получателей настраивает администратор.")
|
||||
|
||||
|
||||
@router.message(Command("unsubscribe"))
|
||||
async def cmd_unsubscribe(message: Message) -> None:
|
||||
args = message.text.split(maxsplit=1) if message.text else []
|
||||
if len(args) < 2:
|
||||
await message.answer("Использование: /unsubscribe <backend|frontend>")
|
||||
return
|
||||
|
||||
is_admin = await _is_admin_user(_sender_id(message))
|
||||
await _handle_subscription_action(
|
||||
message,
|
||||
args[1].strip().lower(),
|
||||
"unsubscribe",
|
||||
_sender_id(message),
|
||||
reply_markup=help_result_keyboard("help:menu:subscriptions", is_admin),
|
||||
)
|
||||
await message.answer("Самоподписка отключена. Получателей настраивает администратор.")
|
||||
|
||||
|
||||
@router.message(Command("ownership"))
|
||||
|
||||
Reference in New Issue
Block a user