vpn-btcpay-provisioner/app/handlers/payment_handler.py
2024-12-30 06:03:07 +00:00

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