294 lines
10 KiB
Python
294 lines
10 KiB
Python
"""
|
||
DNS routes - Yeni akış ile CF hesap seçimi, NS kontrolü, DNS yönetimi
|
||
"""
|
||
from flask import Blueprint, request, jsonify
|
||
from datetime import datetime
|
||
from app.models.domain import db, CloudflareAccount, Domain
|
||
from app.services.cloudflare_service import CloudflareService
|
||
from app.services.nameserver_service import NameserverService
|
||
from app.services.auth_service import token_required
|
||
import hashlib
|
||
|
||
dns_bp = Blueprint('dns', __name__, url_prefix='/api/dns')
|
||
|
||
|
||
def select_lb_ip(domain: str, lb_ips: list) -> str:
|
||
"""Domain için load balancer IP seç (hash-based)"""
|
||
hash_value = int(hashlib.md5(domain.encode()).hexdigest(), 16)
|
||
index = hash_value % len(lb_ips)
|
||
return lb_ips[index]
|
||
|
||
|
||
@dns_bp.route('/check-nameservers', methods=['POST'])
|
||
def check_nameservers():
|
||
"""Domain'in nameserver'larını kontrol et"""
|
||
try:
|
||
data = request.json
|
||
domain = data.get('domain')
|
||
|
||
if not domain:
|
||
return jsonify({"error": "domain gerekli"}), 400
|
||
|
||
# NS kontrolü yap
|
||
result = NameserverService.check_cloudflare_nameservers(domain)
|
||
|
||
return jsonify(result)
|
||
|
||
except Exception as e:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"NS kontrolü sırasında hata: {str(e)}"
|
||
}), 500
|
||
|
||
|
||
@dns_bp.route('/get-ns-instructions', methods=['POST'])
|
||
def get_ns_instructions():
|
||
"""NS yönlendirme talimatlarını al"""
|
||
try:
|
||
data = request.json
|
||
domain = data.get('domain')
|
||
zone_id = data.get('zone_id')
|
||
api_token = data.get('api_token')
|
||
|
||
if not all([domain, zone_id, api_token]):
|
||
return jsonify({"error": "domain, zone_id ve api_token gerekli"}), 400
|
||
|
||
# Mevcut NS'leri al
|
||
current_ns = NameserverService.get_current_nameservers(domain)
|
||
|
||
# Cloudflare zone NS'lerini al
|
||
cf_ns = NameserverService.get_cloudflare_zone_nameservers(zone_id, api_token)
|
||
|
||
if cf_ns["status"] == "error":
|
||
return jsonify(cf_ns), 400
|
||
|
||
return jsonify({
|
||
"status": "success",
|
||
"domain": domain,
|
||
"current_nameservers": current_ns.get("nameservers", []),
|
||
"cloudflare_nameservers": cf_ns["nameservers"],
|
||
"instructions": [
|
||
"1. Domain sağlayıcınızın (GoDaddy, Namecheap, vb.) kontrol paneline giriş yapın",
|
||
"2. Domain yönetimi veya DNS ayarları bölümüne gidin",
|
||
"3. 'Nameservers' veya 'Name Servers' seçeneğini bulun",
|
||
"4. 'Custom Nameservers' veya 'Use custom nameservers' seçeneğini seçin",
|
||
f"5. Aşağıdaki Cloudflare nameserver'larını ekleyin:",
|
||
*[f" - {ns}" for ns in cf_ns["nameservers"]],
|
||
"6. Değişiklikleri kaydedin",
|
||
"7. DNS propagation 24-48 saat sürebilir (genellikle 1-2 saat içinde tamamlanır)"
|
||
]
|
||
})
|
||
|
||
except Exception as e:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"NS talimatları alınırken hata: {str(e)}"
|
||
}), 500
|
||
|
||
|
||
@dns_bp.route('/validate-token', methods=['POST'])
|
||
def validate_cf_token():
|
||
"""Cloudflare API token doğrula (müşterinin kendi token'ı)"""
|
||
try:
|
||
data = request.json
|
||
domain = data.get('domain')
|
||
cf_token = data.get('cf_token')
|
||
|
||
if not domain or not cf_token:
|
||
return jsonify({"error": "domain ve cf_token gerekli"}), 400
|
||
|
||
cf_service = CloudflareService(cf_token)
|
||
result = cf_service.validate_token_and_get_zone(domain)
|
||
|
||
return jsonify(result)
|
||
|
||
except Exception as e:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"Token doğrulama hatası: {str(e)}"
|
||
}), 500
|
||
|
||
|
||
@dns_bp.route('/select-company-account', methods=['POST'])
|
||
def select_company_account():
|
||
"""Şirket CF hesabı seç ve zone oluştur/bul"""
|
||
try:
|
||
data = request.json
|
||
domain = data.get('domain')
|
||
cf_account_id = data.get('cf_account_id')
|
||
|
||
if not domain or not cf_account_id:
|
||
return jsonify({"error": "domain ve cf_account_id gerekli"}), 400
|
||
|
||
# CF hesabını al
|
||
cf_account = CloudflareAccount.query.get(cf_account_id)
|
||
|
||
if not cf_account or not cf_account.is_active:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": "Cloudflare hesabı bulunamadı veya aktif değil"
|
||
}), 404
|
||
|
||
# Hesap kapasitesi kontrolü
|
||
if cf_account.current_domain_count >= cf_account.max_domains:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"Bu hesap kapasitesi dolmuş ({cf_account.current_domain_count}/{cf_account.max_domains})"
|
||
}), 400
|
||
|
||
# API token'ı al
|
||
api_token = cf_account.get_api_token()
|
||
|
||
# Cloudflare'de zone var mı kontrol et
|
||
cf_service = CloudflareService(api_token)
|
||
result = cf_service.validate_token_and_get_zone(domain)
|
||
|
||
if result["status"] == "success":
|
||
# Zone zaten var
|
||
return jsonify({
|
||
"status": "success",
|
||
"zone_exists": True,
|
||
**result
|
||
})
|
||
else:
|
||
# Zone yok, oluşturulması gerekiyor
|
||
# TODO: Zone oluşturma fonksiyonu eklenecek
|
||
return jsonify({
|
||
"status": "pending",
|
||
"zone_exists": False,
|
||
"message": "Zone bulunamadı. Cloudflare'de zone oluşturulması gerekiyor.",
|
||
"cf_account": cf_account.to_dict(include_token=False)
|
||
})
|
||
|
||
except Exception as e:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"Hesap seçimi sırasında hata: {str(e)}"
|
||
}), 500
|
||
|
||
|
||
@dns_bp.route('/preview-changes', methods=['POST'])
|
||
@token_required
|
||
def preview_changes(current_user):
|
||
"""DNS değişiklik önizlemesi"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
data = request.json
|
||
domain = data.get('domain')
|
||
zone_id = data.get('zone_id')
|
||
cf_token = data.get('cf_token')
|
||
lb_ips = data.get('lb_ips', ['176.96.129.77']) # Default server IP
|
||
|
||
if not all([domain, zone_id, cf_token]):
|
||
return jsonify({"error": "domain, zone_id ve cf_token gerekli"}), 400
|
||
|
||
# Load balancer IP seç
|
||
new_ip = select_lb_ip(domain, lb_ips)
|
||
|
||
cf_service = CloudflareService(cf_token)
|
||
preview = cf_service.generate_dns_preview(domain, zone_id, new_ip)
|
||
|
||
return jsonify(preview)
|
||
|
||
except Exception as e:
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"Preview oluşturma hatası: {str(e)}"
|
||
}), 500
|
||
|
||
|
||
@dns_bp.route('/apply-changes', methods=['POST'])
|
||
@token_required
|
||
def apply_changes(current_user):
|
||
"""DNS değişikliklerini uygula ve domain'i kaydet"""
|
||
try:
|
||
customer = current_user.customer
|
||
if not customer:
|
||
return jsonify({'error': 'Customer profile not found'}), 404
|
||
|
||
data = request.json
|
||
domain_name = data.get('domain')
|
||
zone_id = data.get('zone_id')
|
||
cf_token = data.get('cf_token')
|
||
preview = data.get('preview')
|
||
proxy_enabled = data.get('proxy_enabled', True)
|
||
cf_account_id = data.get('cf_account_id')
|
||
cf_account_type = data.get('cf_account_type', 'company')
|
||
project_name = data.get('project_name')
|
||
|
||
if not all([domain_name, zone_id, cf_token, preview]):
|
||
return jsonify({"error": "Eksik parametreler"}), 400
|
||
|
||
# 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 ({customer.max_domains})'
|
||
}), 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
|
||
|
||
cf_service = CloudflareService(cf_token)
|
||
|
||
# DNS değişikliklerini uygula
|
||
result = cf_service.apply_dns_changes(zone_id, preview, proxy_enabled)
|
||
|
||
if result["status"] == "success":
|
||
# SSL yapılandır
|
||
ssl_config = cf_service.configure_ssl(zone_id)
|
||
|
||
# Domain'i veritabanına kaydet
|
||
domain_obj = Domain(
|
||
domain_name=domain_name,
|
||
customer_id=customer.id,
|
||
created_by=current_user.id,
|
||
project_name=project_name,
|
||
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=zone_id,
|
||
cf_proxy_enabled=proxy_enabled,
|
||
lb_ip=preview.get("new_ip"),
|
||
status="active",
|
||
dns_configured=True,
|
||
ssl_configured=len(ssl_config.get("errors", [])) == 0
|
||
)
|
||
|
||
# If using own CF account, save encrypted token
|
||
if cf_account_type == 'own':
|
||
domain_obj.set_cf_api_token(cf_token)
|
||
|
||
db.session.add(domain_obj)
|
||
|
||
# Update CF account domain count if using company account
|
||
if cf_account_type == 'company' and cf_account_id:
|
||
cf_account = CloudflareAccount.query.get(cf_account_id)
|
||
if cf_account:
|
||
cf_account.current_domain_count += 1
|
||
|
||
db.session.commit()
|
||
|
||
return jsonify({
|
||
"status": "success",
|
||
"dns_result": result,
|
||
"ssl_config": ssl_config,
|
||
"domain_id": domain_obj.id,
|
||
"domain": domain_obj.to_dict()
|
||
}), 201
|
||
|
||
return jsonify(result), 500
|
||
|
||
except Exception as e:
|
||
db.session.rollback()
|
||
return jsonify({
|
||
"status": "error",
|
||
"message": f"DNS uygulama hatası: {str(e)}"
|
||
}), 500
|
||
|