diff --git a/.env.example b/.env.example
index 054e2ab4..7b68373d 100644
--- a/.env.example
+++ b/.env.example
@@ -280,9 +280,6 @@ PAL24_REQUEST_TIMEOUT=30
ENABLE_LOGO_MODE=true
LOGO_FILE=vpn_logo.png
-# Режим главного меню (default - полное меню, text - только текст с базовыми кнопками)
-MAIN_MENU_MODE=default
-
# Скрыть блок с ссылкой подключения в разделе с информацией о подписке
HIDE_SUBSCRIPTION_LINK=false
diff --git a/README.md b/README.md
index 8877a1ed..ea6dbeb2 100644
--- a/README.md
+++ b/README.md
@@ -829,9 +829,6 @@ PAL24_REQUEST_TIMEOUT=30
ENABLE_LOGO_MODE=true
LOGO_FILE=vpn_logo.png
-# Режим главного меню (default - полное меню, text - только текст с базовыми кнопками)
-MAIN_MENU_MODE=default
-
# Скрыть блок с ссылкой подключения в разделе с информацией о подписке
HIDE_SUBSCRIPTION_LINK=false
diff --git a/app/config.py b/app/config.py
index a7e80bba..5dca0e74 100644
--- a/app/config.py
+++ b/app/config.py
@@ -227,7 +227,6 @@ class Settings(BaseSettings):
PAL24_SBP_BUTTON_TEXT: Optional[str] = None
PAL24_CARD_BUTTON_TEXT: Optional[str] = None
- MAIN_MENU_MODE: str = "default"
CONNECT_BUTTON_MODE: str = "guide"
MINIAPP_CUSTOM_URL: str = ""
MINIAPP_PURCHASE_URL: str = ""
@@ -294,29 +293,6 @@ class Settings(BaseSettings):
EXTERNAL_ADMIN_TOKEN: Optional[str] = None
EXTERNAL_ADMIN_TOKEN_BOT_ID: Optional[int] = None
- @field_validator('MAIN_MENU_MODE', mode='before')
- @classmethod
- def normalize_main_menu_mode(cls, value: Optional[str]) -> str:
- if not value:
- return "default"
-
- normalized = str(value).strip().lower()
- aliases = {
- "classic": "default",
- "default": "default",
- "full": "default",
- "standard": "default",
- "text": "text",
- "text_only": "text",
- "textual": "text",
- "minimal": "text",
- }
-
- mode = aliases.get(normalized, normalized)
- if mode not in {"default", "text"}:
- raise ValueError("MAIN_MENU_MODE must be one of: default, text")
- return mode
-
@field_validator('SERVER_STATUS_MODE', mode='before')
@classmethod
def normalize_server_status_mode(cls, value: Optional[str]) -> str:
@@ -601,19 +577,6 @@ class Settings(BaseSettings):
def is_notifications_enabled(self) -> bool:
return self.ENABLE_NOTIFICATIONS
-
- def get_main_menu_mode(self) -> str:
- return getattr(self, "MAIN_MENU_MODE", "default")
-
- def is_text_main_menu_mode(self) -> bool:
- return self.get_main_menu_mode() == "text"
-
- def get_main_menu_miniapp_url(self) -> Optional[str]:
- for candidate in [self.MINIAPP_CUSTOM_URL, self.MINIAPP_PURCHASE_URL]:
- value = (candidate or "").strip()
- if value:
- return value
- return None
def get_app_config_path(self) -> str:
if os.path.isabs(self.APP_CONFIG_PATH):
diff --git a/app/handlers/menu.py b/app/handlers/menu.py
index a1b6fe71..407ebe4f 100644
--- a/app/handlers/menu.py
+++ b/app/handlers/menu.py
@@ -168,14 +168,12 @@ async def show_main_menu(
db_user.telegram_id
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
await edit_or_answer_photo(
callback=callback,
@@ -193,28 +191,11 @@ async def show_main_menu(
custom_buttons=custom_buttons,
),
parse_mode="HTML",
- force_text=settings.is_text_main_menu_mode(),
)
if not skip_callback_answer:
await callback.answer()
-async def handle_profile_unavailable(callback: types.CallbackQuery) -> None:
- language = getattr(callback.from_user, "language_code", None) or settings.DEFAULT_LANGUAGE
- try:
- texts = get_texts(language)
- except Exception:
- texts = get_texts()
-
- await callback.answer(
- texts.t(
- "MENU_PROFILE_UNAVAILABLE",
- "❗️ Личный кабинет пока недоступен. Попробуйте позже.",
- ),
- show_alert=True,
- )
-
-
async def show_service_rules(
callback: types.CallbackQuery,
db_user: User,
@@ -899,14 +880,12 @@ async def handle_back_to_menu(
db_user.telegram_id
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
await edit_or_answer_photo(
callback=callback,
@@ -924,7 +903,6 @@ async def handle_back_to_menu(
custom_buttons=custom_buttons,
),
parse_mode="HTML",
- force_text=settings.is_text_main_menu_mode(),
)
await callback.answer()
@@ -1058,12 +1036,7 @@ def register_handlers(dp: Dispatcher):
handle_back_to_menu,
F.data == "back_to_menu"
)
-
- dp.callback_query.register(
- handle_profile_unavailable,
- F.data == "menu_profile_unavailable",
- )
-
+
dp.callback_query.register(
show_service_rules,
F.data == "menu_rules"
diff --git a/app/handlers/start.py b/app/handlers/start.py
index 2df57ece..39840ea1 100644
--- a/app/handlers/start.py
+++ b/app/handlers/start.py
@@ -335,14 +335,12 @@ async def cmd_start(message: types.Message, state: FSMContext, db: AsyncSession,
user.telegram_id
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
await message.answer(
menu_text,
@@ -759,14 +757,12 @@ async def complete_registration_from_callback(
and SupportSettingsService.is_moderator(existing_user.telegram_id)
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
try:
await callback.message.answer(
@@ -941,14 +937,12 @@ async def complete_registration_from_callback(
and SupportSettingsService.is_moderator(user.telegram_id)
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
try:
await callback.message.answer(
@@ -1017,14 +1011,12 @@ async def complete_registration(
and SupportSettingsService.is_moderator(existing_user.telegram_id)
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
try:
await message.answer(
@@ -1199,14 +1191,12 @@ async def complete_registration(
and SupportSettingsService.is_moderator(user.telegram_id)
)
- custom_buttons = []
- if not settings.is_text_main_menu_mode():
- custom_buttons = await MainMenuButtonService.get_buttons_for_user(
- db,
- is_admin=is_admin,
- has_active_subscription=has_active_subscription,
- subscription_is_active=subscription_is_active,
- )
+ custom_buttons = await MainMenuButtonService.get_buttons_for_user(
+ db,
+ is_admin=is_admin,
+ has_active_subscription=has_active_subscription,
+ subscription_is_active=subscription_is_active,
+ )
try:
await message.answer(
diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py
index be1c3149..62873873 100644
--- a/app/keyboards/inline.py
+++ b/app/keyboards/inline.py
@@ -168,59 +168,6 @@ def get_language_selection_keyboard(
return InlineKeyboardMarkup(inline_keyboard=buttons)
-def _build_text_main_menu_keyboard(
- language: str,
- texts,
- *,
- is_admin: bool,
- is_moderator: bool,
-) -> InlineKeyboardMarkup:
- profile_text = texts.t("MENU_PROFILE", "👤 Личный кабинет")
- miniapp_url = settings.get_main_menu_miniapp_url()
-
- if miniapp_url:
- profile_button = InlineKeyboardButton(
- text=profile_text,
- web_app=types.WebAppInfo(url=miniapp_url),
- )
- else:
- profile_button = InlineKeyboardButton(
- text=profile_text,
- callback_data="menu_profile_unavailable",
- )
-
- keyboard_rows: List[List[InlineKeyboardButton]] = [[profile_button]]
-
- if settings.is_language_selection_enabled():
- keyboard_rows.append([
- InlineKeyboardButton(text=texts.MENU_LANGUAGE, callback_data="menu_language")
- ])
-
- support_enabled = False
- try:
- from app.services.support_settings_service import SupportSettingsService
-
- support_enabled = SupportSettingsService.is_support_menu_enabled()
- except Exception:
- support_enabled = settings.SUPPORT_MENU_ENABLED
-
- if support_enabled:
- keyboard_rows.append([
- InlineKeyboardButton(text=texts.MENU_SUPPORT, callback_data="menu_support")
- ])
-
- if is_admin:
- keyboard_rows.append([
- InlineKeyboardButton(text=texts.MENU_ADMIN, callback_data="admin_panel")
- ])
- elif is_moderator:
- keyboard_rows.append([
- InlineKeyboardButton(text="🧑⚖️ Модерация", callback_data="moderator_panel")
- ])
-
- return InlineKeyboardMarkup(inline_keyboard=keyboard_rows)
-
-
def get_main_menu_keyboard(
language: str = DEFAULT_LANGUAGE,
is_admin: bool = False,
@@ -235,14 +182,6 @@ def get_main_menu_keyboard(
custom_buttons: Optional[list[InlineKeyboardButton]] = None,
) -> InlineKeyboardMarkup:
texts = get_texts(language)
-
- if settings.is_text_main_menu_mode():
- return _build_text_main_menu_keyboard(
- language,
- texts,
- is_admin=is_admin,
- is_moderator=is_moderator,
- )
if settings.DEBUG:
print(f"DEBUG KEYBOARD: language={language}, is_admin={is_admin}, has_had_paid={has_had_paid_subscription}, has_active={has_active_subscription}, sub_active={subscription_is_active}, balance={balance_kopeks}")
diff --git a/app/localization/locales/en.json b/app/localization/locales/en.json
index 7c88548c..600bc87c 100644
--- a/app/localization/locales/en.json
+++ b/app/localization/locales/en.json
@@ -397,8 +397,6 @@
"TRAFFIC_ALREADY_UNLIMITED": "⚠ You already have unlimited traffic",
"ADD_TRAFFIC_PROMPT": "📈 Add traffic to your subscription\n\nCurrent limit: {current_traffic}\nChoose extra traffic:",
"USER_NOT_FOUND": "❌ User not found",
- "MENU_PROFILE": "👤 Personal account",
- "MENU_PROFILE_UNAVAILABLE": "❗️ Personal account is not available yet. Please try again later.",
"MENU_LANGUAGE": "🌐 Language",
"SUBSCRIPTION_STATUS_EXPIRED": "Expired",
"SUBSCRIPTION_STATUS_TRIAL": "Trial",
diff --git a/app/localization/locales/ru.json b/app/localization/locales/ru.json
index 19f24a76..47d75c2f 100644
--- a/app/localization/locales/ru.json
+++ b/app/localization/locales/ru.json
@@ -256,8 +256,6 @@
"PUBLIC_OFFER_EMPTY_ALERT": "Публичная оферта ещё не заполнена.",
"PUBLIC_OFFER_HEADER": "📄 Публичная оферта",
"PUBLIC_OFFER_PAGE_INFO": "Страница {current} из {total}",
- "MENU_PROFILE": "👤 Личный кабинет",
- "MENU_PROFILE_UNAVAILABLE": "❗️ Личный кабинет пока недоступен. Попробуйте позже.",
"MENU_LANGUAGE": "🌐 Язык",
"MENU_PROMOCODE": "🎫 Промокод",
"MENU_REFERRALS": "🤝 Партнерка",
diff --git a/app/services/system_settings_service.py b/app/services/system_settings_service.py
index 02cf22ee..057f1fd1 100644
--- a/app/services/system_settings_service.py
+++ b/app/services/system_settings_service.py
@@ -227,7 +227,6 @@ class BotConfigurationService:
"ENABLE_LOGO_MODE": "INTERFACE_BRANDING",
"LOGO_FILE": "INTERFACE_BRANDING",
"HIDE_SUBSCRIPTION_LINK": "INTERFACE_SUBSCRIPTION",
- "MAIN_MENU_MODE": "INTERFACE",
"CONNECT_BUTTON_MODE": "CONNECT_BUTTON",
"MINIAPP_CUSTOM_URL": "CONNECT_BUTTON",
"APP_CONFIG_PATH": "ADDITIONAL",
@@ -322,10 +321,6 @@ class BotConfigurationService:
ChoiceOption("link", "🔗 Прямая ссылка"),
ChoiceOption("happ_cryptolink", "🪙 Happ CryptoLink"),
],
- "MAIN_MENU_MODE": [
- ChoiceOption("default", "📋 Полное меню"),
- ChoiceOption("text", "📝 Текстовое меню"),
- ],
"SERVER_STATUS_MODE": [
ChoiceOption("disabled", "🚫 Отключено"),
ChoiceOption("external_link", "🌐 Внешняя ссылка"),
diff --git a/app/utils/photo_message.py b/app/utils/photo_message.py
index f7e65752..dd40d7e6 100644
--- a/app/utils/photo_message.py
+++ b/app/utils/photo_message.py
@@ -69,12 +69,10 @@ async def edit_or_answer_photo(
caption: str,
keyboard: types.InlineKeyboardMarkup,
parse_mode: str | None = "HTML",
- *,
- force_text: bool = False,
) -> None:
resolved_parse_mode = parse_mode or "HTML"
- # Если режим логотипа выключен или требуется текстовое сообщение — работаем текстом
- if force_text or not settings.ENABLE_LOGO_MODE:
+ # Если режим логотипа выключен — работаем текстом
+ if not settings.ENABLE_LOGO_MODE:
try:
if callback.message.photo:
await callback.message.delete()
@@ -86,10 +84,7 @@ async def edit_or_answer_photo(
parse_mode=resolved_parse_mode,
)
except TelegramBadRequest as error:
- try:
- await callback.message.delete()
- except Exception:
- pass
+ await callback.message.delete()
await _answer_text(callback, caption, keyboard, resolved_parse_mode, error)
return