hosting-platform/backend/app/routes/customer.py

349 lines
12 KiB
Python
Raw Normal View History

2026-01-11 14:38:39 +00:00
"""
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 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 = None
2026-01-11 14:38:39 +00:00
if cf_account_type == 'company':
# Otomatik hesap seçimi - cf_account_id verilmemişse en uygun hesabı seç
2026-01-11 14:38:39 +00:00
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()
if not cf_account:
return jsonify({
'error': 'No available Cloudflare account found. Please contact administrator.'
}), 404
cf_account_id = cf_account.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
2026-01-11 14:38:39 +00:00
if not cf_account.is_active:
return jsonify({'error': 'Cloudflare account is not active'}), 400
if not cf_account.use_for_verification:
return jsonify({'error': 'This Cloudflare account is not available for domain verification'}), 400
2026-01-11 14:38:39 +00:00
# Check CF account capacity
if cf_account.current_domain_count >= cf_account.max_domains:
return jsonify({
'error': f'Cloudflare account is full ({cf_account.max_domains} 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)
# 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()
return jsonify({
'message': 'Domain created successfully',
'domain': domain.to_dict()
}), 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
# 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)
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 (company accounts only)"""
try:
# Get active company CF accounts
accounts = CloudflareAccount.query.filter_by(is_active=True).all()
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)
return jsonify({
'accounts': result,
'total': len(result)
}), 200
except Exception as e:
return jsonify({'error': str(e)}), 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