diff --git a/bot/handlers/commands/settings/set_name_cmd.py b/bot/handlers/commands/settings/set_name_cmd.py new file mode 100644 index 0000000..1cb5b99 --- /dev/null +++ b/bot/handlers/commands/settings/set_name_cmd.py @@ -0,0 +1,157 @@ +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 configs import COMMANDS +from middleware.loggers import logger + +__all__ = ("router",) +CMD: str = "set_name".lower() +router: Router = Router(name=f"{CMD}_cmd_router") + + +class SetNameForm(StatesGroup): + new_name: State = State() + + +def format_retry_time(retry_after: int) -> str: + """Форматирование времени повторной попытки в читаемом виде""" + hours, remainder = divmod(retry_after, 3600) + minutes, seconds = divmod(remainder, 60) + + if hours > 0: + return f"{hours} часов, {minutes} минут, {seconds} секунд" + elif minutes > 0: + return f"{minutes} минут, {seconds} секунд" + else: + return f"{seconds} секунд" + + +async def handle_set_name( + new_name: str, + message: Message | CallbackQuery, + state: FSMContext, + bot: Bot +) -> None: + """ + Установка имени бота с проверкой длины, обработкой перегрузки и логированием + """ + if len(new_name) > 64: + await msg( + update=message, + text=_("❌ Имя бота должно быть не более 64 символов. Текущая длина: {length}").format( + length=len(new_name) + ), + markup=settings_keyboard(), + state=state + ) + return + + try: + await bot.set_my_name(new_name) + BotInfo.first_name = new_name + await state.clear() + await msg( + update=message, + text=_("✅ Имя бота успешно изменено на: {new_name}").format(new_name=new_name), + markup=settings_keyboard(), + state=state + ) + logger.info(f"Имя бота изменено на: {new_name}") + + 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: + 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
+):
+ """
+ Обработчик команды /set_name с поддержкой:
+ 1. Immediate установки через аргумент команды
+ 2. Callback query
+ 3. FSM ввод
+ """
+ current_name = getattr(BotInfo, "first_name", "") or _("Не установлено")
+
+ # Immediate установка через аргумент команды
+ if command and command.args:
+ new_name = command.args.strip()
+ if len(new_name) > 64:
+ await msg(
+ update=message,
+ text=_("❌ Имя не должно превышать 64 символа. Текущая длина: {length}").format(
+ length=len(new_name)
+ ),
+ markup=settings_keyboard(),
+ state=state
+ )
+ return
+ await handle_set_name(new_name, message, state, bot)
+ return
+
+ # Для callback query или пустой команды — показываем текущее имя и запускаем FSM
+ await state.clear()
+ if isinstance(message, CallbackQuery):
+ await message.answer()
+ text: str = _(
+ "🤖 Смена имени бота\n\n"
+ "Текущее имя: {current}\n\n"
+ "Пожалуйста, введите новое имя для бота (максимум 64 символа):"
+ ).format(current=current_name)
+ await msg(update=message, text=text, markup=settings_keyboard(), state=state)
+ await state.set_state(SetNameForm.new_name)
+
+
+@router.message(SetNameForm.new_name, IsOwner())
+async def process_new_name(message: Message, state: FSMContext, bot: Bot):
+ """
+ Обработка ввода нового имени через FSM
+ """
+ new_name: str = message.text.strip()
+
+ if not new_name:
+ await message.answer(_("❌ Пожалуйста, введите корректное имя."))
+ return
+
+ await handle_set_name(new_name, message, state, bot)