129 lines
5.0 KiB
Python
129 lines
5.0 KiB
Python
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 |