Commit Graph

82 Commits

Author SHA1 Message Date
firewookie 555b887952 Merge remote-tracking branch 'origin/dev' into dev 2026-03-08 09:23:08 +05:00
Fringg 3a361628aa feat: register TELEGRAM_OIDC category, hints in admin settings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:25:54 +03:00
Fringg 084a3cd16f feat: configurable Telegram Login Widget with admin settings
- Add 4 TELEGRAM_WIDGET_* settings to config (size, radius, userpic, request_access)
- Register TELEGRAM_WIDGET category with choices, hints, and prefix mapping
- Add public GET /branding/telegram-widget endpoint returning widget config
- Use Literal type for size validation, Field(ge=0, le=20) for radius bounds
- Clamp radius values from DB to prevent out-of-range values
2026-03-07 01:48:14 +03:00
firewookie 7ed91b13eb - RioPay payment system integration 2026-03-06 11:44:22 +05:00
Fringg dce9eaa597 fix: reset traffic purchases on expired subscription renewal + pricing fixes
- Reset TrafficPurchase records and purchased_traffic_gb when renewing
  expired subscriptions (was incorrectly preserving stale purchases,
  inflating traffic limit e.g. 100GB+20GB=120GB instead of fresh 100GB)
- Fix in extend_subscription() CRUD, cabinet /renew, bot handlers,
  simple_subscription handlers
- Add RemnaWave sync to cabinet /renew endpoint after subscription changes
- Fix device_price_kopeks=0 falsy-zero bug (11+ instances, or → is not None)
- Fix double-increment of purchased_traffic_gb in cabinet traffic purchase
- Fix orphaned TrafficPurchase records in 5 locations (replace_subscription,
  extend_subscription fixed_with_topup, classic mode, switch_tariff,
  purchase.py is_traffic_fixed)
- Fix admin_users.py UnboundLocalError from TrafficPurchase inline import
  shadowing module-level import
- Standardize pricing order: base + devices → promo_group → promo_offer
  across all 5+ pricing paths (cabinet, miniapp, autopay, auto-purchase,
  monitoring)
- Fix exception handlers in calculate_renewal_price (raise instead of
  returning fallback 0)
- Fix monitoring_service double-discount (promo_offer applied twice)
- Fix auto-purchase _get_tariff_price_for_period return type to tuple
  (base_price, discount_percent) so callers add devices before discount
- Pass traffic_limit_gb/device_limit to extend_subscription in
  simple_subscription.py instead of manual overwrites
2026-03-04 04:46:29 +03:00
Fringg 628a99e7aa fix: classic mode prices overridden by active tariff prices
Root cause: ensure_tariffs_synced runs BEFORE bot_configuration_service.initialize(),
so SALES_MODE from system_settings is not yet applied. If SALES_MODE=classic is set
via cabinet (not .env), load_period_prices_from_db sees tariffs mode and loads tariff
prices into _DB_PERIOD_PRICES. Then refresh_period_prices() always prefers
_DB_PERIOD_PRICES over settings.PRICE_*_DAYS, even in classic mode.

Three fixes:
1. refresh_period_prices() now checks settings.is_tariffs_mode() before using
   _DB_PERIOD_PRICES — classic mode always uses settings.PRICE_*_DAYS
2. initialize() calls refresh_period_prices() after all DB overrides are applied,
   so SALES_MODE is correct when prices are recalculated
3. Switching SALES_MODE to classic via cabinet now clears _DB_PERIOD_PRICES
2026-03-04 03:12:34 +03:00
Fringg 69868418e5 style: format 6 files with ruff 2026-03-02 04:35:16 +03:00
Fringg 4eaedd33bf feat: add RESET_TRAFFIC_ON_TARIFF_SWITCH admin setting
New boolean setting (default: True) controls whether user traffic
is reset when switching between tariff plans.

Changes:
- config.py: add RESET_TRAFFIC_ON_TARIFF_SWITCH setting
- system_settings_service.py: category override (TRAFFIC) + hints
- pricing.py: admin bot handler toggle entry
- cabinet/routes/subscription.py: pass reset_traffic to RemnaWave on switch
- webapi/routes/miniapp.py: same for miniapp tariff switch
- tariff_purchase.py: use setting in 3 switch handlers (was hardcoded)
- subscription_auto_purchase_service.py: separate tariff switch vs payment logic
- crud/subscription.py: conditional traffic_used_gb reset on tariff change
2026-02-27 09:57:37 +03:00
Fringg 295d2e877e refactor: remove legacy app-config.json system
Replace dual-configuration architecture (Remnawave API + local file fallback)
with Remnawave-only approach. When config is unavailable, show explicit
"not configured" message instead of silent file fallback.

