import logging import requests import os from pathlib import Path import traceback from .webhook_handler import get_vault_values from ..utils.db.operations import DatabaseManager from ..utils.db.models import SubscriptionStatus logger = logging.getLogger(__name__) class BTCPayHandler: def __init__(self): logger.info("Initializing BTCPayHandler") try: # Get configuration from Ansible vault logger.debug("Retrieving vault values") vault_values = get_vault_values() self.base_url = vault_values['btcpay_base_url'] self.api_key = vault_values['btcpay_api_key'] self.store_id = vault_values['btcpay_store_id'] logger.info(f"BTCPayHandler initialized with base URL: {self.base_url}") except Exception as e: logger.error(f"Failed to initialize BTCPayHandler: {str(e)}") logger.error(traceback.format_exc()) raise def create_invoice(self, amount_sats, duration_hours, user_id, public_key): """Create BTCPay invoice for VPN subscription""" try: logger.info(f"Creating invoice: {amount_sats} sats, {duration_hours}h for user {user_id}") # First, get or create user user = DatabaseManager.get_user_by_uuid(user_id) if not user: user = DatabaseManager.create_user(user_id) logger.info(f"Created new user with ID: {user_id}") headers = { 'Authorization': f'token {self.api_key}', 'Content-Type': 'application/json' } # Get app URL from environment or use a default app_url = os.getenv('APP_BASE_URL', 'http://localhost:5000').rstrip('/') logger.debug(f"Using app URL for redirect: {app_url}") payload = { 'amount': amount_sats, 'currency': 'SATS', 'metadata': { 'duration_hours': duration_hours, 'userId': user_id, 'publicKey': public_key, 'orderId': f'vpn_sub_{duration_hours}h' }, 'checkout': { 'redirectURL': f'{app_url}/payment/success?userId={user_id}', 'redirectAutomatically': True } } logger.debug(f"Sending request to BTCPay Server: {self.base_url}/api/v1/stores/{self.store_id}/invoices") logger.debug(f"Request payload: {payload}") response = requests.post( f'{self.base_url}/api/v1/stores/{self.store_id}/invoices', headers=headers, json=payload ) logger.debug(f"BTCPay response status: {response.status_code}") logger.debug(f"BTCPay response content: {response.text}") if response.status_code != 200: logger.error(f"BTCPay invoice creation failed: {response.text}") return None invoice_data = response.json() invoice_id = invoice_data['id'] logger.info(f"Successfully created invoice {invoice_id}") # Create pending subscription subscription = DatabaseManager.create_subscription( user_id, invoice_id, public_key, duration_hours ) logger.info(f"Created pending subscription for invoice {invoice_id}") return { 'invoice_id': invoice_id, 'checkout_url': invoice_data['checkoutLink'], 'user_id': user_id } except Exception as e: logger.error("Error creating BTCPay invoice:") logger.error(traceback.format_exc()) return None def get_subscription_config(self, user_id): """Get WireGuard configuration details for a subscription""" try: logger.info(f"Fetching subscription config for user {user_id}") user = DatabaseManager.get_user_by_uuid(user_id) if not user: logger.error(f"User {user_id} not found") return None subscription = DatabaseManager.get_active_subscription_for_user(user.id) if not subscription: logger.error(f"No active subscription found for user {user_id}") return None return { 'serverPublicKey': os.getenv('WIREGUARD_SERVER_PUBLIC_KEY'), 'serverEndpoint': os.getenv('WIREGUARD_SERVER_ENDPOINT'), 'clientIp': subscription.assigned_ip } except Exception as e: logger.error(f"Error getting subscription config: {str(e)}") logger.error(traceback.format_exc()) return None