Files
PrimoGuardBot/bot/handlers/commands/settings/set_widget_cmd.py

176 lines
6.8 KiB
Python

from aiogram import Router, F, Bot
from aiogram.exceptions import TelegramAPIError, TelegramRetryAfter
from aiogram.filters import Command, CommandObject
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import StatesGroup, State
from aiogram.types import Message, CallbackQuery
from aiogram.utils.i18n import gettext as _
from bot.core.bots import BotInfo
from bot.filters import IsSuperAdmin
from bot.handlers.commands.settings.settings_cmd import settings_keyboard
from bot.templates import msg
from bot.utils import format_retry_time, status_clear
from configs import COMMANDS
from middleware.loggers import logger
__all__ = ("router",)
CMD: str = "set_widget".lower()
router: Router = Router(name=f"{CMD}_cmd_router")
class SetWidgetForm(StatesGroup):
"""Состояния FSM для изменения виджета (описания бота)."""
new_widget: State = State()
async def handle_set_widget(
new_widget: str,
message: Message | CallbackQuery,
state: FSMContext,
bot: Bot
) -> None:
"""
Устанавливает новое значение виджета (описания бота).
Args:
new_widget (str): Новый текст виджета.
message (Message | CallbackQuery): Объект сообщения или callback-запроса.
state (FSMContext): Контекст состояния FSM.
bot (Bot): Экземпляр текущего бота.
"""
# Проверка длины текста (Telegram API ограничивает description до 512 символов)
if len(new_widget) > 512:
await msg(
update=message,
text=_("❌ Виджет бота должен быть не более 512 символов. Текущая длина: {length}").format(
length=len(new_widget)
),
markup=settings_keyboard(),
state=state
)
return
try:
# Устанавливаем описание через Telegram API
await bot.set_my_description(description=new_widget)
# Сохраняем в BotInfo для локального использования
BotInfo.widget = new_widget
# Очищаем состояние FSM
await state.clear()
# Отправляем уведомление пользователю
await msg(
update=message,
text=_("✅ Виджет бота успешно изменён на: <b>{new_widget}</b>").format(
new_widget=new_widget
),
markup=settings_keyboard(),
state=state
)
logger.info(f"Виджет бота изменён на: {new_widget}")
except TelegramRetryAfter as e:
# Если запрос слишком частый
retry_text: str = format_retry_time(e.retry_after)
logger.warning(f"Превышен лимит запросов при смене виджета. Попробуйте через {retry_text}")
await msg(
update=message,
text=_("⚠️ Слишком частая смена виджета!\nПопробуйте снова через: <b>{retry_text}</b>").format(
retry_text=retry_text
),
markup=settings_keyboard(),
state=state
)
except TelegramAPIError as e:
# Ошибка Telegram API
logger.error(f"Ошибка Telegram API при изменении виджета: {e}")
await msg(
update=message,
text=_("❌ Ошибка Telegram API при изменении виджета: <pre>{error}</pre>").format(error=str(e)),
markup=settings_keyboard(),
state=state
)
except Exception as e:
# Непредвиденная ошибка
logger.error(f"Непредвиденная ошибка при изменении виджета: {e}")
await msg(
update=message,
text=_("❌ Непредвиденная ошибка при изменении виджета: <pre>{error}</pre>").format(error=str(e)),
markup=settings_keyboard(),
state=state
)
@router.callback_query(F.data.lower() == CMD, IsSuperAdmin())
@router.message(Command(*COMMANDS[CMD], prefix=BotInfo.prefix, ignore_case=True), IsSuperAdmin())
async def set_widget_cmd(
message: Message | CallbackQuery,
state: FSMContext,
bot: Bot,
command: CommandObject | None = None
) -> None:
"""
Обработчик команды /set_widget.
Поддерживает:
1. Немедленное изменение через аргумент команды (/set_widget TEXT).
2. Callback-запрос.
3. FSM ввод.
"""
# Получаем текущее значение виджета
current_widget: str = BotInfo.widget
# Вариант 1: пользователь ввёл аргумент сразу (/set_widget TEXT)
if command and command.args:
new_widget: str = command.args.strip()
if len(new_widget) > 512:
await msg(
update=message,
text=_("❌ Виджет не должен превышать 512 символов. Текущая длина: {length}").format(
length=len(new_widget)
),
markup=settings_keyboard(),
state=state
)
return
await handle_set_widget(new_widget, message, state, bot)
return
# Вариант 2: Callback query или пустая команда → запускаем FSM
await status_clear(update=message, state=state)
text: str = _(
"📝 <b>Смена виджета бота</b>\n\n"
"Текущий виджет: <i>{current}</i>\n\n"
"Пожалуйста, введите новый виджет для бота (максимум 512 символов):"
).format(current=current_widget)
await msg(update=message, text=text, markup=settings_keyboard(), state=state)
await state.set_state(SetWidgetForm.new_widget)
@router.message(SetWidgetForm.new_widget, IsSuperAdmin())
async def process_new_widget(
message: Message,
state: FSMContext,
bot: Bot
) -> None:
"""
Обрабатывает ввод нового текста виджета через FSM.
"""
new_widget: str = message.text.strip()
# Проверяем, что пользователь что-то ввёл
if not new_widget:
await message.answer(_("❌ Пожалуйста, введите корректный виджет."))
return
await handle_set_widget(new_widget, message, state, bot)
BotInfo.widget = new_widget