mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-02-17 12:06:47 +01:00
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
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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">
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
<i class="fas fa-edit edit-icon"
|
||||
style="color: #5b5fcf; cursor: pointer; margin-right: 10px;"
|
||||
ng-click="openEditModal(record)"
|
||||
title="{% trans 'Edit Record' %}"></i>
|
||||
<i class="fas fa-trash delete-icon"
|
||||
style="color: #ef4444; cursor: pointer;"
|
||||
ng-click="deleteRecord(record.id)"
|
||||
@@ -937,6 +962,56 @@
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Edit DNS Record Modal -->
|
||||
<div class="edit-record-overlay" ng-show="showEditModal" ng-click="closeEditModal()">
|
||||
<div class="edit-record-modal" ng-click="$event.stopPropagation()">
|
||||
<h4 class="mb-4" style="color: var(--text-primary, #1e293b); font-weight: 600;">
|
||||
<i class="fas fa-edit"></i> {% trans "Edit DNS Record" %}
|
||||
</h4>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{% trans "Name" %}</label>
|
||||
<input type="text" class="form-control" ng-model="editRecord.name" placeholder="e.g. www or @">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{% trans "Type" %}</label>
|
||||
<select class="form-control" ng-model="editRecord.type">
|
||||
<option value="A">A</option>
|
||||
<option value="AAAA">AAAA</option>
|
||||
<option value="CNAME">CNAME</option>
|
||||
<option value="MX">MX</option>
|
||||
<option value="TXT">TXT</option>
|
||||
<option value="NS">NS</option>
|
||||
<option value="SOA">SOA</option>
|
||||
<option value="SRV">SRV</option>
|
||||
<option value="CAA">CAA</option>
|
||||
<option value="SPF">SPF</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{% trans "TTL" %}</label>
|
||||
<input type="text" class="form-control" ng-model="editRecord.ttl" placeholder="3600 or AUTO">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{% trans "Value / Content" %}</label>
|
||||
<input type="text" class="form-control" ng-model="editRecord.content" placeholder="Record value">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{% trans "Priority" %}</label>
|
||||
<input type="number" class="form-control" ng-model="editRecord.priority" placeholder="0">
|
||||
</div>
|
||||
<div class="form-group" ng-if="editRecord.proxiable">
|
||||
<label class="form-label">{% trans "Proxy (orange cloud)" %}</label>
|
||||
<input type="checkbox" ng-model="editRecord.proxy" style="margin-left: 8px;">
|
||||
</div>
|
||||
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 1.5rem;">
|
||||
<button type="button" class="btn-secondary" ng-click="closeEditModal()">{% trans "Cancel" %}</button>
|
||||
<button type="button" class="btn-primary" ng-click="saveEditRecord()">
|
||||
<i class="fas fa-save"></i> {% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alert Messages -->
|
||||
<div style="margin-top: 2rem;">
|
||||
|
||||
@@ -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'),
|
||||
]
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user