- Delete app-config.json and admin_apps.py CRUD module (~1260 lines)
- Remove sync loaders, legacy step format handlers, device_mapping dicts
- Remove miniapp /app-config.json endpoint and filesystem search
- Remove backup service app-config.json snapshot/restore
- Remove APP_CONFIG_PATH setting, env var, docker volume mount
- Remove hardcoded 6-device keyboard fallback
- Remove legacy step-based keyboard rendering (installationStep etc.)
- Add "config not configured" message when Remnawave config is missing
- Update admin UI: "clear config" disables guide mode instead of reverting
2026-02-24 05:58:25 +03:00
Fringg 8375d7ecc5 feat: add multi-channel mandatory subscription system
- Multi-channel subscription enforcement via middleware, events, and cabinet API
- 3-layer cache architecture: Redis -> PostgreSQL -> rate-limited Telegram API
- ChatMemberUpdated event-driven tracking with automatic VPN access control
- Admin management via bot FSM handler and REST API with full CRUD
- Channel ID normalization: @username resolved to numeric ID at creation time
- Fail-closed error handling: API errors deny access (security-first)
- Background reconciliation with keyset pagination (100 per batch)
- Per-user rate limiting on subscription check button (5s cooldown)
- Redis connection pooling via cache singleton (no per-request connections)
- Database: channel_id index, multi-row upsert optimization
- Localization: en, ru, zh, fa, ua translations for all new strings
- Frontend blocking UI with channel list and subscription status
- Admin channel management page with toggle, delete, and create
2026-02-24 02:50:31 +03:00
Fringg 784616b349 refactor: replace universal_migration.py with Alembic
Remove the 7,791-line universal_migration.py and 16 incomplete individual
Alembic migrations. Replace with a single initial schema migration using
Base.metadata.create_all(checkfirst=True).

Changes:
- Add programmatic Alembic runner (app/database/migrations.py) with
  auto-stamp logic for existing databases transitioning from
  universal_migration
- Extract ensure_default_web_api_token() to web_api_token_service.py
- Extract sync_postgres_sequences() to database.py with SQL injection
  prevention via _quote_ident()
- Add HMAC token hashing support with backward-compatible dual-hash
  fallback and automatic rehashing
- Remove dead init_db() function and unused imports
- Add Makefile targets: migrate, migration, migrate-stamp, migrate-history
- Fix fileConfig() destroying structlog config (disable_existing_loggers)
- Remove duplicate migrations/alembic/alembic.ini with credentials
- Add script.py.mako template for future migration generation
- Update startup flow: alembic upgrade → sync sequences → ensure token
- Harden database.py: ParamSpec for retry decorator, safe URL logging,
  echo='debug' mode, execute_with_retry validation
- Update documentation references

31 files changed, 302 insertions(+), 9,226 deletions(-)
2026-02-18 08:10:20 +03:00
Fringg 0807a9ff19 fix: sync SUPPORT_SYSTEM_MODE between SystemSettings and SupportSettings
When changing SUPPORT_SYSTEM_MODE via system settings admin panel, the
SupportSettingsService JSON cache was not updated, causing the old value
to take priority. Now both services stay in sync bidirectionally.
2026-02-16 18:22:44 +03:00
Fringg 1f0fef114b refactor: complete structlog migration with contextvars, kwargs, and logging hardening
- Add ContextVarsMiddleware for automatic user_id/chat_id/username binding
  via structlog contextvars (aiogram) and http_method/http_path (FastAPI)
- Use bound_contextvars() context manager instead of clear_contextvars()
  to safely restore previous state instead of wiping all context
- Register ContextVarsMiddleware as outermost middleware (before GlobalError)
  so all error logs include user context
- Replace structlog.get_logger() with structlog.get_logger(__name__) across
  270 calls in 265 files for meaningful logger names
- Switch wrapper_class from BoundLogger to make_filtering_bound_logger()
  for pre-processor level filtering (performance optimization)
- Migrate 1411 %-style positional arg logger calls to structlog kwargs
  style across 161 files via AST script
- Migrate log_rotation_service.py from stdlib logging to structlog
- Add payment module prefixes to TelegramNotifierProcessor.IGNORED_LOGGER_PREFIXES
  and ExcludePaymentFilter.PAYMENT_MODULES to prevent payment data leaking
  to Telegram notifications and general log files
- Fix LoggingMiddleware: add from_user null-safety for channel posts,
  switch time.time() to time.monotonic() for duration measurement
- Remove duplicate logger assignments in purchase.py, config.py,
  inline.py, and admin/payments.py
2026-02-16 09:18:12 +03:00
Fringg bf2b2f1c56 feat: add button style and emoji support for cabinet mode (Bot API 9.4)
- Upgrade aiogram to 3.25.0 for style/icon_custom_emoji_id support
- Add CABINET_BUTTON_STYLE config for global color override
- Per-section default styles: subscription (green), balance (blue),
  referral (green), admin (red), home (blue)
