From 57db7532189de7a90b68fdc080dc748d313bc270 Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 25 Sep 2025 11:52:47 +0300 Subject: [PATCH] Support Happ redirect button for cryptolink mode --- app/config.py | 5 +++++ app/handlers/subscription.py | 18 ++++++++++++++++-- app/keyboards/inline.py | 22 ++++++++++++++++------ app/utils/subscription_utils.py | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/app/config.py b/app/config.py index 6d16054c..9de0a3a0 100644 --- a/app/config.py +++ b/app/config.py @@ -210,6 +210,7 @@ class Settings(BaseSettings): CONNECT_BUTTON_MODE: str = "guide" MINIAPP_CUSTOM_URL: str = "" CONNECT_BUTTON_HAPP_DOWNLOAD_ENABLED: bool = False + HAPP_CRYPTOLINK_REDIRECT_TEMPLATE: Optional[str] = None HAPP_DOWNLOAD_LINK_IOS: Optional[str] = None HAPP_DOWNLOAD_LINK_ANDROID: Optional[str] = None HAPP_DOWNLOAD_LINK_MACOS: Optional[str] = None @@ -555,6 +556,10 @@ class Settings(BaseSettings): def is_happ_download_button_enabled(self) -> bool: return self.is_happ_cryptolink_mode() and self.CONNECT_BUTTON_HAPP_DOWNLOAD_ENABLED + def get_happ_cryptolink_redirect_template(self) -> Optional[str]: + template = (self.HAPP_CRYPTOLINK_REDIRECT_TEMPLATE or "").strip() + return template or None + def get_happ_download_link(self, platform: str) -> Optional[str]: platform_key = platform.lower() diff --git a/app/handlers/subscription.py b/app/handlers/subscription.py index e6dab937..97b91d0b 100644 --- a/app/handlers/subscription.py +++ b/app/handlers/subscription.py @@ -64,7 +64,10 @@ from app.utils.pricing_utils import ( format_period_description, ) from app.utils.pagination import paginate_list -from app.utils.subscription_utils import get_display_subscription_link +from app.utils.subscription_utils import ( + get_display_subscription_link, + get_happ_cryptolink_redirect_link, +) logger = logging.getLogger(__name__) @@ -4611,6 +4614,7 @@ async def handle_open_subscription_link( return if settings.is_happ_cryptolink_mode(): + redirect_link = get_happ_cryptolink_redirect_link(subscription_link) happ_message = ( texts.t( "SUBSCRIPTION_HAPP_OPEN_TITLE", @@ -4628,7 +4632,17 @@ async def handle_open_subscription_link( ).format(subscription_link=subscription_link) ) - keyboard = get_happ_cryptolink_keyboard(subscription_link, db_user.language) + if redirect_link: + happ_message += "\n\n" + texts.t( + "SUBSCRIPTION_HAPP_OPEN_BUTTON_HINT", + "▶️ Нажмите кнопку \"Подключиться\" ниже, чтобы открыть Happ и добавить подписку автоматически.", + ) + + keyboard = get_happ_cryptolink_keyboard( + subscription_link, + db_user.language, + redirect_link=redirect_link, + ) await callback.message.answer( happ_message, diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py index 01e79ce4..adb4462f 100644 --- a/app/keyboards/inline.py +++ b/app/keyboards/inline.py @@ -9,7 +9,10 @@ from app.config import settings, PERIOD_PRICES, TRAFFIC_PRICES from app.localization.loader import DEFAULT_LANGUAGE from app.localization.texts import get_texts from app.utils.pricing_utils import format_period_description -from app.utils.subscription_utils import get_display_subscription_link +from app.utils.subscription_utils import ( + get_display_subscription_link, + get_happ_cryptolink_redirect_link, +) import logging logger = logging.getLogger(__name__) @@ -257,15 +260,22 @@ def get_happ_download_button_row(texts) -> Optional[List[InlineKeyboardButton]]: def get_happ_cryptolink_keyboard( subscription_link: str, language: str = DEFAULT_LANGUAGE, + redirect_link: Optional[str] = None, ) -> InlineKeyboardMarkup: texts = get_texts(language) - buttons = [ - [ + final_redirect_link = redirect_link or get_happ_cryptolink_redirect_link(subscription_link) + + buttons: List[List[InlineKeyboardButton]] = [] + + if final_redirect_link: + buttons.append([ InlineKeyboardButton( text=texts.t("CONNECT_BUTTON", "🔗 Подключиться"), - url=subscription_link, + url=final_redirect_link, ) - ], + ]) + + buttons.extend([ [ InlineKeyboardButton( text=texts.t("HAPP_PLATFORM_IOS", "🍎 iOS"), @@ -296,7 +306,7 @@ def get_happ_cryptolink_keyboard( callback_data="back_to_menu", ) ], - ] + ]) return InlineKeyboardMarkup(inline_keyboard=buttons) diff --git a/app/utils/subscription_utils.py b/app/utils/subscription_utils.py index 62db4142..a2741b5d 100644 --- a/app/utils/subscription_utils.py +++ b/app/utils/subscription_utils.py @@ -1,6 +1,7 @@ import logging from datetime import datetime from typing import Optional +from urllib.parse import quote from sqlalchemy import select, delete, func from sqlalchemy.ext.asyncio import AsyncSession from app.database.models import Subscription, User @@ -109,3 +110,34 @@ def get_display_subscription_link(subscription: Optional[Subscription]) -> Optio return crypto_link or base_link return base_link + + +def get_happ_cryptolink_redirect_link(subscription_link: Optional[str]) -> Optional[str]: + if not subscription_link: + return None + + template = settings.get_happ_cryptolink_redirect_template() + if not template: + return None + + encoded_link = quote(subscription_link, safe="") + replacements = { + "{subscription_link}": encoded_link, + "{link}": encoded_link, + "{subscription_link_raw}": subscription_link, + "{link_raw}": subscription_link, + } + + replaced = False + for placeholder, value in replacements.items(): + if placeholder in template: + template = template.replace(placeholder, value) + replaced = True + + if replaced: + return template + + if template.endswith(("=", "?", "&")): + return f"{template}{encoded_link}" + + return f"{template}{encoded_link}"