diff --git a/app/handlers/admin/main.py b/app/handlers/admin/main.py
index fbc9bf13..c18aad2c 100644
--- a/app/handlers/admin/main.py
+++ b/app/handlers/admin/main.py
@@ -2,6 +2,7 @@ import logging
from aiogram import Dispatcher, types, F
from aiogram.filters import Command
from sqlalchemy.ext.asyncio import AsyncSession
+from aiogram.exceptions import TelegramBadRequest
from app.config import settings
from app.database.models import User
@@ -26,6 +27,55 @@ from app.database.crud.ticket import TicketCRUD
logger = logging.getLogger(__name__)
+async def safe_edit_message(
+ callback: types.CallbackQuery,
+ text: str,
+ reply_markup: types.InlineKeyboardMarkup,
+ parse_mode: str = "HTML"
+):
+ """
+ Безопасное редактирование сообщений, которое корректно обрабатывает
+ как обычные текстовые сообщения, так и сообщения с фото
+ """
+ if callback.message.photo:
+ try:
+ await callback.message.edit_caption(
+ caption=text,
+ reply_markup=reply_markup,
+ parse_mode=parse_mode
+ )
+ except TelegramBadRequest as e:
+ if "there is no text in the message to edit" in str(e) or "message is not modified" in str(e):
+ try:
+ await callback.message.delete()
+ await callback.message.answer(
+ text=text,
+ reply_markup=reply_markup,
+ parse_mode=parse_mode
+ )
+ except Exception:
+ try:
+ await callback.message.edit_text(
+ text,
+ reply_markup=reply_markup,
+ parse_mode=parse_mode
+ )
+ except TelegramBadRequest:
+ await callback.message.answer(
+ text=text,
+ reply_markup=reply_markup,
+ parse_mode=parse_mode
+ )
+ else:
+ raise
+ else:
+ await callback.message.edit_text(
+ text,
+ reply_markup=reply_markup,
+ parse_mode=parse_mode
+ )
+
+
@admin_required
@error_handler
async def show_admin_panel(
@@ -56,9 +106,11 @@ async def show_admin_panel(
except Exception as e:
logger.error(f"Не удалось получить статистику Remnawave для админ-панели: {e}")
- await callback.message.edit_text(
+ await safe_edit_message(
+ callback,
admin_text,
- reply_markup=get_admin_main_keyboard(db_user.language)
+ get_admin_main_keyboard(db_user.language),
+ "HTML"
)
await callback.answer()
@@ -71,12 +123,15 @@ async def show_users_submenu(
db: AsyncSession
):
texts = get_texts(db_user.language)
+
+ message_text = (texts.t("ADMIN_USERS_SUBMENU_TITLE", "👥 **Управление пользователями и подписками**\n\n") +
+ texts.t("ADMIN_SUBMENU_SELECT_SECTION", "Выберите нужный раздел:"))
- await callback.message.edit_text(
- texts.t("ADMIN_USERS_SUBMENU_TITLE", "👥 **Управление пользователями и подписками**\n\n") +
- texts.t("ADMIN_SUBMENU_SELECT_SECTION", "Выберите нужный раздел:"),
- reply_markup=get_admin_users_submenu_keyboard(db_user.language),
- parse_mode="Markdown"
+ await safe_edit_message(
+ callback,
+ message_text,
+ get_admin_users_submenu_keyboard(db_user.language),
+ "Markdown"
)
await callback.answer()
@@ -89,12 +144,15 @@ async def show_promo_submenu(
db: AsyncSession
):
texts = get_texts(db_user.language)
+
+ message_text = (texts.t("ADMIN_PROMO_SUBMENU_TITLE", "💰 **Промокоды и статистика**\n\n") +
+ texts.t("ADMIN_SUBMENU_SELECT_SECTION", "Выберите нужный раздел:"))
- await callback.message.edit_text(
- texts.t("ADMIN_PROMO_SUBMENU_TITLE", "💰 **Промокоды и статистика**\n\n") +
- texts.t("ADMIN_SUBMENU_SELECT_SECTION", "Выберите нужный раздел:"),
- reply_markup=get_admin_promo_submenu_keyboard(db_user.language),
- parse_mode="Markdown"
+ await safe_edit_message(
+ callback,
+ message_text,
+ get_admin_promo_submenu_keyboard(db_user.language),
+ "Markdown"
)
await callback.answer()
@@ -107,12 +165,15 @@ async def show_communications_submenu(
db: AsyncSession
):
texts = get_texts(db_user.language)
+
+ message_text = (texts.t("ADMIN_COMMUNICATIONS_SUBMENU_TITLE", "📨 **Коммуникации**\n\n") +
+ texts.t("ADMIN_COMMUNICATIONS_SUBMENU_DESCRIPTION", "Управление рассылками и текстами интерфейса:"))
- await callback.message.edit_text(
- texts.t("ADMIN_COMMUNICATIONS_SUBMENU_TITLE", "📨 **Коммуникации**\n\n") +
- texts.t("ADMIN_COMMUNICATIONS_SUBMENU_DESCRIPTION", "Управление рассылками и текстами интерфейса:"),
- reply_markup=get_admin_communications_submenu_keyboard(db_user.language),
- parse_mode="Markdown"
+ await safe_edit_message(
+ callback,
+ message_text,
+ get_admin_communications_submenu_keyboard(db_user.language),
+ "Markdown"
)
await callback.answer()
@@ -135,14 +196,18 @@ async def show_support_submenu(
[InlineKeyboardButton(text=texts.t("ADMIN_SUPPORT_TICKETS", "🎫 Тикеты поддержки"), callback_data="admin_tickets")],
[InlineKeyboardButton(text=texts.BACK, callback_data="back_to_menu")]
])
- await callback.message.edit_text(
- texts.t("ADMIN_SUPPORT_SUBMENU_TITLE", "🛟 **Поддержка**\n\n") + (
- texts.t("ADMIN_SUPPORT_SUBMENU_DESCRIPTION_MODERATOR", "Доступ к тикетам.")
- if is_moderator_only
- else texts.t("ADMIN_SUPPORT_SUBMENU_DESCRIPTION", "Управление тикетами и настройками поддержки:")
- ),
- reply_markup=kb,
- parse_mode="Markdown"
+
+ message_text = (texts.t("ADMIN_SUPPORT_SUBMENU_TITLE", "🛟 **Поддержка**\n\n") + (
+ texts.t("ADMIN_SUPPORT_SUBMENU_DESCRIPTION_MODERATOR", "Доступ к тикетам.")
+ if is_moderator_only
+ else texts.t("ADMIN_SUPPORT_SUBMENU_DESCRIPTION", "Управление тикетами и настройками поддержки:")
+ ))
+
+ await safe_edit_message(
+ callback,
+ message_text,
+ kb,
+ "Markdown"
)
await callback.answer()
@@ -158,11 +223,15 @@ async def show_moderator_panel(
[InlineKeyboardButton(text=texts.t("ADMIN_SUPPORT_TICKETS", "🎫 Тикеты поддержки"), callback_data="admin_tickets")],
[InlineKeyboardButton(text=texts.t("BACK_TO_MAIN_MENU_BUTTON", "⬅️ В главное меню"), callback_data="back_to_menu")]
])
- await callback.message.edit_text(
- texts.t("ADMIN_SUPPORT_MODERATION_TITLE", "🧑⚖️ Модерация поддержки") + "\n\n" +
- texts.t("ADMIN_SUPPORT_MODERATION_DESCRIPTION", "Доступ к тикетам поддержки."),
- parse_mode="HTML",
- reply_markup=kb
+
+ message_text = (texts.t("ADMIN_SUPPORT_MODERATION_TITLE", "🧑⚖️ Модерация поддержки") + "\n\n" +
+ texts.t("ADMIN_SUPPORT_MODERATION_DESCRIPTION", "Доступ к тикетам поддержки."))
+
+ await safe_edit_message(
+ callback,
+ message_text,
+ kb,
+ "HTML"
)
await callback.answer()
@@ -235,7 +304,12 @@ async def show_support_audit(
kb_rows.append([InlineKeyboardButton(text=texts.BACK, callback_data="admin_submenu_support")])
kb = InlineKeyboardMarkup(inline_keyboard=kb_rows)
- await callback.message.edit_text("\n".join(lines), parse_mode="HTML", reply_markup=kb)
+ await safe_edit_message(
+ callback,
+ "\n".join(lines),
+ kb,
+ "HTML"
+ )
await callback.answer()
@@ -247,12 +321,15 @@ async def show_settings_submenu(
db: AsyncSession
):
texts = get_texts(db_user.language)
+
+ message_text = (texts.t("ADMIN_SETTINGS_SUBMENU_TITLE", "⚙️ **Настройки системы**\n\n") +
+ texts.t("ADMIN_SETTINGS_SUBMENU_DESCRIPTION", "Управление Remnawave, мониторингом и другими настройками:"))
- await callback.message.edit_text(
- texts.t("ADMIN_SETTINGS_SUBMENU_TITLE", "⚙️ **Настройки системы**\n\n") +
- texts.t("ADMIN_SETTINGS_SUBMENU_DESCRIPTION", "Управление Remnawave, мониторингом и другими настройками:"),
- reply_markup=get_admin_settings_submenu_keyboard(db_user.language),
- parse_mode="Markdown"
+ await safe_edit_message(
+ callback,
+ message_text,
+ get_admin_settings_submenu_keyboard(db_user.language),
+ "Markdown"
)
await callback.answer()
@@ -265,12 +342,15 @@ async def show_system_submenu(
db: AsyncSession
):
texts = get_texts(db_user.language)
+
+ message_text = (texts.t("ADMIN_SYSTEM_SUBMENU_TITLE", "🛠️ **Системные функции**\n\n") +
+ texts.t("ADMIN_SYSTEM_SUBMENU_DESCRIPTION", "Отчеты, обновления, логи, резервные копии и системные операции:"))
- await callback.message.edit_text(
- texts.t("ADMIN_SYSTEM_SUBMENU_TITLE", "🛠️ **Системные функции**\n\n") +
- texts.t("ADMIN_SYSTEM_SUBMENU_DESCRIPTION", "Отчеты, обновления, логи, резервные копии и системные операции:"),
- reply_markup=get_admin_system_submenu_keyboard(db_user.language),
- parse_mode="Markdown"
+ await safe_edit_message(
+ callback,
+ message_text,
+ get_admin_system_submenu_keyboard(db_user.language),
+ "Markdown"
)
await callback.answer()
@@ -449,4 +529,4 @@ def register_handlers(dp: Dispatcher):
dp.message.register(
admin_commands_help,
Command("admin_help")
- )
\ No newline at end of file
+ )