From dbc05728a740b64625d83e0ecfdc62a2b1f55605 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 16 Feb 2026 14:39:46 +0100 Subject: [PATCH] CloudFlare DNS: edit records on click (name, type, TTL, value, priority, proxy) - Add updateDNSRecordCloudFlare backend (dnsManager, view, URL) - Return real priority in getCurrentRecordsForDomainCloudFlare - Edit (pencil) button + modal with all fields; Save calls update API - openEditModal, closeEditModal, saveEditRecord in dns.js --- dns/dnsManager.py | 66 +++++++++++++++- .../dns/addDeleteDNSRecordsCloudFlare.html | 75 +++++++++++++++++++ dns/urls.py | 1 + dns/views.py | 9 +++ public/static/dns/dns.js | 48 ++++++++++++ static/dns/dns.js | 47 ++++++++++++ 6 files changed, 245 insertions(+), 1 deletion(-) diff --git a/dns/dnsManager.py b/dns/dnsManager.py index 83d17706b..45874d1e7 100644 --- a/dns/dnsManager.py +++ b/dns/dnsManager.py @@ -775,11 +775,14 @@ class DNSManager: else: ttl = dns_record['ttl'] + prio = dns_record.get('priority', 0) + if prio is None: + prio = 0 dic = {'id': dns_record['id'], 'type': dns_record['type'], 'name': dns_record['name'], 'content': dns_record['content'], - 'priority': '1400', + 'priority': str(prio), 'ttl': ttl, 'proxy': dns_record['proxied'], 'proxiable': dns_record['proxiable'] @@ -844,6 +847,67 @@ class DNSManager: final_json = json.dumps(final_dic) return HttpResponse(final_json) + def updateDNSRecordCloudFlare(self, userID=None, data=None): + """Update an existing CloudFlare DNS record (name, type, ttl, content, priority, proxied).""" + try: + currentACL = ACLManager.loadedACL(userID) + if ACLManager.currentContextPermission(currentACL, 'addDeleteRecords') == 0: + return ACLManager.loadErrorJson('update_status', 0) + + zone_domain = data['selectedZone'] + record_id = data['id'] + name = (data.get('name') or '').strip() + record_type = (data.get('recordType') or data.get('type') or '').strip() + content = (data.get('content') or '').strip() + ttl_val = data.get('ttl') + priority = data.get('priority', 0) + proxied = data.get('proxied', False) + + if not name or not record_type or not content: + final_json = json.dumps({'status': 0, 'update_status': 0, 'error_message': 'Name, type and content are required.'}) + return HttpResponse(final_json) + + try: + ttl_int = int(ttl_val) if ttl_val not in (None, '', 'AUTO') else 1 + except (ValueError, TypeError): + ttl_int = 1 + if ttl_int < 0: + ttl_int = 1 + elif ttl_int > 86400 and ttl_int != 1: + ttl_int = 86400 + + try: + priority_int = int(priority) if priority not in (None, '') else 0 + except (ValueError, TypeError): + priority_int = 0 + + admin = Administrator.objects.get(pk=userID) + self.admin = admin + if ACLManager.checkOwnershipZone(zone_domain, admin, currentACL) != 1: + return ACLManager.loadErrorJson() + + self.loadCFKeys() + params = {'name': zone_domain, 'per_page': 50} + cf = CloudFlare.CloudFlare(email=self.email, token=self.key) + zones = cf.zones.get(params=params) + zone_list = sorted(zones, key=lambda v: v['name']) + if not zone_list: + final_json = json.dumps({'status': 0, 'update_status': 0, 'error_message': 'Zone not found.'}) + return HttpResponse(final_json) + zone_id = zone_list[0]['id'] + + update_data = {'name': name, 'type': record_type, 'content': content, 'ttl': ttl_int, 'priority': priority_int} + if record_type in ['A', 'CNAME']: + update_data['proxied'] = bool(proxied) + + cf.zones.dns_records.put(zone_id, record_id, data=update_data) + final_dic = {'status': 1, 'update_status': 1, 'error_message': 'None'} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + except BaseException as msg: + final_dic = {'status': 0, 'update_status': 0, 'error_message': str(msg)} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) def addDNSRecordCloudFlare(self, userID = None, data = None): try: diff --git a/dns/templates/dns/addDeleteDNSRecordsCloudFlare.html b/dns/templates/dns/addDeleteDNSRecordsCloudFlare.html index 09a90bcf8..d288dd79a 100644 --- a/dns/templates/dns/addDeleteDNSRecordsCloudFlare.html +++ b/dns/templates/dns/addDeleteDNSRecordsCloudFlare.html @@ -203,6 +203,27 @@ background: var(--bg-secondary, #f8f9ff); border-color: #5b5fcf; } + + .edit-record-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + } + .edit-record-modal { + background: var(--bg-primary, white); + border-radius: 12px; + padding: 2rem; + max-width: 480px; + width: 90%; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + } .alert { padding: 1rem 1.5rem; @@ -899,6 +920,10 @@ type="checkbox"> + + + +
+
+

+ {% trans "Edit DNS Record" %} +

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
diff --git a/dns/urls.py b/dns/urls.py index 00f019f68..2ca5850c2 100644 --- a/dns/urls.py +++ b/dns/urls.py @@ -27,6 +27,7 @@ urlpatterns = [ re_path(r'^getCurrentRecordsForDomainCloudFlare$', views.getCurrentRecordsForDomainCloudFlare, name='getCurrentRecordsForDomainCloudFlare'), re_path(r'^deleteDNSRecordCloudFlare$', views.deleteDNSRecordCloudFlare, name='deleteDNSRecordCloudFlare'), re_path(r'^addDNSRecordCloudFlare$', views.addDNSRecordCloudFlare, name='addDNSRecordCloudFlare'), + re_path(r'^updateDNSRecordCloudFlare$', views.updateDNSRecordCloudFlare, name='updateDNSRecordCloudFlare'), re_path(r'^syncCF$', views.syncCF, name='syncCF'), re_path(r'^enableProxy$', views.enableProxy, name='enableProxy'), ] diff --git a/dns/views.py b/dns/views.py index de628f894..3a19fa540 100644 --- a/dns/views.py +++ b/dns/views.py @@ -339,6 +339,15 @@ def addDNSRecordCloudFlare(request): return redirect(loadLoginPage) +def updateDNSRecordCloudFlare(request): + try: + userID = request.session['userID'] + dm = DNSManager() + return dm.updateDNSRecordCloudFlare(userID, json.loads(request.body)) + except KeyError: + return redirect(loadLoginPage) + + def syncCF(request): try: userID = request.session['userID'] diff --git a/public/static/dns/dns.js b/public/static/dns/dns.js index 18cc88645..830113996 100644 --- a/public/static/dns/dns.js +++ b/public/static/dns/dns.js @@ -811,6 +811,9 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window $scope.couldNotDeleteRecords = true; $scope.couldNotAddRecord = true; $scope.recordValueDefault = false; + $scope.records = []; + $scope.showEditModal = false; + $scope.editRecord = {}; // Hide records boxes $(".aaaaRecord").hide(); @@ -1135,6 +1138,51 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window }; + $scope.openEditModal = function (record) { + $scope.editRecord = { + id: record.id, + name: record.name, + type: record.type, + ttl: record.ttl, + content: record.content, + priority: record.priority || 0, + proxy: record.proxy, + proxiable: record.proxiable + }; + $scope.showEditModal = true; + }; + + $scope.closeEditModal = function () { + $scope.showEditModal = false; + }; + + $scope.saveEditRecord = function () { + var url = "/dns/updateDNSRecordCloudFlare"; + var data = { + selectedZone: $scope.selectedZone, + id: $scope.editRecord.id, + name: $scope.editRecord.name, + recordType: $scope.editRecord.type, + content: $scope.editRecord.content, + ttl: $scope.editRecord.ttl === 'AUTO' || $scope.editRecord.ttl === 1 ? 1 : parseInt($scope.editRecord.ttl, 10) || 3600, + priority: parseInt($scope.editRecord.priority, 10) || 0, + proxied: $scope.editRecord.proxy + }; + var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } }; + $http.post(url, data, config).then(function (response) { + if (response.data.update_status === 1) { + $scope.closeEditModal(); + populateCurrentRecords(); + new PNotify({ title: 'Success', text: 'Record updated.', type: 'success' }); + } else { + $scope.errorMessage = response.data.error_message || 'Update failed'; + new PNotify({ title: 'Error', text: $scope.errorMessage, type: 'error' }); + } + }, function () { + new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' }); + }); + }; + $scope.syncCF = function () { $scope.recordsLoading = false; diff --git a/static/dns/dns.js b/static/dns/dns.js index b7a36b268..0018a9683 100644 --- a/static/dns/dns.js +++ b/static/dns/dns.js @@ -813,6 +813,8 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window $scope.couldNotAddRecord = true; $scope.recordValueDefault = false; $scope.records = []; + $scope.showEditModal = false; + $scope.editRecord = {}; // Hide records boxes $(".aaaaRecord").hide(); @@ -1140,6 +1142,51 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window }; + $scope.openEditModal = function (record) { + $scope.editRecord = { + id: record.id, + name: record.name, + type: record.type, + ttl: record.ttl, + content: record.content, + priority: record.priority || 0, + proxy: record.proxy, + proxiable: record.proxiable + }; + $scope.showEditModal = true; + }; + + $scope.closeEditModal = function () { + $scope.showEditModal = false; + }; + + $scope.saveEditRecord = function () { + var url = "/dns/updateDNSRecordCloudFlare"; + var data = { + selectedZone: $scope.selectedZone, + id: $scope.editRecord.id, + name: $scope.editRecord.name, + recordType: $scope.editRecord.type, + content: $scope.editRecord.content, + ttl: $scope.editRecord.ttl === 'AUTO' || $scope.editRecord.ttl === 1 ? 1 : parseInt($scope.editRecord.ttl, 10) || 3600, + priority: parseInt($scope.editRecord.priority, 10) || 0, + proxied: $scope.editRecord.proxy + }; + var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } }; + $http.post(url, data, config).then(function (response) { + if (response.data.update_status === 1) { + $scope.closeEditModal(); + populateCurrentRecords(); + new PNotify({ title: 'Success', text: 'Record updated.', type: 'success' }); + } else { + $scope.errorMessage = response.data.error_message || 'Update failed'; + new PNotify({ title: 'Error', text: $scope.errorMessage, type: 'error' }); + } + }, function () { + new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' }); + }); + }; + $scope.syncCF = function () { $scope.recordsLoading = false;