Commit Graph

6687 Commits

Author SHA1 Message Date
Egor f9d58e964c Merge pull request #2594 from BEDOLAGA-DEV/dev
Dev
2026-02-12 03:06:34 +03:00
Fringg d3c14ac303 fix: UnboundLocalError for get_logo_media in required_sub_channel_check 2026-02-12 02:56:14 +03:00
Fringg fda9f3beec fix: suppress bot-blocked-by-user error in AuthMiddleware 2026-02-12 02:53:05 +03:00
Fringg 27365b3c75 fix: handle time/date types in backup JSON serialization 2026-02-12 02:51:20 +03:00
Fringg 3dac332a9f chore: ruff format 7 files 2026-02-11 21:50:49 +03:00
Fringg c5124b97b6 fix: payment race conditions, balance atomicity, renewal rollback safety
- YooKassa: SELECT FOR UPDATE on payment row to prevent concurrent double-processing
- subtract_user_balance: row locking to prevent concurrent balance race conditions
- subtract_user_balance: transaction creation before commit for atomicity
- subscription renewal: compensating refund if extend_subscription fails after charge
- StaleDataError: use savepoint instead of full rollback to protect parent transaction
2026-02-11 21:49:37 +03:00
Fringg ee2e79db31 refactor: remove modem functionality from classic subscriptions
Remove all modem purchase/management code:
- Delete modem handler, service, and tests
- Remove modem button from keyboards and admin panel
- Remove modem pricing from calculations
- Remove modem REST API endpoint and schemas
- Remove modem decorator, config settings, and notification formatting
- Keep DB column and migration for backwards compatibility
2026-02-11 21:14:08 +03:00
Fringg d05ff678ab fix: HTML parse fallback, email change race condition, username length limit
- start.py: retry welcome message with parse_mode=None on TelegramBadRequest HTML parse error
- auth.py: handle IntegrityError race condition on email change, wrap email sending in try-except
- config.py: truncate RemnaWave username to 36 chars (API limit) instead of 64
2026-02-11 20:51:50 +03:00
Fringg fcaa9dfb27 fix: clean stale squad UUIDs from tariffs during server sync
When squads are deleted from the RemnaWave panel and servers are synced,
the bot cleaned subscription connected_squads but left stale UUIDs in
tariff.allowed_squads. This caused errors when users tried to purchase
or extend subscriptions with tariffs referencing deleted squads.

Now sync_with_remnawave also removes stale UUIDs from all tariffs.
2026-02-11 18:37:19 +03:00
Fringg c30c2feee1 fix: handle StaleDataError in webhook user.deleted server counter decrement
When a user is deleted from the panel, the subscription may already be
cascade-deleted by the time the webhook handler tries to decrement
server counters. This caused StaleDataError followed by
PendingRollbackError when accessing subscription.id in the error handler.

- Save subscription.id before DB operations to avoid lazy load after rollback
- Catch StaleDataError explicitly and rollback the session
- Re-fetch subscription/user after potential rollback in _handle_user_deleted
- Skip subscription cleanup if it was already cascade-deleted
2026-02-11 18:35:36 +03:00
Fringg 640da34736 fix: remove DisplayNameRestrictionMiddleware
Blocking users based on display name patterns caused false positives
for legitimate users. Removed middleware registration from dispatcher.
2026-02-11 18:31:50 +03:00
Fringg 93bb8e0eb4 fix: allow email change for unverified emails
Unverified email users could not change their email (e.g. to fix a typo)
because the endpoint required email_verified=True. Now unverified emails
are replaced directly without code verification, and a new verification
email is sent to the updated address.
2026-02-11 18:28:52 +03:00
Fringg 7d9ced8f4f fix: delete subscription_servers before subscription to prevent FK violation
reset_user_subscription and reset_trial endpoints did not clean up
subscription_servers rows before deleting the subscription, causing
ForeignKeyViolationError on subscription_servers.subscription_id_fkey.

