diff --git a/backend/app/routes/customer.py b/backend/app/routes/customer.py index 5cccde7..c7584fb 100644 --- a/backend/app/routes/customer.py +++ b/backend/app/routes/customer.py @@ -3,7 +3,7 @@ Customer Routes - Domain Management Customer-specific endpoints with isolation """ from flask import Blueprint, request, jsonify -from app.models.domain import db, Domain, DNSRecord, CloudflareAccount +from app.models.domain import db, Domain, DNSRecord from app.models.user import Customer from app.services.auth_service import token_required from app.services.admin_api_service import AdminAPIService @@ -24,21 +24,41 @@ def get_domains(current_user): # Get domains with customer isolation domains = Domain.query.filter_by(customer_id=customer.id).all() - + + # Fetch CF account names from Admin Panel (batch) + cf_account_names = {} + if domains: + # Get unique CF account IDs + cf_account_ids = set( + d.cf_account_id for d in domains + if d.cf_account_type == 'company' and d.cf_account_id + ) + + if cf_account_ids: + admin_api = AdminAPIService() + accounts_result = admin_api.get_available_cf_accounts() + + if accounts_result['status'] == 'success': + for acc in accounts_result.get('accounts', []): + cf_account_names[acc['id']] = acc['name'] + # Add CF account info result = [] for domain in domains: domain_dict = domain.to_dict() - + # Add CF account name if using company account - if domain.cf_account_type == 'company' and domain.cf_account: - domain_dict['cf_account_name'] = domain.cf_account.name + if domain.cf_account_type == 'company' and domain.cf_account_id: + domain_dict['cf_account_name'] = cf_account_names.get( + domain.cf_account_id, + f'CF Account #{domain.cf_account_id}' + ) else: domain_dict['cf_account_name'] = 'Own Account' - + # Add DNS record count domain_dict['dns_record_count'] = len(domain.dns_records) - + result.append(domain_dict) return jsonify({ @@ -70,14 +90,22 @@ def get_domain(current_user, domain_id): return jsonify({'error': 'Domain not found'}), 404 domain_dict = domain.to_dict() - - # Add CF account info - if domain.cf_account_type == 'company' and domain.cf_account: - domain_dict['cf_account_name'] = domain.cf_account.name - + + # Add CF account info from Admin Panel + if domain.cf_account_type == 'company' and domain.cf_account_id: + admin_api = AdminAPIService() + account_result = admin_api.get_cf_account(domain.cf_account_id) + + if account_result['status'] == 'success': + domain_dict['cf_account_name'] = account_result['account']['name'] + else: + domain_dict['cf_account_name'] = f'CF Account #{domain.cf_account_id}' + else: + domain_dict['cf_account_name'] = 'Own Account' + # Add DNS records domain_dict['dns_records'] = [record.to_dict() for record in domain.dns_records] - + return jsonify(domain_dict), 200 except Exception as e: @@ -162,7 +190,41 @@ def create_domain(current_user): 'error': f'Cloudflare account is full ({cf_account_data.get("max_domains", 0)} domains max)' }), 400 - # Create domain + # Create zone in Cloudflare if using company account + cf_zone_id = None + cf_nameservers = [] + cf_api_token = None + + if cf_account_type == 'company' and cf_account_id: + # Get CF account with API token from Admin Panel + admin_api = AdminAPIService() + account_result = admin_api.get_cf_account(cf_account_id) + + if account_result['status'] != 'success': + return jsonify({ + 'error': f"Failed to get CF account: {account_result.get('error')}" + }), 500 + + cf_api_token = account_result['account'].get('api_token') + if not cf_api_token: + return jsonify({ + 'error': 'CF account API token not found' + }), 500 + + # Create zone in Cloudflare + from app.services.cloudflare_service import CloudflareService + cf_service = CloudflareService(cf_api_token) + zone_result = cf_service.create_zone(domain_name) + + if zone_result['status'] != 'success': + return jsonify({ + 'error': f"Failed to create Cloudflare zone: {zone_result.get('message', 'Unknown error')}" + }), 500 + + cf_zone_id = zone_result['zone_id'] + cf_nameservers = zone_result.get('nameservers', []) + + # Create domain in database domain = Domain( domain_name=domain_name, customer_id=customer.id, @@ -171,11 +233,11 @@ def create_domain(current_user): use_cloudflare=data.get('use_cloudflare', True), cf_account_type=cf_account_type, cf_account_id=cf_account_id if cf_account_type == 'company' else None, - cf_zone_id=data.get('cf_zone_id'), + cf_zone_id=cf_zone_id, cf_proxy_enabled=data.get('cf_proxy_enabled', True), status='pending' ) - + # If using own CF account, save encrypted token if cf_account_type == 'own' and data.get('cf_api_token'): domain.set_cf_api_token(data['cf_api_token']) @@ -183,13 +245,21 @@ def create_domain(current_user): db.session.add(domain) 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 + # Increment domain count in Admin Panel if using company account + if cf_account_type == 'company' and cf_account_id: + admin_api = AdminAPIService() + increment_result = admin_api.increment_domain_count(cf_account_id) + + if increment_result['status'] != 'success': + # Log warning but don't fail the request + # Domain is already created in customer DB + print(f"Warning: Failed to increment domain count in Admin Panel: {increment_result.get('error')}") return jsonify({ 'message': 'Domain created successfully', 'domain': domain.to_dict(), - 'cf_account_name': cf_account_data.get('name') if cf_account_data else None + 'cf_account_name': cf_account_data.get('name') if cf_account_data else None, + 'nameservers': cf_nameservers }), 201 except Exception as e: @@ -258,12 +328,24 @@ def delete_domain(current_user, domain_id): if not domain: return jsonify({'error': 'Domain not found'}), 404 - # Note: CF account domain count is managed in Admin Panel database - # We don't update it here since we're using separate databases + # Store CF account info before deletion + cf_account_id = domain.cf_account_id + cf_account_type = domain.cf_account_type + # Delete domain db.session.delete(domain) db.session.commit() + # Decrement domain count in Admin Panel if using company account + if cf_account_type == 'company' and cf_account_id: + admin_api = AdminAPIService() + decrement_result = admin_api.decrement_domain_count(cf_account_id) + + if decrement_result['status'] != 'success': + # Log warning but don't fail the request + # Domain is already deleted from customer DB + print(f"Warning: Failed to decrement domain count in Admin Panel: {decrement_result.get('error')}") + return jsonify({'message': 'Domain deleted successfully'}), 200 except Exception as e: diff --git a/backend/app/services/cloudflare_service.py b/backend/app/services/cloudflare_service.py index 1ef0570..38cb2d0 100644 --- a/backend/app/services/cloudflare_service.py +++ b/backend/app/services/cloudflare_service.py @@ -5,10 +5,59 @@ import CloudFlare class CloudflareService: """Cloudflare API işlemleri""" - + def __init__(self, api_token: str): self.cf = CloudFlare.CloudFlare(token=api_token) self.api_token = api_token + + def create_zone(self, domain: str) -> Dict: + """ + Create a new zone in Cloudflare + Returns zone_id and nameservers + """ + try: + # Create zone + zone_data = { + 'name': domain, + 'jump_start': True # Auto-scan DNS records + } + + zone = self.cf.zones.post(data=zone_data) + + return { + 'status': 'success', + 'zone_id': zone['id'], + 'zone_name': zone['name'], + 'nameservers': zone.get('name_servers', []), + 'zone_status': zone.get('status', 'pending'), + 'created_on': zone.get('created_on') + } + + except CloudFlare.exceptions.CloudFlareAPIError as e: + error_code = e.code if hasattr(e, 'code') else 0 + error_message = str(e) + + # Handle specific errors + if error_code == 1061: # Zone already exists + return { + 'status': 'error', + 'error': 'zone_exists', + 'message': f'Zone {domain} already exists in this Cloudflare account' + } + + return { + 'status': 'error', + 'error': 'cloudflare_api_error', + 'message': f'Cloudflare API error: {error_message}', + 'code': error_code + } + + except Exception as e: + return { + 'status': 'error', + 'error': 'unexpected_error', + 'message': f'Unexpected error: {str(e)}' + } def validate_token_and_get_zone(self, domain: str) -> Dict: """