feat: Integrate Admin Panel API for CF account management
- Add AdminAPIService to fetch CF accounts from Admin Panel - Update customer routes to use Admin Panel API instead of local DB - Add ADMIN_API_URL and ADMIN_API_INTERNAL_KEY config - Remove local CF account count management (managed in Admin Panel) - Support automatic CF account selection from Admin Panel
This commit is contained in:
parent
7f564c7638
commit
c28642cc6e
|
|
@ -27,6 +27,10 @@ class Config:
|
|||
# Encryption (for sensitive data like API tokens)
|
||||
ENCRYPTION_KEY = os.getenv("ENCRYPTION_KEY")
|
||||
|
||||
# Admin Panel API (for fetching CF accounts)
|
||||
ADMIN_API_URL = os.getenv("ADMIN_API_URL", "http://localhost:5001")
|
||||
ADMIN_API_INTERNAL_KEY = os.getenv("ADMIN_API_INTERNAL_KEY", "internal-api-key-change-in-production")
|
||||
|
||||
# Cloudflare Platform Account (opsiyonel - deprecated, use database instead)
|
||||
PLATFORM_CF_API_TOKEN = os.getenv("PLATFORM_CF_API_TOKEN")
|
||||
PLATFORM_CF_ACCOUNT_ID = os.getenv("PLATFORM_CF_ACCOUNT_ID")
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from flask import Blueprint, request, jsonify
|
|||
from app.models.domain import db, Domain, DNSRecord, CloudflareAccount
|
||||
from app.models.user import Customer
|
||||
from app.services.auth_service import token_required
|
||||
from app.services.admin_api_service import AdminAPIService
|
||||
from datetime import datetime
|
||||
|
||||
customer_bp = Blueprint('customer', __name__, url_prefix='/api/customer')
|
||||
|
|
@ -115,42 +116,50 @@ def create_domain(current_user):
|
|||
# Validate CF account if using company account
|
||||
cf_account_id = data.get('cf_account_id')
|
||||
cf_account_type = data.get('cf_account_type', 'company')
|
||||
cf_account = None
|
||||
cf_account_data = None
|
||||
|
||||
if cf_account_type == 'company':
|
||||
# Fetch available CF accounts from Admin Panel
|
||||
admin_api = AdminAPIService()
|
||||
|
||||
# Otomatik hesap seçimi - cf_account_id verilmemişse en uygun hesabı seç
|
||||
if not cf_account_id:
|
||||
# En az dolu, aktif ve verification için kullanılabilir hesabı seç
|
||||
cf_account = CloudflareAccount.query.filter(
|
||||
CloudflareAccount.is_active == True,
|
||||
CloudflareAccount.use_for_verification == True,
|
||||
CloudflareAccount.current_domain_count < CloudflareAccount.max_domains
|
||||
).order_by(
|
||||
CloudflareAccount.current_domain_count.asc()
|
||||
).first()
|
||||
accounts_result = admin_api.get_available_cf_accounts()
|
||||
|
||||
if not cf_account:
|
||||
if accounts_result['status'] != 'success' or not accounts_result.get('accounts'):
|
||||
return jsonify({
|
||||
'error': 'No available Cloudflare account found. Please contact administrator.'
|
||||
}), 404
|
||||
|
||||
cf_account_id = cf_account.id
|
||||
# En az dolu hesabı seç
|
||||
available_accounts = [
|
||||
acc for acc in accounts_result['accounts']
|
||||
if not acc.get('is_full', True)
|
||||
]
|
||||
|
||||
if not available_accounts:
|
||||
return jsonify({
|
||||
'error': 'All Cloudflare accounts are full. Please contact administrator.'
|
||||
}), 404
|
||||
|
||||
# En az dolu olanı seç
|
||||
cf_account_data = min(available_accounts, key=lambda x: x.get('current_domains', 0))
|
||||
cf_account_id = cf_account_data['id']
|
||||
else:
|
||||
# Manuel seçim yapılmışsa o hesabı kullan
|
||||
cf_account = CloudflareAccount.query.get(cf_account_id)
|
||||
if not cf_account:
|
||||
return jsonify({'error': 'Cloudflare account not found'}), 404
|
||||
# Manuel seçim yapılmışsa o hesabı Admin Panel'den çek
|
||||
account_result = admin_api.get_cf_account(cf_account_id)
|
||||
|
||||
if not cf_account.is_active:
|
||||
return jsonify({'error': 'Cloudflare account is not active'}), 400
|
||||
if account_result['status'] != 'success':
|
||||
return jsonify({
|
||||
'error': account_result.get('error', 'Cloudflare account not found')
|
||||
}), 404
|
||||
|
||||
if not cf_account.use_for_verification:
|
||||
return jsonify({'error': 'This Cloudflare account is not available for domain verification'}), 400
|
||||
cf_account_data = account_result['account']
|
||||
|
||||
# Check CF account capacity
|
||||
if cf_account.current_domain_count >= cf_account.max_domains:
|
||||
# Validate account
|
||||
if cf_account_data.get('is_full', True):
|
||||
return jsonify({
|
||||
'error': f'Cloudflare account is full ({cf_account.max_domains} domains max)'
|
||||
'error': f'Cloudflare account is full ({cf_account_data.get("max_domains", 0)} domains max)'
|
||||
}), 400
|
||||
|
||||
# Create domain
|
||||
|
|
@ -172,16 +181,15 @@ def create_domain(current_user):
|
|||
domain.set_cf_api_token(data['cf_api_token'])
|
||||
|
||||
db.session.add(domain)
|
||||
|
||||
# Update CF account domain count if using company account
|
||||
if cf_account_type == 'company' and cf_account:
|
||||
cf_account.current_domain_count += 1
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Note: CF account domain count is managed in Admin Panel database
|
||||
# We don't update it here since we're using separate databases
|
||||
|
||||
return jsonify({
|
||||
'message': 'Domain created successfully',
|
||||
'domain': domain.to_dict()
|
||||
'domain': domain.to_dict(),
|
||||
'cf_account_name': cf_account_data.get('name') if cf_account_data else None
|
||||
}), 201
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -250,9 +258,8 @@ def delete_domain(current_user, domain_id):
|
|||
if not domain:
|
||||
return jsonify({'error': 'Domain not found'}), 404
|
||||
|
||||
# Update CF account count if using company account
|
||||
if domain.cf_account_type == 'company' and domain.cf_account:
|
||||
domain.cf_account.current_domain_count = max(0, domain.cf_account.current_domain_count - 1)
|
||||
# Note: CF account domain count is managed in Admin Panel database
|
||||
# We don't update it here since we're using separate databases
|
||||
|
||||
db.session.delete(domain)
|
||||
db.session.commit()
|
||||
|
|
@ -297,26 +304,30 @@ def get_domain_dns(current_user, domain_id):
|
|||
@customer_bp.route('/cloudflare-accounts', methods=['GET'])
|
||||
@token_required
|
||||
def get_cloudflare_accounts(current_user):
|
||||
"""Get available Cloudflare accounts (company accounts only)"""
|
||||
"""Get available Cloudflare accounts from Admin Panel API"""
|
||||
try:
|
||||
# Get active company CF accounts
|
||||
accounts = CloudflareAccount.query.filter_by(is_active=True).all()
|
||||
# Fetch CF accounts from Admin Panel API
|
||||
admin_api = AdminAPIService()
|
||||
result = admin_api.get_available_cf_accounts()
|
||||
|
||||
result = []
|
||||
for account in accounts:
|
||||
account_dict = account.to_dict(include_token=False)
|
||||
# Calculate available capacity
|
||||
account_dict['available_capacity'] = account.max_domains - account.current_domain_count
|
||||
account_dict['is_full'] = account.current_domain_count >= account.max_domains
|
||||
result.append(account_dict)
|
||||
if result['status'] == 'error':
|
||||
return jsonify({
|
||||
'error': result.get('error', 'Failed to fetch CF accounts from Admin Panel'),
|
||||
'accounts': [],
|
||||
'total': 0
|
||||
}), 500
|
||||
|
||||
return jsonify({
|
||||
'accounts': result,
|
||||
'total': len(result)
|
||||
'accounts': result.get('accounts', []),
|
||||
'total': result.get('total', 0)
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
return jsonify({
|
||||
'error': str(e),
|
||||
'accounts': [],
|
||||
'total': 0
|
||||
}), 500
|
||||
|
||||
|
||||
@customer_bp.route('/stats', methods=['GET'])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
"""
|
||||
Admin Panel API Service
|
||||
Handles communication with Admin Panel API to fetch CF accounts
|
||||
"""
|
||||
import requests
|
||||
from typing import Dict, List, Optional
|
||||
from app.config import Config
|
||||
|
||||
|
||||
class AdminAPIService:
|
||||
"""Service to communicate with Admin Panel API"""
|
||||
|
||||
def __init__(self):
|
||||
self.base_url = Config.ADMIN_API_URL
|
||||
self.api_key = Config.ADMIN_API_INTERNAL_KEY
|
||||
self.headers = {
|
||||
'X-Internal-API-Key': self.api_key,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
def get_available_cf_accounts(self) -> Dict:
|
||||
"""
|
||||
Fetch available CF accounts from Admin Panel
|
||||
|
||||
Returns:
|
||||
{
|
||||
"status": "success" | "error",
|
||||
"accounts": [...],
|
||||
"total": int,
|
||||
"error": str (if error)
|
||||
}
|
||||
"""
|
||||
try:
|
||||
url = f"{self.base_url}/api/cf-accounts/internal/available"
|
||||
response = requests.get(url, headers=self.headers, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': f'Admin API returned {response.status_code}: {response.text}',
|
||||
'accounts': [],
|
||||
'total': 0
|
||||
}
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': 'Admin API request timeout',
|
||||
'accounts': [],
|
||||
'total': 0
|
||||
}
|
||||
except requests.exceptions.ConnectionError:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': 'Cannot connect to Admin API',
|
||||
'accounts': [],
|
||||
'total': 0
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': f'Admin API error: {str(e)}',
|
||||
'accounts': [],
|
||||
'total': 0
|
||||
}
|
||||
|
||||
def get_cf_account(self, account_id: int) -> Dict:
|
||||
"""
|
||||
Fetch specific CF account with API token from Admin Panel
|
||||
|
||||
Args:
|
||||
account_id: CF account ID
|
||||
|
||||
Returns:
|
||||
{
|
||||
"status": "success" | "error",
|
||||
"account": {...},
|
||||
"error": str (if error)
|
||||
}
|
||||
"""
|
||||
try:
|
||||
url = f"{self.base_url}/api/cf-accounts/internal/{account_id}"
|
||||
response = requests.get(url, headers=self.headers, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
elif response.status_code == 404:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': 'CF account not found'
|
||||
}
|
||||
elif response.status_code == 403:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': 'CF account not available for verification'
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': f'Admin API returned {response.status_code}: {response.text}'
|
||||
}
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': 'Admin API request timeout'
|
||||
}
|
||||
except requests.exceptions.ConnectionError:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': 'Cannot connect to Admin API'
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': f'Admin API error: {str(e)}'
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue