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)