- Style priority: explicit > CABINET_BUTTON_STYLE > per-section default
- Add icon_custom_emoji_id pass-through for Premium bot owners
- Admin panel setting for button style with color picker
2026-02-12 22:34:38 +03:00
Fringg ad87c5fb5e feat: rename MAIN_MENU_MODE=text to cabinet with deep-linking to frontend sections
- Rename mode from 'text' to 'cabinet' (text/text_only/minimal kept as aliases)
- Add build_cabinet_url() for joining MINIAPP_CUSTOM_URL with section paths
- Cabinet main menu now has section-specific buttons: subscription, balance,
  referral, support, info — each opens the corresponding cabinet page
- Add CALLBACK_TO_CABINET_PATH mapping for automatic deep-linking from
  callback_data to cabinet routes (/subscription, /balance, /referral, etc.)
- Unmapped callback_data gracefully falls back to regular Telegram callbacks
- Add startup validation warning when cabinet mode is active without MINIAPP_CUSTOM_URL
- Update admin broadcast buttons with section-specific routing
- Backward compatible: is_text_main_menu_mode() kept as alias for is_cabinet_mode()
2026-02-12 22:21:08 +03:00
Fringg 57dc1ff47f fix: resolve deadlock on server_squads counter updates and add webhook notification toggles
- Fix deadlock: enforce sorted lock ordering in add_user_to_servers/remove_user_from_servers
- Fix cross-call deadlock: add update_server_user_counts() for atomic add+remove in one sorted pass
- Fix deadlock in squad migration: use sorted dict iteration for counter updates
- Fix broken "Buy traffic" button: subscription_add_traffic → buy_traffic callback_data
- Add 12 webhook notification toggle settings (WEBHOOK_NOTIFY_*) with master toggle
- Add admin UI category "Уведомления от вебхуков" with hints in BotConfigurationService
- Add toggle check in _notify_user() respecting master and per-event settings
2026-02-12 06:47:26 +03:00
Fringg a3903a252e refactor: remove smart auto-activation & activation prompt, fix production bugs
Remove AUTO_ACTIVATE_AFTER_TOPUP and SHOW_ACTIVATION_PROMPT_AFTER_TOPUP
features from all payment providers, config, system settings, and tests.
Cart auto-purchase (AUTO_PURCHASE_AFTER_TOPUP) is preserved.

Bug fixes:
- fix KeyError 'months' in devices.py for custom locale overrides
- fix IntegrityError on trial subscription retry (update existing PENDING instead of INSERT)
- fix PendingRollbackError cascade by adding db.rollback() before recovery
- fix TelegramForbiddenError not caught in photo_message.py
- fix "query is too old" spam in required_sub_channel_check
- add missing trial locale keys (TRIAL_PAYMENT_DESCRIPTION, TRIAL_REFUND_DESCRIPTION, TRIAL_ACTIVATION_ERROR)
2026-02-09 21:39:53 +03:00
Fringg c4794db1dd feat: add TRIAL_DISABLED_FOR setting to disable trial by user type
New setting allows granular control over trial availability:
- none: trial available for all (default)
- email: trial disabled for email users
- telegram: trial disabled for telegram users
- all: trial disabled for everyone

Enforced in bot handlers, cabinet API, and miniapp routes.
Automatically appears in admin panel as dropdown via CHOICES.
2026-02-07 00:19:25 +03:00
c0mrade 9a2aea038a chore: add uv package manager and ruff linter configuration
- Add pyproject.toml with uv and ruff configuration
- Pin Python version to 3.13 via .python-version
- Add Makefile commands: lint, format, fix
- Apply ruff formatting to entire codebase
- Remove unused imports (base64 in yookassa/simple_subscription)
- Update .gitignore for new config files
2026-01-24 17:45:27 +03:00
gy9vin 7aa64521d2 feat(payments): добавить KassaAI как отдельную платёжную систему
Новая платёжка KassaAI (api.fk.life) работает параллельно с Freekassa.

  Добавлено:
  - app/services/kassa_ai_service.py — API-сервис
  - app/database/crud/kassa_ai.py — CRUD-операции
  - app/services/payment/kassa_ai.py — KassaAiPaymentMixin
  - app/handlers/balance/kassa_ai.py — хендлеры пополнения

  Изменено:
  - config.py — настройки KASSA_AI_*
  - models.py — PaymentMethod.KASSA_AI, модель KassaAiPayment
  - payment_service.py — подключён KassaAiPaymentMixin
  - webserver/payments.py — webhook /kassa-ai-webhook
  - keyboards/inline.py — кнопка KassaAI
  - handlers/balance/main.py — регистрация хендлеров
  - universal_migration.py — миграция таблицы kassa_ai_payments
  - system_settings_service.py — настройки в админке
  - .env.example — примеры переменных

  Способы оплаты: 44=СБП, 36=Карты РФ, 43=SberPay
