Fix CloudFlare DNS Management: Filter main domains only, auto-delete DNS records on domain removal, improve table display

- Filter domain dropdown to show only main domains (exclude sub-domains)
- Add automatic CloudFlare DNS record deletion when domains/sub-domains are removed
- Improve DNS Records table display to match SSH Logins/Logs table styling
- Add loading states and proper table structure with ng-if conditions
- Update CSS to match activity-table styling with sticky headers
This commit is contained in:
master3395
2026-01-04 02:13:10 +01:00
parent d8dbe6e410
commit cfee3d9867
6 changed files with 264 additions and 24 deletions

View File

@@ -839,6 +839,102 @@ class DNS:
## There does not exist a zone for this domain.
pass
@staticmethod
def deleteCloudFlareDNSRecords(domainName, adminUserName=None):
"""
Delete all CloudFlare DNS records for a domain when domain is removed from CyberPanel.
This function is called automatically when domains/sub-domains are deleted.
"""
try:
# Check if CloudFlare is configured for this admin user
if adminUserName:
cfFile = '%s%s' % (DNS.CFPath, adminUserName)
else:
# Try to find admin user from domain
try:
from loginSystem.models import Administrator
from websiteFunctions.models import Websites, ChildDomains
try:
website = Websites.objects.get(domain=domainName)
adminUserName = website.admin.userName
except:
try:
childDomain = ChildDomains.objects.get(domain=domainName)
adminUserName = childDomain.master.admin.userName
except:
return 0, "Could not find admin user for domain"
cfFile = '%s%s' % (DNS.CFPath, adminUserName)
except:
return 0, "Could not determine admin user"
if not os.path.exists(cfFile):
# CloudFlare not configured for this user, skip deletion
return 1, "CloudFlare not configured"
# Load CloudFlare credentials
data = open(cfFile, 'r').readlines()
email = data[0].rstrip('\n')
token = data[1].rstrip('\n')
# Initialize CloudFlare API
cf = CloudFlare.CloudFlare(email=email, token=token)
try:
# Find the zone for this domain
params = {'name': domainName, 'per_page': 50}
zones = cf.zones.get(params=params)
for zone in sorted(zones, key=lambda v: v['name']):
if zone['name'] == domainName:
zone_id = zone['id']
# Get all DNS records for this zone
try:
dns_records = cf.zones.dns_records.get(zone_id)
# Delete all DNS records
deleted_count = 0
for record in dns_records:
try:
cf.zones.dns_records.delete(zone_id, record['id'])
deleted_count += 1
except Exception as e:
logging.CyberCPLogFileWriter.writeToFile(
f'Error deleting CloudFlare DNS record {record["id"]} for {domainName}: {str(e)}')
if deleted_count > 0:
logging.CyberCPLogFileWriter.writeToFile(
f'Deleted {deleted_count} CloudFlare DNS records for {domainName}')
return 1, f"Deleted {deleted_count} DNS records"
else:
return 1, "No DNS records found to delete"
except CloudFlare.exceptions.CloudFlareAPIError as e:
logging.CyberCPLogFileWriter.writeToFile(
f'CloudFlare API error deleting DNS records for {domainName}: {str(e)}')
return 0, str(e)
except Exception as e:
logging.CyberCPLogFileWriter.writeToFile(
f'Error getting CloudFlare DNS records for {domainName}: {str(e)}')
return 0, str(e)
# Zone not found in CloudFlare
return 1, "Domain not found in CloudFlare"
except CloudFlare.exceptions.CloudFlareAPIError as e:
logging.CyberCPLogFileWriter.writeToFile(
f'CloudFlare API error for {domainName}: {str(e)}')
return 0, str(e)
except Exception as e:
logging.CyberCPLogFileWriter.writeToFile(
f'Error deleting CloudFlare DNS records for {domainName}: {str(e)}')
return 0, str(e)
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
f'Error in deleteCloudFlareDNSRecords for {domainName}: {str(msg)}')
return 0, str(msg)
@staticmethod
def createDNSZone(virtualHostName, admin):
try:

View File

@@ -398,6 +398,12 @@ class vhost:
delWebsite = Websites.objects.get(domain=virtualHostName)
externalApp = delWebsite.externalApp
# Get admin user name for CloudFlare cleanup
adminUserName = None
try:
adminUserName = delWebsite.admin.userName
except:
pass
##
@@ -411,6 +417,14 @@ class vhost:
numberOfSites = Websites.objects.count() + ChildDomains.objects.count()
vhost.deleteCoreConf(items.domain, numberOfSites)
# Delete CloudFlare DNS records for child domain
try:
DNS.deleteCloudFlareDNSRecords(items.domain, adminUserName)
except Exception as cfError:
# Log error but don't fail deletion if CloudFlare deletion fails
logging.CyberCPLogFileWriter.writeToFile(
f'CloudFlare DNS deletion failed for child domain {items.domain}: {str(cfError)}')
### Delete ACME Folder
if os.path.exists('/root/.acme.sh/%s' % (items.domain)):
@@ -455,6 +469,14 @@ class vhost:
for items in databases:
mysqlUtilities.deleteDatabase(items.dbName, items.dbUser)
# Delete CloudFlare DNS records for main domain before deletion
try:
DNS.deleteCloudFlareDNSRecords(virtualHostName, adminUserName)
except Exception as cfError:
# Log error but don't fail deletion if CloudFlare deletion fails
logging.CyberCPLogFileWriter.writeToFile(
f'CloudFlare DNS deletion failed for {virtualHostName}: {str(cfError)}')
delWebsite.delete()
## Deleting DNS Zone if there is any.

View File

@@ -1834,6 +1834,22 @@ local_name %s {
vhost.deleteCoreConf(virtualHostName, numberOfWebsites)
delWebsite = ChildDomains.objects.get(domain=virtualHostName)
# Get admin user name before deletion for CloudFlare cleanup
adminUserName = None
try:
adminUserName = delWebsite.master.admin.userName
except:
pass
# Delete CloudFlare DNS records for this domain
try:
from plogical.dnsUtilities import DNS
DNS.deleteCloudFlareDNSRecords(virtualHostName, adminUserName)
except Exception as cfError:
# Log error but don't fail domain deletion if CloudFlare deletion fails
logging.CyberCPLogFileWriter.writeToFile(
f'CloudFlare DNS deletion failed for {virtualHostName}: {str(cfError)}')
if DeleteDocRoot:
command = 'rm -rf %s' % (delWebsite.path)
ProcessUtilities.executioner(command)