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

349 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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
if cf_account_type == 'company':
# 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()
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
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
# 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