diff --git a/backend/app/routes/admin.py b/backend/app/routes/admin.py index 9edd3c9..f4bd71e 100644 --- a/backend/app/routes/admin.py +++ b/backend/app/routes/admin.py @@ -1,9 +1,11 @@ """ -Admin routes - Cloudflare hesap yönetimi +Admin routes - Cloudflare hesap yönetimi ve Customer yönetimi """ from flask import Blueprint, request, jsonify -from app.models.domain import db, CloudflareAccount +from app.models.domain import db, CloudflareAccount, Domain +from app.models.user import User, Customer from app.services.cloudflare_service import CloudflareService +from sqlalchemy import func admin_bp = Blueprint('admin', __name__, url_prefix='/api/admin') @@ -268,3 +270,216 @@ def test_cf_account(account_id): "message": f"Test sırasında hata: {str(e)}" }), 500 + +# ============================================ +# CUSTOMER MANAGEMENT ENDPOINTS +# ============================================ + +@admin_bp.route('/customers', methods=['GET']) +def list_customers(): + """Tüm müşterileri listele""" + try: + # Query parameters + page = request.args.get('page', 1, type=int) + per_page = request.args.get('per_page', 20, type=int) + search = request.args.get('search', '') + + # Base query + query = db.session.query(User, Customer).join(Customer, User.id == Customer.user_id) + + # Search filter + if search: + query = query.filter( + db.or_( + User.email.ilike(f'%{search}%'), + User.full_name.ilike(f'%{search}%'), + Customer.company_name.ilike(f'%{search}%') + ) + ) + + # Pagination + total = query.count() + results = query.offset((page - 1) * per_page).limit(per_page).all() + + # Format response + customers = [] + for user, customer in results: + # Get domain count + domain_count = Domain.query.filter_by(customer_id=customer.id).count() + + customer_data = { + **user.to_dict(), + **customer.to_dict(), + 'domain_count': domain_count + } + customers.append(customer_data) + + return jsonify({ + "status": "success", + "customers": customers, + "pagination": { + "page": page, + "per_page": per_page, + "total": total, + "pages": (total + per_page - 1) // per_page + } + }) + + except Exception as e: + return jsonify({ + "status": "error", + "message": f"Müşteriler listelenirken hata: {str(e)}" + }), 500 + + +@admin_bp.route('/customers/', methods=['GET']) +def get_customer(customer_id): + """Belirli bir müşteriyi getir""" + try: + customer = Customer.query.get(customer_id) + + if not customer: + return jsonify({ + "status": "error", + "message": "Müşteri bulunamadı" + }), 404 + + user = User.query.get(customer.user_id) + + # Get domains + domains = Domain.query.filter_by(customer_id=customer.id).all() + + return jsonify({ + "status": "success", + "customer": { + **user.to_dict(), + **customer.to_dict(), + 'domains': [d.to_dict() for d in domains] + } + }) + + except Exception as e: + return jsonify({ + "status": "error", + "message": f"Müşteri getirilirken hata: {str(e)}" + }), 500 + + +@admin_bp.route('/customers//plan', methods=['PUT']) +def update_customer_plan(customer_id): + """Müşterinin planını güncelle""" + try: + data = request.json + customer = Customer.query.get(customer_id) + + if not customer: + return jsonify({ + "status": "error", + "message": "Müşteri bulunamadı" + }), 404 + + # Update plan + if 'subscription_plan' in data: + customer.subscription_plan = data['subscription_plan'] + + if 'max_domains' in data: + customer.max_domains = data['max_domains'] + + if 'max_containers' in data: + customer.max_containers = data['max_containers'] + + if 'subscription_status' in data: + customer.subscription_status = data['subscription_status'] + + db.session.commit() + + return jsonify({ + "status": "success", + "message": "Plan başarıyla güncellendi", + "customer": customer.to_dict() + }) + + except Exception as e: + db.session.rollback() + return jsonify({ + "status": "error", + "message": f"Plan güncellenirken hata: {str(e)}" + }), 500 + + +@admin_bp.route('/customers//status', methods=['PUT']) +def update_customer_status(customer_id): + """Müşteri durumunu güncelle (aktif/pasif)""" + try: + data = request.json + customer = Customer.query.get(customer_id) + + if not customer: + return jsonify({ + "status": "error", + "message": "Müşteri bulunamadı" + }), 404 + + user = User.query.get(customer.user_id) + + if 'is_active' in data: + user.is_active = data['is_active'] + + if 'subscription_status' in data: + customer.subscription_status = data['subscription_status'] + + db.session.commit() + + return jsonify({ + "status": "success", + "message": "Durum başarıyla güncellendi" + }) + + except Exception as e: + db.session.rollback() + return jsonify({ + "status": "error", + "message": f"Durum güncellenirken hata: {str(e)}" + }), 500 + + +@admin_bp.route('/stats', methods=['GET']) +def get_admin_stats(): + """Admin dashboard istatistikleri""" + try: + total_customers = Customer.query.count() + active_customers = db.session.query(Customer).join(User).filter(User.is_active == True).count() + total_domains = Domain.query.count() + active_domains = Domain.query.filter_by(status='active').count() + + # CF accounts stats + total_cf_accounts = CloudflareAccount.query.filter_by(is_active=True).count() + + # Subscription breakdown + subscription_stats = db.session.query( + Customer.subscription_plan, + func.count(Customer.id) + ).group_by(Customer.subscription_plan).all() + + return jsonify({ + "status": "success", + "stats": { + "customers": { + "total": total_customers, + "active": active_customers + }, + "domains": { + "total": total_domains, + "active": active_domains + }, + "cf_accounts": total_cf_accounts, + "subscriptions": {plan: count for plan, count in subscription_stats} + } + }) + + except Exception as e: + return jsonify({ + "status": "error", + "message": f"İstatistikler alınırken hata: {str(e)}" + }), 500 + diff --git a/frontend/src/pages/DomainSetupNew.jsx b/frontend/src/pages/DomainSetupNew.jsx index 281dbc7..12a7440 100644 --- a/frontend/src/pages/DomainSetupNew.jsx +++ b/frontend/src/pages/DomainSetupNew.jsx @@ -73,14 +73,42 @@ function DomainSetupNew() { setStep(2) } - const handleCFAccountTypeSelect = (type) => { + const handleCFAccountTypeSelect = async (type) => { setCfAccountType(type) setError(null) - + if (type === 'own') { setStep(3) // Go to token input } else { - setStep(4) // Go to company account selection + // Auto-select first active company CF account + if (companyCFAccounts.length > 0) { + const firstAccount = companyCFAccounts[0] + setSelectedCFAccount(firstAccount) + + // Automatically validate with company account + setLoading(true) + try { + const response = await dnsAPI.selectCompanyAccount(domain, firstAccount.id) + + if (response.data.status === 'success') { + setZoneInfo(response.data) + // Check if NS is already configured + await checkNameservers() + setStep(5) // Go to NS check/instructions + } else { + setError(response.data.message || 'Şirket hesabı seçilemedi') + setStep(4) // Show account selection + } + } catch (err) { + setError('Şirket hesabı seçilirken hata oluştu') + setStep(4) // Show account selection + } finally { + setLoading(false) + } + } else { + setError('Aktif şirket CF hesabı bulunamadı') + setStep(4) // Go to company account selection + } } }