2026-01-20 19:09:27 +03:00
gy9vin dff723aede feat(monitoring): добавить настройки мониторинга трафика в админку
- Добавлена кнопка "⚙️ Настройки трафика" в меню мониторинга
  - Добавлен UI для управления быстрой и суточной проверками трафика
  - Можно включать/выключать проверки, менять пороги и интервалы
  - Настройки сохраняются в БД через BotConfigurationService
  - Добавлены SETTING_HINTS с описаниями параметров
2026-01-20 17:19:57 +03:00
gy9vin 94cd06302a Фиксы UI 2026-01-16 15:58:22 +03:00
Egor 65c087aefb Update system_settings_service.py 2026-01-16 04:57:04 +03:00
PEDZEO 243eef066c Add ban notification messages and refactor notification service
- Introduced new ban notification messages for device limit, WiFi, and mobile network violations in the configuration.
- Refactored the BanNotificationService to utilize the new messages from the configuration for sending notifications.
- Added a new method to handle mobile network ban notifications.
- Updated API routes to support the new notification type for mobile network bans.
2026-01-14 07:25:09 +03:00
PEDZEO 0e24a5505c feat(subscription): добавлены новые функции для управления тарифами и трафиком
- Обновлены схемы и маршруты для поддержки покупки тарифов и управления трафиком.
- Реализована синхронизация тарифов и серверов из RemnaWave при запуске.
- Добавлены новые параметры в тарифы: server_traffic_limits и allow_traffic_topup.
- Обновлены настройки и логика для проверки доступности докупки трафика в зависимости от тарифа.
- Внедрены новые эндпоинты для работы с колесом удачи и обработка платежей через Stars.

Обновлён .env.example с новыми параметрами для режима продаж подписок.
2026-01-12 07:41:10 +03:00
Egor 23b64ffb2a Revert "Revert "Frekassa"" 2026-01-06 22:43:01 +03:00
Egor aeaaa54920 Revert "Frekassa" 2026-01-06 22:40:35 +03:00
Egor 53a10c0640 Add files via upload 2026-01-06 20:56:44 +03:00
yazhog 800d589afa Document YooKassa VAT codes in env example 2025-12-31 12:00:48 +03:00
Egor c9c25613af Add new traffic selection mode option 2025-12-30 18:10:08 +04:00
Egor 83cb1ec823 Add files via upload 2025-12-25 21:01:11 +03:00
Egor 791482a8a1 Update system_settings_service.py 2025-12-22 19:32:06 +03:00
Egor fc955bd3b2 Revert "Add admin web panel miniapp toggle" 2025-12-15 07:24:41 +03:00
Egor 174f9b8517 Add admin web panel miniapp toggle 2025-12-15 07:18:45 +03:00
Egor 0892f494d9 Revert "Add internal squad management for users and trials" 2025-12-08 04:17:05 +03:00
Egor 6c41263511 Add internal squad management for users and trials 2025-12-08 04:15:18 +03:00
Egor 386b9ae998 Add configurable user tags for trial and paid subscriptions 2025-12-08 02:44:53 +03:00
Egor 9d3f096be0 Add toggle for support top-ups 2025-11-24 08:17:23 +03:00
Egor 29c6e296df Escape promo discount format hint for HTML 2025-11-23 06:36:44 +03:00
Egor edff6d5102 Add tests for Platega payment flows and method parsing 2025-11-07 07:49:38 +03:00
Egor 47bd1be714 Update system_settings_service.py 2025-11-06 03:21:48 +03:00
Egor 777ad52bad Update system_settings_service.py 2025-11-06 03:02:31 +03:00
Egor 5fcadb5544 Update system_settings_service.py 2025-11-06 02:48:36 +03:00
Egor 0a8af20b58 Update system_settings_service.py 2025-11-06 02:23:32 +03:00
Egor 221cc05af3 Group timezone and payment verification settings 2025-11-01 05:27:56 +03:00
Egor 17768c303f Ensure env configuration takes priority over DB overrides 2025-11-01 02:50:24 +03:00
Egor da46c18210 Revert "Add automatic Telegram Stars rate fetching and toggle" 2025-11-01 00:55:55 +03:00
Egor 61a93f86b3 Add dynamic Telegram Stars rate with auto refresh 2025-11-01 00:25:55 +03:00
Egor e02123c1ed Add configurable retry attempts for maintenance checks 2025-10-31 22:15:05 +03:00
Egor cf6bbffd9b Respect maintenance monitoring setting 2025-10-31 21:45:58 +03:00