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 IsOwner 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( message=message, text=_("❌ Виджет бота должен быть не более 512 символов. Текущая длина: {length}").format( length=len(new_widget) ), markup=settings_keyboard(), ) return try: # Устанавливаем описание через Telegram API await bot.set_my_description(description=new_widget) # Сохраняем в BotInfo для локального использования BotInfo.widget = new_widget # Очищаем состояние FSM await state.clear() # Отправляем уведомление пользователю await msg( message=message, text=_("✅ Виджет бота успешно изменён на: {new_widget}").format( new_widget=new_widget ), markup=settings_keyboard(), ) 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( message=message, text=_("⚠️ Слишком частая смена виджета!\nПопробуйте снова через: {retry_text}").format( retry_text=retry_text ), markup=settings_keyboard(), ) except TelegramAPIError as e: # Ошибка Telegram API logger.error(f"Ошибка Telegram API при изменении виджета: {e}") await msg( message=message, text=_("❌ Ошибка Telegram API при изменении виджета:
{error}").format(error=str(e)),
markup=settings_keyboard(),
)
except Exception as e:
# Непредвиденная ошибка
logger.error(f"Непредвиденная ошибка при изменении виджета: {e}")
await msg(
message=message,
text=_("❌ Непредвиденная ошибка при изменении виджета: {error}").format(error=str(e)),
markup=settings_keyboard(),
)
@router.callback_query(F.data.lower() == CMD, IsOwner())
@router.message(Command(*COMMANDS[CMD], prefix=BotInfo.prefix, ignore_case=True), IsOwner())
async def settings_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(
message=message,
text=_("❌ Виджет не должен превышать 512 символов. Текущая длина: {length}").format(
length=len(new_widget)
),
markup=settings_keyboard(),
)
return
await handle_set_widget(new_widget, message, state, bot)
return
# Вариант 2: Callback query или пустая команда → запускаем FSM
await status_clear(message=message, state=state)
text: str = _(
"📝 Смена виджета бота\n\n"
"Текущий виджет: {current}\n\n"
"Пожалуйста, введите новый виджет для бота (максимум 512 символов):"
).format(current=current_widget)
await msg(message=message, text=text, markup=settings_keyboard())
await state.set_state(SetWidgetForm.new_widget)
@router.message(SetWidgetForm.new_widget, IsOwner())
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)