Also fixed the same missing cleanup in user_service.hard_delete_user.
2026-02-11 18:25:42 +03:00
Fringg b5998ea9d2 fix: use traffic topup config and add WATA 429 retry
- Cabinet API: use get_traffic_topup_packages() instead of
  get_traffic_packages() in classic mode endpoints (lines 622, 727, 2410)
  to prevent infinite free traffic exploit via initial-purchase packages
- WATA service: add retry logic for 429 rate limit responses with
  Retry-After parsing from header and response body, up to 2 retries,
  downgrade 429 from error to warning log level
2026-02-11 18:20:30 +03:00
Egor aabadf1ffd Merge pull request #2592 from BEDOLAGA-DEV/release-please--branches--main
chore(main): release 3.10.1
v3.10.1
2026-02-11 06:11:43 +03:00
github-actions[bot] e5e5bb3354 chore(main): release 3.10.1 2026-02-11 03:11:02 +00:00
Egor ea41b0af7a Merge pull request #2591 from BEDOLAGA-DEV/dev
Dev
2026-02-11 06:10:38 +03:00
Fringg 3193ffbd1b fix: change CryptoBot URL priority to bot_invoice_url for Telegram opening 2026-02-11 05:50:43 +03:00
Egor 5da01cc6df Merge pull request #2590 from BEDOLAGA-DEV/main
w
2026-02-11 04:47:13 +03:00
Fringg 887ea9cf5a style: format subscription.py with ruff 2026-02-11 04:45:42 +03:00
Fringg bee4aa4284 fix: protect server counter callers and fix tariff change detection
- Wrap unprotected add/remove_user_to/from_servers calls in try/except
  in miniapp.py and cabinet subscription.py to prevent 500 errors
- Fix is_tariff_change to include classic-to-tariff transitions
  (subscription.tariff_id=None → new tariff_id) so purchased traffic
  is properly reset when switching modes
2026-02-11 04:44:15 +03:00
Fringg b167ed3dd1 fix: preserve purchased traffic when extending same tariff
extend_subscription was unconditionally resetting purchased_traffic_gb
and deleting TrafficPurchase records whenever traffic_limit_gb was passed,
even when extending the same tariff (not changing). Now only resets
on actual tariff change (is_tariff_change=True), preserving purchased
traffic on same-tariff extensions.
2026-02-11 04:38:08 +03:00
Fringg 6cec024e46 fix: use flush instead of commit in server counter functions
add_user_to_servers and remove_user_from_servers were calling
db.commit() internally, breaking transaction atomicity for all
callers that perform additional operations afterward. Changed to
db.flush() so the caller controls the commit boundary.
2026-02-11 04:15:50 +03:00
Fringg 2094886990 fix: address review issues in backup, updates, and webhook handlers
- backup: add DATE column parsing in restore, use is_file() in delete_backup
- updates: add missing callback.answer() in show_updates_menu early return
- webhook: add server counter decrement and SubscriptionServer cleanup on user deletion, use single commit
2026-02-11 04:09:39 +03:00
Fringg b0fd38d60c fix: clear subscription data when user deleted from Remnawave panel
Previously only status was set to expired and remnawave_uuid cleared.
Now also clears subscription_url, subscription_crypto_link,
remnawave_short_uuid, and connected_squads so the bot correctly
shows no active subscription after panel deletion.
2026-02-11 04:02:09 +03:00
Fringg 3a680b41b0 fix: suppress 'message is not modified' error in updates panel
- Remove dangling version_info['repo_url'] expression
- Handle 'message is not modified' in all three update handlers
  to prevent error screen on repeated button clicks
2026-02-11 03:47:30 +03:00
Fringg 02e40bd6f7 fix: expand backup coverage to all 68 models and harden restore
- Add 37 missing models to backup (payment providers, polls, contests,
  wheel, FAQ, promo offers, webhooks, configs, menu buttons, etc.)
