From e76558d68bb10c6e70c191c59ed02b41ce2a6a14 Mon Sep 17 00:00:00 2001 From: 3252a8 <3252a8@proton.me> Date: Mon, 18 May 2026 20:30:30 +0300 Subject: [PATCH] refactor: move stars presentation into module --- .../bot/app/web/admin_settings_manifest.py | 1 - backend/bot/payment_providers/stars.py | 52 ++++++++++++++++++- backend/config/settings.py | 6 --- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/backend/bot/app/web/admin_settings_manifest.py b/backend/bot/app/web/admin_settings_manifest.py index 2eb495f..e856440 100644 --- a/backend/bot/app/web/admin_settings_manifest.py +++ b/backend/bot/app/web/admin_settings_manifest.py @@ -197,7 +197,6 @@ SETTINGS_MANIFEST: List[SettingField] = [ # ─── Payment providers (toggles) ─────────────────────────────── # Common SettingField("STARS_ENABLED", "bool", "payments", "Telegram Stars", subsection="Общие"), - *_payment_presentation_fields("STARS", "Telegram Stars", default_icon="Sparkles"), SettingField( "PAYMENT_METHODS_ORDER", "string", diff --git a/backend/bot/payment_providers/stars.py b/backend/bot/payment_providers/stars.py index 08e2d08..c155e4e 100644 --- a/backend/bot/payment_providers/stars.py +++ b/backend/bot/payment_providers/stars.py @@ -4,6 +4,7 @@ from typing import Optional from aiogram import Bot, F, Router, types from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, LabeledPrice from aiohttp import web +from pydantic_settings import SettingsConfigDict from sqlalchemy.ext.asyncio import AsyncSession from bot.keyboards.inline.user_keyboards import payment_methods_back_callback @@ -15,8 +16,11 @@ from db.dal import payment_dal from .base import ( PaymentProviderSpec, + ProviderEnvConfig, + ProviderManifestField, ServiceFactoryContext, WebAppPaymentContext, + provider_env_file, ) from .shared import ( PaymentSuccessRequest, @@ -37,6 +41,22 @@ from .shared import ( ) +class StarsPresentation(ProviderEnvConfig): + model_config = SettingsConfigDict( + env_file=provider_env_file(), + env_file_encoding="utf-8", + env_prefix="PAYMENT_STARS_", + extra="ignore", + ) + + WEBAPP_LABEL_RU: Optional[str] = None + WEBAPP_LABEL_EN: Optional[str] = None + WEBAPP_ICON: Optional[str] = None + TELEGRAM_LABEL_RU: Optional[str] = None + TELEGRAM_LABEL_EN: Optional[str] = None + TELEGRAM_EMOJI: Optional[str] = None + + class StarsService: def __init__( self, @@ -349,6 +369,31 @@ async def create_webapp_payment(ctx: WebAppPaymentContext) -> web.Response: return payment_failed("Failed to create invoice") +_PRESENTATION_MANIFEST = tuple( + ProviderManifestField( + key=key, type=type_, label=label, description=description, + placeholder=placeholder, subsection="Telegram Stars", + target="presentation", attr=attr, + ) + for key, type_, label, description, placeholder, attr in ( + ("PAYMENT_STARS_WEBAPP_LABEL_RU", "string", "WebApp button text (RU)", + "Custom Russian text shown in the Web App payment method button.", "", "WEBAPP_LABEL_RU"), + ("PAYMENT_STARS_WEBAPP_LABEL_EN", "string", "WebApp button text (EN)", + "Custom English text shown in the Web App payment method button.", "", "WEBAPP_LABEL_EN"), + ("PAYMENT_STARS_WEBAPP_ICON", "icon", "WebApp button icon", + "Lucide icon name rendered inside the Web App payment method button.", + "Sparkles", "WEBAPP_ICON"), + ("PAYMENT_STARS_TELEGRAM_LABEL_RU", "string", "Telegram button text (RU)", + "Custom Russian text shown in Telegram bot payment buttons.", "", "TELEGRAM_LABEL_RU"), + ("PAYMENT_STARS_TELEGRAM_LABEL_EN", "string", "Telegram button text (EN)", + "Custom English text shown in Telegram bot payment buttons.", "", "TELEGRAM_LABEL_EN"), + ("PAYMENT_STARS_TELEGRAM_EMOJI", "string", "Telegram button emoji", + "Emoji prepended to the Telegram bot payment button when customized.", + "🌟", "TELEGRAM_EMOJI"), + ) +) + + SPEC = PaymentProviderSpec( id="stars", provider_key="telegram_stars", @@ -358,7 +403,10 @@ SPEC = PaymentProviderSpec( webapp_icon="Sparkles", telegram_labels={"ru": "Звёзды Telegram", "en": "Telegram Stars"}, pending_status="pending_stars", - enabled=lambda settings: settings.STARS_ENABLED, + # STARS_ENABLED stays on the global Settings — subscription_options reads + # it together with STARS_PRICE_* fields, so it has cross-cutting bizlogic + # reach beyond just the provider flag. + enabled=lambda settings: bool(getattr(settings, "STARS_ENABLED", False)), service_key="stars_service", callback_prefix="pay_stars", router=router, @@ -368,4 +416,6 @@ SPEC = PaymentProviderSpec( price_source="stars", emoji="⭐", telegram_emoji="⭐", + presentation_class=StarsPresentation, + manifest_fields=_PRESENTATION_MANIFEST, ) diff --git a/backend/config/settings.py b/backend/config/settings.py index f8e1fd8..9d7f432 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -233,12 +233,6 @@ class Settings(BaseSettings): PAYMENT_YOOKASSA_TELEGRAM_LABEL_RU: Optional[str] = None PAYMENT_YOOKASSA_TELEGRAM_LABEL_EN: Optional[str] = None PAYMENT_YOOKASSA_TELEGRAM_EMOJI: Optional[str] = None - PAYMENT_STARS_WEBAPP_LABEL_RU: Optional[str] = None - PAYMENT_STARS_WEBAPP_LABEL_EN: Optional[str] = None - PAYMENT_STARS_WEBAPP_ICON: Optional[str] = None - PAYMENT_STARS_TELEGRAM_LABEL_RU: Optional[str] = None - PAYMENT_STARS_TELEGRAM_LABEL_EN: Optional[str] = None - PAYMENT_STARS_TELEGRAM_EMOJI: Optional[str] = None MONTH_1_ENABLED: bool = Field(default=True, alias="1_MONTH_ENABLED") MONTH_3_ENABLED: bool = Field(default=True, alias="3_MONTHS_ENABLED")