Refactor backend and add registry build workflow
Build and publish Docker image / build-and-publish (push) Successful in 2m45s
Build and publish Docker image / build-and-publish (push) Successful in 2m45s
This commit is contained in:
commit
c177d7981d
43 files changed
+18124
No files matched your search
@@ -0,0 +1,298 @@
|
||||
"""Domains API routes for AnchorHost."""
|
||||
|
||||
|
||||
from domain_runtime import domain_manager
|
||||
from domain_service import create_domain_record, delete_domain_record, get_domain_by_id, get_user_domains, link_domain_to_server, unlink_domain_from_server
|
||||
from flask import Blueprint, jsonify, request
|
||||
from runtime_config import (
|
||||
logger,
|
||||
)
|
||||
from server_records import get_server_by_id
|
||||
from user_service import authenticate_user, get_bearer_token, require_admin
|
||||
from websocket_service import sync_user_domains_with_dns
|
||||
|
||||
__all__ = ['create_domain_api', 'delete_domain_api', 'fix_all_dnssec_api', 'get_domains_api', 'link_domain_api', 'sync_domains_api', 'test_domain_api', 'unlink_domain_api', 'verify_dnssec_api']
|
||||
|
||||
|
||||
|
||||
bp = Blueprint("domains", __name__)
|
||||
|
||||
|
||||
@bp.route('/api/dnssec/fix-all', methods=['POST'])
|
||||
def fix_all_dnssec_api():
|
||||
"""Fix DNSSEC delegation for all user domains"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
|
||||
# Only allow admin users
|
||||
if not user or user.get('role') != 'admin':
|
||||
return jsonify({'error': 'Admin access required'}), 403
|
||||
|
||||
if not domain_manager:
|
||||
return jsonify({'error': 'Domain manager not available'}), 503
|
||||
|
||||
# Run the fix
|
||||
domain_manager.fix_all_dnssec_delegations()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'DNSSEC fix process initiated. Check logs for details.'
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fixing DNSSEC: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/dnssec/verify/<username>', methods=['GET'])
|
||||
def verify_dnssec_api(username):
|
||||
"""Verify DNSSEC delegation for a user"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
|
||||
# Users can only check their own DNSSEC, admins can check any
|
||||
if not user or (user.get('role') != 'admin' and user.get('username') != username):
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
|
||||
if not domain_manager:
|
||||
return jsonify({'error': 'Domain manager not available'}), 503
|
||||
|
||||
result = domain_manager.setup_dnssec_delegation(username)
|
||||
|
||||
return jsonify(result), 200 if result.get('success') else 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error verifying DNSSEC: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains', methods=['GET'])
|
||||
def get_domains_api():
|
||||
"""Get domains API endpoint"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
if not user:
|
||||
return jsonify({'error': 'Unauthorized'}), 401
|
||||
|
||||
include_serverless = request.args.get('include_serverless', 'true').lower() == 'true'
|
||||
domains = get_user_domains(user['id'], include_serverless)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'domains': domains,
|
||||
'count': len(domains)
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting domains: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains/sync', methods=['POST'])
|
||||
def sync_domains_api():
|
||||
"""Sync domains between database and DNS"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
if not user:
|
||||
return jsonify({'error': 'Unauthorized'}), 401
|
||||
|
||||
success = sync_user_domains_with_dns(user['id'])
|
||||
|
||||
if success:
|
||||
domains = get_user_domains(user['id'], True)
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Domains synced successfully',
|
||||
'domains': domains,
|
||||
'count': len(domains)
|
||||
}), 200
|
||||
else:
|
||||
return jsonify({'error': 'Failed to sync domains'}), 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error syncing domains: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains', methods=['POST'])
|
||||
def create_domain_api():
|
||||
"""Create domain API endpoint"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
if not user:
|
||||
return jsonify({'error': 'Unauthorized'}), 401
|
||||
|
||||
if not domain_manager:
|
||||
return jsonify({'error': 'Domain service not available'}), 503
|
||||
|
||||
data = request.get_json()
|
||||
subdomain = data.get('subdomain')
|
||||
server_id = data.get('serverId')
|
||||
|
||||
if not subdomain:
|
||||
return jsonify({'error': 'Subdomain name required'}), 400
|
||||
|
||||
# Check if subdomain is available
|
||||
availability_result = domain_manager.check_domain_availability(subdomain, user['username'])
|
||||
if not availability_result.get('available', False):
|
||||
return jsonify({'error': availability_result.get('message', 'Domain not available')}), 400
|
||||
|
||||
# Create the subdomain
|
||||
result = domain_manager.create_subdomain(user['username'], subdomain)
|
||||
|
||||
if result['success'] and result.get('domain_data'):
|
||||
# Save to database
|
||||
domain_record = {
|
||||
'user_id': user['id'],
|
||||
'subdomain': result['domain_data']['subdomain'],
|
||||
'full_domain': result['domain_data']['domain'],
|
||||
'record_type': result['domain_data']['record_type'],
|
||||
'ip_address': result['domain_data']['ip_address'],
|
||||
'ttl': result['domain_data']['ttl'],
|
||||
'server_id': server_id,
|
||||
'created_at': result['domain_data']['created_at']
|
||||
}
|
||||
|
||||
db_domain = create_domain_record(domain_record)
|
||||
|
||||
if db_domain:
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'domain': db_domain,
|
||||
'message': result['message']
|
||||
}), 201
|
||||
else:
|
||||
return jsonify({'error': 'Domain created in DNS but failed to save to database'}), 500
|
||||
else:
|
||||
return jsonify({'error': result.get('message', 'Failed to create domain')}), 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating domain: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains/<domain_id>', methods=['DELETE'])
|
||||
def delete_domain_api(domain_id):
|
||||
"""Delete domain API endpoint"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
if not user:
|
||||
return jsonify({'error': 'Unauthorized'}), 401
|
||||
|
||||
if not domain_manager:
|
||||
return jsonify({'error': 'Domain service not available'}), 503
|
||||
|
||||
# Get domain from database
|
||||
domain = get_domain_by_id(domain_id)
|
||||
if not domain or domain['user_id'] != user['id']:
|
||||
return jsonify({'error': 'Domain not found or access denied'}), 404
|
||||
|
||||
# Delete from DNS
|
||||
result = domain_manager.delete_subdomain(user['username'], domain['subdomain'])
|
||||
|
||||
if result['success']:
|
||||
# Delete from database
|
||||
if delete_domain_record(domain_id):
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': result['message']
|
||||
}), 200
|
||||
else:
|
||||
return jsonify({'error': 'Domain deleted from DNS but failed to delete from database'}), 500
|
||||
else:
|
||||
return jsonify({'error': result.get('message', 'Failed to delete domain')}), 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting domain: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains/<domain_id>/link', methods=['POST'])
|
||||
def link_domain_api(domain_id):
|
||||
"""Link domain to server API endpoint"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
if not user:
|
||||
return jsonify({'error': 'Unauthorized'}), 401
|
||||
|
||||
data = request.get_json()
|
||||
server_id = data.get('serverId')
|
||||
|
||||
if not server_id:
|
||||
return jsonify({'error': 'Server ID required'}), 400
|
||||
|
||||
# Verify domain belongs to user
|
||||
domain = get_domain_by_id(domain_id)
|
||||
if not domain or domain['user_id'] != user['id']:
|
||||
return jsonify({'error': 'Domain not found or access denied'}), 404
|
||||
|
||||
# Verify server belongs to user
|
||||
server = get_server_by_id(server_id)
|
||||
if not server or server['owner_id'] != user['id']:
|
||||
return jsonify({'error': 'Server not found or access denied'}), 404
|
||||
|
||||
# Check if server is a website or VPS
|
||||
if server['type'] not in ['website', 'vps']:
|
||||
return jsonify({'error': 'Domain can only be linked to Website or VPS servers'}), 400
|
||||
|
||||
# Link domain to server (this will create IngressRoute)
|
||||
if link_domain_to_server(domain_id, server_id):
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'Domain linked to server {server["name"]} with IngressRoute created'
|
||||
}), 200
|
||||
else:
|
||||
return jsonify({'error': 'Failed to link domain'}), 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error linking domain: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains/<domain_id>/unlink', methods=['POST'])
|
||||
def unlink_domain_api(domain_id):
|
||||
"""Unlink domain from server API endpoint"""
|
||||
try:
|
||||
token = get_bearer_token()
|
||||
user = authenticate_user(token)
|
||||
if not user:
|
||||
return jsonify({'error': 'Unauthorized'}), 401
|
||||
|
||||
# Verify domain belongs to user
|
||||
domain = get_domain_by_id(domain_id)
|
||||
if not domain or domain['user_id'] != user['id']:
|
||||
return jsonify({'error': 'Domain not found or access denied'}), 404
|
||||
|
||||
# Unlink domain from server (this will delete IngressRoute)
|
||||
if unlink_domain_from_server(domain_id):
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Domain unlinked from server and IngressRoute removed'
|
||||
}), 200
|
||||
else:
|
||||
return jsonify({'error': 'Failed to unlink domain'}), 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error unlinking domain: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/api/domains/test', methods=['GET'])
|
||||
def test_domain_api():
|
||||
"""Test domain API connection"""
|
||||
if not require_admin():
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
try:
|
||||
if not domain_manager:
|
||||
return jsonify({'success': False, 'message': 'Domain manager not initialized'}), 503
|
||||
|
||||
success = domain_manager.test_connection()
|
||||
|
||||
return jsonify({
|
||||
'success': success,
|
||||
'message': 'Domain API connection test completed',
|
||||
'connected': success
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error testing domain API: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
Reference in new issue
Block a user