- Add tariff_promo_groups and payment_method_promo_groups association tables
- Replace hardcoded association restore with generic handler
- Fix transaction atomicity: flush instead of commit in inner methods,
  remove inner rollback calls, single commit/rollback in outer handler
- Fix composite PK support for UserPromoGroup (was only detecting first PK)
- Fix duplicate insert bug when clear_existing=True and record already exists
- Add cabinet_refresh_tokens to clear list, fix support_audit_logs deletion order
- Add Time column parsing for ReferralContest.daily_summary_time
- Security: tarfile filter='data', path traversal protection in _restore_files
  and delete_backup, os.sep in startswith checks
2026-02-11 03:35:16 +03:00
Fringg 19dabf3851 fix: allow purchase when recalculated price is lower than cached
Only block purchase when the price increased (user would overpay).
When a promo discount activates between viewing price and confirming,
the recalculated price is lower — allow the purchase at the new price
instead of forcing the user to restart the checkout flow.
2026-02-11 02:30:40 +03:00
Fringg eaf3a07579 fix: use callback fallback when MINIAPP_CUSTOM_URL is not set
Only consider MINIAPP_CUSTOM_URL for miniapp buttons, not the
purchase-only MINIAPP_PURCHASE_URL which cannot display subscription
info and loads indefinitely. When no custom URL is configured, fall
back to regular callback_data so the bot shows subscription natively.
2026-02-11 01:58:40 +03:00
Fringg be1da976e1 fix: ignore 'message is not modified' on privacy policy decline
User clicking Decline twice produced the same edit_text causing
TelegramBadRequest. Silently ignore it and remove pointless retry.
2026-02-11 01:40:49 +03:00
Fringg a1ffd5bda6 fix: prevent cascading greenlet errors after sync rollback
After db.rollback() all ORM objects expire. Subsequent attribute access
triggers lazy load in async context causing greenlet_spawn errors for
every remaining user. Break the sync loop after rollback instead of
continuing with a corrupted session.

Also downgrade TelegramNetworkError to warning in channel_checker.
2026-02-11 01:39:39 +03:00
Fringg d58a80f3ea fix: handle StaleDataError in webhook when user already deleted
When a user is deleted via cabinet, RemnaWave sends user.disabled webhook
but the subscription row is already cascade-deleted. This caused
StaleDataError on commit + PendingRollbackError when logging user.id.

Save user_id before handler call and catch StaleDataError as warning.
2026-02-11 01:18:58 +03:00
Egor 45c7afe34c Update README.md 2026-02-11 01:03:58 +03:00
Fringg e43a8d6ce4 fix: downgrade Telegram timeout errors to warning in monitoring service
Add TelegramNetworkError handling before generic Exception catch in all
notification methods to prevent timeout errors from generating error
reports in chat. Timeouts are transient network issues, not bugs.
2026-02-10 23:11:48 +03:00
Fringg e94b93d0c1 fix: handle nullable traffic_limit_gb and end_date in subscription model
Add None-safety guards to Subscription model properties (is_active,
is_expired, should_be_expired, actual_status, days_left,
traffic_used_percent) and pricing handler comparisons to prevent
TypeError when nullable columns contain None values.
2026-02-10 20:35:42 +03:00
Egor 2ad26a9156 Merge pull request #2588 from BEDOLAGA-DEV/release-please--branches--main
chore(main): release 3.10.0
v3.10.0
2026-02-10 07:59:27 +03:00
github-actions[bot] 3383b9c790 chore(main): release 3.10.0 2026-02-10 04:58:24 +00:00
Egor 6acaf18203 Merge pull request #2587 from BEDOLAGA-DEV/dev
Release: dev → main
2026-02-10 07:57:54 +03:00
Fringg 019fbc12b6 fix: webhook:close button not working due to channel check timeout
Channel checker middleware called bot.get_chat_member() which could
timeout (60s), causing callback.answer() to fail with "query too old".

