360 lines
12 KiB
Python
360 lines
12 KiB
Python
"""
|
||
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.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')
|
||
|
||
|
||
@customer_bp.route('/domains', methods=['GET'])
|
||
@token_required
|
||
def get_domains(current_user):
|
||
"""Get all domains for the current customer"""
|
||
try:
|
||
# Get customer
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
# Get domains with customer isolation
|
||
domains = Domain.query.filter_by(customer_id=customer.id).all()
|
||
|
||
# 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
|
||
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({
|
||
'domains': result,
|
||
'total': len(result),
|
||
'limit': customer.max_domains
|
||
}), 200
|
||
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|
||
@customer_bp.route('/domains/<int:domain_id>', methods=['GET'])
|
||
@token_required
|
||
def get_domain(current_user, domain_id):
|
||
"""Get specific domain details"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
# Get domain with customer isolation
|
||
domain = Domain.query.filter_by(
|
||
id=domain_id,
|
||
customer_id=customer.id
|
||
).first()
|
||
|
||
if not domain:
|
||
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 DNS records
|
||
domain_dict['dns_records'] = [record.to_dict() for record in domain.dns_records]
|
||
|
||
return jsonify(domain_dict), 200
|
||
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|
||
@customer_bp.route('/domains', methods=['POST'])
|
||
@token_required
|
||
def create_domain(current_user):
|
||
"""Create a new domain"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
data = request.get_json()
|
||
|
||
# Validate required fields
|
||
if not data.get('domain_name'):
|
||
return jsonify({'error': 'domain_name is required'}), 400
|
||
|
||
domain_name = data['domain_name'].lower().strip()
|
||
|
||
# Check domain limit
|
||
current_count = Domain.query.filter_by(customer_id=customer.id).count()
|
||
if current_count >= customer.max_domains:
|
||
return jsonify({
|
||
'error': f'Domain limit reached. Maximum {customer.max_domains} domains allowed.'
|
||
}), 403
|
||
|
||
# Check if domain already exists
|
||
existing = Domain.query.filter_by(domain_name=domain_name).first()
|
||
if existing:
|
||
return jsonify({'error': 'Domain already exists'}), 409
|
||
|
||
# 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_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:
|
||
accounts_result = admin_api.get_available_cf_accounts()
|
||
|
||
if accounts_result['status'] != 'success' or not accounts_result.get('accounts'):
|
||
return jsonify({
|
||
'error': 'No available Cloudflare account found. Please contact administrator.'
|
||
}), 404
|
||
|
||
# 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ı Admin Panel'den çek
|
||
account_result = admin_api.get_cf_account(cf_account_id)
|
||
|
||
if account_result['status'] != 'success':
|
||
return jsonify({
|
||
'error': account_result.get('error', 'Cloudflare account not found')
|
||
}), 404
|
||
|
||
cf_account_data = account_result['account']
|
||
|
||
# Validate account
|
||
if cf_account_data.get('is_full', True):
|
||
return jsonify({
|
||
'error': f'Cloudflare account is full ({cf_account_data.get("max_domains", 0)} domains max)'
|
||
}), 400
|
||
|
||
# Create domain
|
||
domain = Domain(
|
||
domain_name=domain_name,
|
||
customer_id=customer.id,
|
||
created_by=current_user.id,
|
||
project_name=data.get('project_name'),
|
||
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_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'])
|
||
|
||
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
|
||
|
||
return jsonify({
|
||
'message': 'Domain created successfully',
|
||
'domain': domain.to_dict(),
|
||
'cf_account_name': cf_account_data.get('name') if cf_account_data else None
|
||
}), 201
|
||
|
||
except Exception as e:
|
||
db.session.rollback()
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|
||
@customer_bp.route('/domains/<int:domain_id>', methods=['PUT'])
|
||
@token_required
|
||
def update_domain(current_user, domain_id):
|
||
"""Update domain"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
# Get domain with customer isolation
|
||
domain = Domain.query.filter_by(
|
||
id=domain_id,
|
||
customer_id=customer.id
|
||
).first()
|
||
|
||
if not domain:
|
||
return jsonify({'error': 'Domain not found'}), 404
|
||
|
||
data = request.get_json()
|
||
|
||
# Update allowed fields
|
||
if 'project_name' in data:
|
||
domain.project_name = data['project_name']
|
||
|
||
if 'cf_proxy_enabled' in data:
|
||
domain.cf_proxy_enabled = data['cf_proxy_enabled']
|
||
|
||
if 'status' in data and data['status'] in ['pending', 'active', 'suspended', 'error']:
|
||
domain.status = data['status']
|
||
|
||
domain.updated_at = datetime.utcnow()
|
||
db.session.commit()
|
||
|
||
return jsonify({
|
||
'message': 'Domain updated successfully',
|
||
'domain': domain.to_dict()
|
||
}), 200
|
||
|
||
except Exception as e:
|
||
db.session.rollback()
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|
||
@customer_bp.route('/domains/<int:domain_id>', methods=['DELETE'])
|
||
@token_required
|
||
def delete_domain(current_user, domain_id):
|
||
"""Delete domain"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
# Get domain with customer isolation
|
||
domain = Domain.query.filter_by(
|
||
id=domain_id,
|
||
customer_id=customer.id
|
||
).first()
|
||
|
||
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
|
||
|
||
db.session.delete(domain)
|
||
db.session.commit()
|
||
|
||
return jsonify({'message': 'Domain deleted successfully'}), 200
|
||
|
||
except Exception as e:
|
||
db.session.rollback()
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|
||
@customer_bp.route('/domains/<int:domain_id>/dns', methods=['GET'])
|
||
@token_required
|
||
def get_domain_dns(current_user, domain_id):
|
||
"""Get DNS records for a domain"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
# Get domain with customer isolation
|
||
domain = Domain.query.filter_by(
|
||
id=domain_id,
|
||
customer_id=customer.id
|
||
).first()
|
||
|
||
if not domain:
|
||
return jsonify({'error': 'Domain not found'}), 404
|
||
|
||
records = [record.to_dict() for record in domain.dns_records]
|
||
|
||
return jsonify({
|
||
'domain': domain.domain_name,
|
||
'records': records,
|
||
'total': len(records)
|
||
}), 200
|
||
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|
||
@customer_bp.route('/cloudflare-accounts', methods=['GET'])
|
||
@token_required
|
||
def get_cloudflare_accounts(current_user):
|
||
"""Get available Cloudflare accounts from Admin Panel API"""
|
||
try:
|
||
# Fetch CF accounts from Admin Panel API
|
||
admin_api = AdminAPIService()
|
||
result = admin_api.get_available_cf_accounts()
|
||
|
||
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.get('accounts', []),
|
||
'total': result.get('total', 0)
|
||
}), 200
|
||
|
||
except Exception as e:
|
||
return jsonify({
|
||
'error': str(e),
|
||
'accounts': [],
|
||
'total': 0
|
||
}), 500
|
||
|
||
|
||
@customer_bp.route('/stats', methods=['GET'])
|
||
@token_required
|
||
def get_customer_stats(current_user):
|
||
"""Get customer statistics"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
# Count domains by status
|
||
total_domains = Domain.query.filter_by(customer_id=customer.id).count()
|
||
active_domains = Domain.query.filter_by(customer_id=customer.id, status='active').count()
|
||
pending_domains = Domain.query.filter_by(customer_id=customer.id, status='pending').count()
|
||
|
||
return jsonify({
|
||
'total_domains': total_domains,
|
||
'active_domains': active_domains,
|
||
'pending_domains': pending_domains,
|
||
'max_domains': customer.max_domains,
|
||
'available_slots': customer.max_domains - total_domains,
|
||
'subscription_plan': customer.subscription_plan
|
||
}), 200
|
||
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
|