From 8b8d86542d366602320985c8f804348673d94c61 Mon Sep 17 00:00:00 2001 From: Verum Date: Mon, 23 Feb 2026 14:21:11 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B2=D0=B8=D0=B4=D0=B6=D0=B5=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commands/settings/set_widget_cmd.py | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 bot/handlers/commands/settings/set_widget_cmd.py diff --git a/bot/handlers/commands/settings/set_widget_cmd.py b/bot/handlers/commands/settings/set_widget_cmd.py new file mode 100644 index 0000000..3959c88 --- /dev/null +++ b/bot/handlers/commands/settings/set_widget_cmd.py @@ -0,0 +1,174 @@ +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( + 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=_("✅ Виджет бота успешно изменён на: {new_widget}").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Попробуйте снова через: {retry_text}").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 при изменении виджета:
{error}
").format(error=str(e)), + markup=settings_keyboard(), + state=state + ) + + except Exception as e: + # Непредвиденная ошибка + logger.error(f"Непредвиденная ошибка при изменении виджета: {e}") + await msg( + update=message, + text=_("❌ Непредвиденная ошибка при изменении виджета:
{error}
").format(error=str(e)), + markup=settings_keyboard(), + state=state + ) + + +@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.short_description + + # Вариант 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 = _( + "📝 Смена виджета бота\n\n" + "Текущий виджет: {current}\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, 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)