diff --git a/.env.example b/.env.example index 77f05953..a15da1fc 100644 --- a/.env.example +++ b/.env.example @@ -290,6 +290,7 @@ CONNECT_BUTTON_MODE=guide # URL для режима miniapp_custom (обязателен при CONNECT_BUTTON_MODE=miniapp_custom) MINIAPP_CUSTOM_URL= +MINIAPP_SUBSCRIPTION_PURCHASE_URL= MINIAPP_SERVICE_NAME_EN=Bedolaga VPN MINIAPP_SERVICE_NAME_RU=Bedolaga VPN MINIAPP_SERVICE_DESCRIPTION_EN=Secure & Fast Connection diff --git a/README.md b/README.md index c1fdb9f1..c97c466d 100644 --- a/README.md +++ b/README.md @@ -535,6 +535,7 @@ CONNECT_BUTTON_MODE=guide # URL для режима miniapp_custom (обязателен при CONNECT_BUTTON_MODE=miniapp_custom) MINIAPP_CUSTOM_URL= +MINIAPP_SUBSCRIPTION_PURCHASE_URL= MINIAPP_SERVICE_NAME_EN=Bedolaga VPN MINIAPP_SERVICE_NAME_RU=Bedolaga VPN MINIAPP_SERVICE_DESCRIPTION_EN=Secure & Fast Connection diff --git a/app/config.py b/app/config.py index 773f4f45..7ab0198b 100644 --- a/app/config.py +++ b/app/config.py @@ -213,6 +213,7 @@ class Settings(BaseSettings): CONNECT_BUTTON_MODE: str = "guide" MINIAPP_CUSTOM_URL: str = "" + MINIAPP_SUBSCRIPTION_PURCHASE_URL: str = "" MINIAPP_SERVICE_NAME_EN: str = "Bedolaga VPN" MINIAPP_SERVICE_NAME_RU: str = "Bedolaga VPN" MINIAPP_SERVICE_DESCRIPTION_EN: str = "Secure & Fast Connection" @@ -550,6 +551,13 @@ class Settings(BaseSettings): "ru": desc_ru, }, } + + def get_miniapp_purchase_url(self) -> Optional[str]: + value = getattr(self, "MINIAPP_SUBSCRIPTION_PURCHASE_URL", "") + if value is None: + return None + purchase_url = str(value).strip() + return purchase_url or None def get_app_config_cache_ttl(self) -> int: return self.APP_CONFIG_CACHE_TTL diff --git a/app/webapi/routes/miniapp.py b/app/webapi/routes/miniapp.py index 64bc7bd4..eded3fa6 100644 --- a/app/webapi/routes/miniapp.py +++ b/app/webapi/routes/miniapp.py @@ -24,6 +24,8 @@ from app.utils.telegram_webapp import ( from ..dependencies import get_db_session from ..schemas.miniapp import ( + MiniAppBranding, + MiniAppConfigResponse, MiniAppConnectedServer, MiniAppDevice, MiniAppPromoGroup, @@ -258,6 +260,16 @@ async def _load_subscription_links( return payload +@router.get("/config", response_model=MiniAppConfigResponse) +async def get_miniapp_config() -> MiniAppConfigResponse: + branding_data = settings.get_miniapp_branding() + branding = MiniAppBranding(**branding_data) if branding_data else None + return MiniAppConfigResponse( + branding=branding, + subscription_purchase_url=settings.get_miniapp_purchase_url(), + ) + + @router.post("/subscription", response_model=MiniAppSubscriptionResponse) async def get_subscription_details( payload: MiniAppSubscriptionRequest, @@ -383,6 +395,7 @@ async def get_subscription_details( else None, subscription_type="trial" if subscription.is_trial else "paid", autopay_enabled=bool(subscription.autopay_enabled), + subscription_purchase_url=settings.get_miniapp_purchase_url(), branding=settings.get_miniapp_branding(), ) diff --git a/app/webapi/schemas/miniapp.py b/app/webapi/schemas/miniapp.py index a0d5cb1a..8effe4bb 100644 --- a/app/webapi/schemas/miniapp.py +++ b/app/webapi/schemas/miniapp.py @@ -11,6 +11,11 @@ class MiniAppBranding(BaseModel): service_description: Dict[str, Optional[str]] = Field(default_factory=dict) +class MiniAppConfigResponse(BaseModel): + branding: Optional[MiniAppBranding] = None + subscription_purchase_url: Optional[str] = None + + class MiniAppSubscriptionRequest(BaseModel): init_data: str = Field(..., alias="initData") @@ -74,6 +79,7 @@ class MiniAppSubscriptionResponse(BaseModel): user: MiniAppSubscriptionUser subscription_url: Optional[str] = None subscription_crypto_link: Optional[str] = None + subscription_purchase_url: Optional[str] = None links: List[str] = Field(default_factory=list) ss_conf_links: Dict[str, str] = Field(default_factory=dict) connected_squads: List[str] = Field(default_factory=list) diff --git a/miniapp/index.html b/miniapp/index.html index 27253b84..9e1fed9b 100644 --- a/miniapp/index.html +++ b/miniapp/index.html @@ -314,6 +314,16 @@ line-height: 1.6; } + .error-actions { + margin-top: 24px; + display: flex; + justify-content: center; + } + + .error-actions .btn { + min-width: 200px; + } + /* Cards */ .card { background: var(--bg-secondary); @@ -1186,6 +1196,9 @@