Skip channel check for lightweight UI callbacks (webhook:close,
ban_notify:delete, noop). Also answer callback before delete attempt
and add fallback to remove keyboard if delete fails.
2026-02-10 07:54:24 +03:00
Fringg 5156d635f0 fix: sync subscription status from panel in user.modified webhook
When subscription was extended in panel, webhook updated end_date but
left status as expired. Now syncs ACTIVE/DISABLED status from panel
payload when end_date is in the future.
2026-02-10 07:49:10 +03:00
Fringg f77922522a fix: allow non-HTTP deep links in crypto link webhook updates
_is_valid_url only accepted http(s), silently dropping valid deep links
like happ://, vless://, ss:// from revoked webhook payloads.
Added _is_valid_link that accepts any URI scheme.
2026-02-10 07:41:32 +03:00
Fringg 0db00a8f90 style: format cryptobot.py with ruff 2026-02-10 07:33:42 +03:00
Fringg fe54640885 fix: add missing placeholders to Arabic SUBSCRIPTION_INFO template
Was just a header text without {status}, {type}, etc. placeholders,
causing KeyError when .format() was called.
2026-02-10 07:30:52 +03:00
Fringg ec8eaf52bf fix: downgrade transient API errors (502/503/504) to warning level
502/503/504 are transient errors that don't need ERROR reports in chat.
Also downgrade API connection test failure to warning.
2026-02-10 07:27:20 +03:00
Fringg fe5f5ded96 feat: add MULENPAY_WEBSITE_URL setting for post-payment redirect
Previously website_url was hardcoded to WEBHOOK_URL, redirecting users
to the webhook endpoint after payment. Now configurable via env var.
2026-02-10 07:25:58 +03:00
Fringg 2cb6d731e9 fix: stop CryptoBot webhook retry loop and save cabinet payments to DB
Cabinet was calling CryptoBotService.create_invoice() directly without
saving CryptoBotPayment to DB. When webhook arrived, payment lookup
failed and returned HTTP 400, causing infinite retries.

Now cabinet uses PaymentService.create_cryptobot_payment() (same as
miniapp) with proper USD conversion via currency_converter.

Also return HTTP 200 for unknown invoice_ids to stop retry spam.
2026-02-10 07:25:54 +03:00
Fringg 184c52d4ea feat: webhook protection — prevent sync/monitoring from overwriting webhook data
Add last_webhook_update_at timestamp to Subscription model. When a webhook
handler modifies a subscription, it stamps this field. Auto-sync, monitoring,
and force-check services skip subscriptions updated by webhook within the
last 60 seconds, preventing stale panel data from overwriting fresh
real-time changes.

- Add last_webhook_update_at column + migration
- Stamp all 8 webhook handlers with commit in every code path
- Add is_recently_updated_by_webhook() guard in 12 sync/monitoring paths
- Add REMNAWAVE_WEBHOOK_* variables to .env.example
- Add webhook setup documentation to README with Caddy/nginx examples
- Fix pre-existing yookassa webhook test (mock AsyncSessionLocal)
2026-02-10 07:16:22 +03:00
Fringg 8e85e244cb feat: handle errors.bandwidth_usage_threshold_reached_max_notifications webhook
Last remaining unhandled RemnaWave backend event — sends admin
notification when the bandwidth threshold notification limit is reached.
2026-02-10 06:34:20 +03:00
Fringg 43a326a98c feat: handle service.subpage_config_changed webhook event
Add admin notification when subscription page config is
created, updated or deleted in RemnaWave panel.
2026-02-10 06:32:52 +03:00
Fringg d9de15a5a0 feat: add close button to all webhook notifications
Add dismissible close button (✖️) to every webhook notification message.
Users can now close any webhook notification by tapping the button,
which deletes the message via webhook:close callback handler.
2026-02-10 06:22:17 +03:00