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)