mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-05-06 00:16:52 +02:00
DNS CloudFlare: delete confirmation, clear all, restore, export/import, orphan check
- Delete record: confirmation dialog and local backup before delete - Clear all DNS records: double confirmation (zone name), local backup, Restore button - Export/Import DNS records (JSON) for zone - Check orphan DNS: find A/AAAA/CNAME for hostnames no longer in panel, remove with backup - Backend: getExportRecordsCloudFlare, clearAllDNSRecordsCloudFlare, importDNSRecordsCloudFlare, getStaleDNSRecordsCloudFlare, removeStaleDNSRecordsCloudFlare
This commit is contained in:
@@ -732,6 +732,22 @@ app.controller('configureDefaultNameservers', function ($scope, $http) {
|
||||
|
||||
/* Java script code for CloudFlare */
|
||||
|
||||
app.directive('cfImportFile', function () {
|
||||
return {
|
||||
link: function (scope, element) {
|
||||
element.on('change', function (ev) {
|
||||
var files = ev.target && ev.target.files;
|
||||
if (files && files.length && scope.onImportFile) {
|
||||
scope.$apply(function () {
|
||||
scope.onImportFile(files);
|
||||
});
|
||||
}
|
||||
ev.target.value = '';
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.filter('dnsRecordSearch', function () {
|
||||
return function (records, searchText) {
|
||||
if (!records || !Array.isArray(records)) return records;
|
||||
@@ -828,6 +844,13 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.couldNotAddRecord = true;
|
||||
$scope.recordValueDefault = false;
|
||||
$scope.records = [];
|
||||
$scope.cfDeletedBackup = {};
|
||||
$scope.exportLoading = false;
|
||||
$scope.clearAllLoading = false;
|
||||
$scope.restoreLoading = false;
|
||||
$scope.staleRecords = [];
|
||||
$scope.staleModalVisible = false;
|
||||
$scope.staleLoading = false;
|
||||
$scope.showEditModal = false;
|
||||
$scope.editRecord = {};
|
||||
|
||||
@@ -1083,6 +1106,30 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
|
||||
}
|
||||
|
||||
$scope.confirmDeleteRecord = function (record) {
|
||||
var msg = 'Delete DNS record?\n\nName: ' + (record.name || '') + '\nType: ' + (record.type || '') + '\nValue: ' + (record.content || '');
|
||||
if (!$window.confirm(msg)) {
|
||||
return;
|
||||
}
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) {
|
||||
return;
|
||||
}
|
||||
if (!$scope.cfDeletedBackup[zone]) {
|
||||
$scope.cfDeletedBackup[zone] = [];
|
||||
}
|
||||
$scope.cfDeletedBackup[zone].push({
|
||||
type: record.type,
|
||||
name: record.name,
|
||||
content: record.content,
|
||||
priority: parseInt(record.priority, 10) || 0,
|
||||
ttl: record.ttlNum || record.ttl || 3600,
|
||||
proxy: record.proxy,
|
||||
proxiable: record.proxiable !== false
|
||||
});
|
||||
$scope.deleteRecord(record.id);
|
||||
};
|
||||
|
||||
$scope.deleteRecord = function (id) {
|
||||
|
||||
|
||||
@@ -1168,6 +1215,198 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
|
||||
};
|
||||
|
||||
$scope.hasBackupForZone = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return false;
|
||||
var list = $scope.cfDeletedBackup[zone];
|
||||
return list && list.length > 0;
|
||||
};
|
||||
|
||||
$scope.confirmClearAll = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return;
|
||||
var msg1 = 'This will remove ALL DNS records for this zone in CloudFlare. This action cannot be undone on CloudFlare.\n\nA local copy will be kept so you can use Restore.\n\nContinue?';
|
||||
if (!$window.confirm(msg1)) return;
|
||||
var msg2 = 'Type the zone name below to confirm:\n\n' + zone;
|
||||
var typed = $window.prompt(msg2);
|
||||
if (typed === null) return;
|
||||
if (typed.trim() !== zone) {
|
||||
new PNotify({ title: 'Cancelled', text: 'Zone name did not match. No records were deleted.', type: 'warning' });
|
||||
return;
|
||||
}
|
||||
$scope.clearAllLoading = true;
|
||||
url = '/dns/clearAllDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.clearAllLoading = false;
|
||||
if (response.data.delete_status === 1 && response.data.deleted_records) {
|
||||
$scope.cfDeletedBackup[zone] = response.data.deleted_records;
|
||||
$scope.canNotFetchRecords = true;
|
||||
$scope.recordsFetched = false;
|
||||
$scope.recordDeleted = false;
|
||||
populateCurrentRecords();
|
||||
new PNotify({ title: 'Done', text: 'All DNS records were deleted. Use Restore to undo.', type: 'success' });
|
||||
} else {
|
||||
$scope.errorMessage = response.data.error_message || 'Clear all failed';
|
||||
new PNotify({ title: 'Error', text: $scope.errorMessage, type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.clearAllLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.restoreFromBackup = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
var list = $scope.cfDeletedBackup[zone];
|
||||
if (!zone || !list || list.length === 0) return;
|
||||
$scope.restoreLoading = true;
|
||||
url = '/dns/importDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone, records: list };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.restoreLoading = false;
|
||||
if (response.data.import_status === 1) {
|
||||
$scope.cfDeletedBackup[zone] = [];
|
||||
populateCurrentRecords();
|
||||
var failed = response.data.failed || [];
|
||||
var msg = response.data.imported + ' record(s) restored.';
|
||||
if (failed.length) msg += ' ' + failed.length + ' failed.';
|
||||
new PNotify({ title: 'Restore done', text: msg, type: failed.length ? 'warning' : 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Restore failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.restoreLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.exportRecords = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return;
|
||||
$scope.exportLoading = true;
|
||||
url = '/dns/getExportRecordsCloudFlare';
|
||||
var data = { selectedZone: zone };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.exportLoading = false;
|
||||
if (response.data.fetchStatus === 1 && response.data.data) {
|
||||
var arr = typeof response.data.data === 'string' ? JSON.parse(response.data.data) : response.data.data;
|
||||
var blob = new Blob([JSON.stringify(arr, null, 2)], { type: 'application/json' });
|
||||
var a = document.createElement('a');
|
||||
a.href = (window.URL || window.webkitURL).createObjectURL(blob);
|
||||
a.download = 'dns-records-' + zone.replace(/\./g, '-') + '.json';
|
||||
a.click();
|
||||
if (a.href) (window.URL || window.webkitURL).revokeObjectURL(a.href);
|
||||
new PNotify({ title: 'Export done', text: 'DNS records downloaded.', type: 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Export failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.exportLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.onImportFile = function (files) {
|
||||
if (!files || !files.length) return;
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) {
|
||||
new PNotify({ title: 'Error', text: 'Select a zone first.', type: 'error' });
|
||||
return;
|
||||
}
|
||||
var file = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
var text = e.target && e.target.result;
|
||||
if (!text) {
|
||||
new PNotify({ title: 'Error', text: 'Could not read file.', type: 'error' });
|
||||
return;
|
||||
}
|
||||
var arr;
|
||||
try {
|
||||
arr = JSON.parse(text);
|
||||
} catch (err) {
|
||||
new PNotify({ title: 'Error', text: 'Invalid JSON: ' + (err.message || ''), type: 'error' });
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(arr)) {
|
||||
if (arr && Array.isArray(arr.records)) arr = arr.records;
|
||||
else if (arr && arr.data) arr = Array.isArray(arr.data) ? arr.data : [arr.data];
|
||||
else arr = [arr];
|
||||
}
|
||||
url = '/dns/importDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone, records: arr };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
if (response.data.import_status === 1) {
|
||||
populateCurrentRecords();
|
||||
var failed = response.data.failed || [];
|
||||
var msg = response.data.imported + ' record(s) imported.';
|
||||
if (failed.length) msg += ' ' + failed.length + ' failed.';
|
||||
new PNotify({ title: 'Import done', text: msg, type: failed.length ? 'warning' : 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Import failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
reader.readAsText(file, 'UTF-8');
|
||||
};
|
||||
|
||||
$scope.checkStaleRecords = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return;
|
||||
$scope.staleLoading = true;
|
||||
url = '/dns/getStaleDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.staleLoading = false;
|
||||
if (response.data.fetchStatus === 1) {
|
||||
$scope.staleRecords = response.data.stale_records || [];
|
||||
$scope.staleModalVisible = true;
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Could not fetch stale records', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.staleLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.closeStaleModal = function () {
|
||||
$scope.staleModalVisible = false;
|
||||
$scope.staleRecords = [];
|
||||
};
|
||||
|
||||
$scope.removeStaleRecords = function () {
|
||||
if (!$scope.staleRecords || $scope.staleRecords.length === 0) return;
|
||||
var zone = $scope.selectedZone;
|
||||
var msg = 'Remove ' + $scope.staleRecords.length + ' orphan DNS record(s)? A local copy will be kept for Restore.';
|
||||
if (!$window.confirm(msg)) return;
|
||||
var ids = $scope.staleRecords.map(function (r) { return r.id; });
|
||||
url = '/dns/removeStaleDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone, ids: ids };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
if (response.data.delete_status === 1 && response.data.deleted_records) {
|
||||
if (!$scope.cfDeletedBackup[zone]) $scope.cfDeletedBackup[zone] = [];
|
||||
$scope.cfDeletedBackup[zone] = $scope.cfDeletedBackup[zone].concat(response.data.deleted_records);
|
||||
$scope.closeStaleModal();
|
||||
populateCurrentRecords();
|
||||
new PNotify({ title: 'Done', text: response.data.deleted_records.length + ' orphan record(s) removed. Use Restore to undo.', type: 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Remove failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.dnsTypeList = ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SOA', 'SRV', 'CAA', 'SPF', 'DNSKEY', 'CDNSKEY', 'HTTPS', 'SVCB', 'URI', 'LOC', 'NAPTR', 'SMIMEA', 'SSHFP', 'TLSA', 'PTR'];
|
||||
$scope.getTypeOptions = function (record) {
|
||||
var list = angular.copy($scope.dnsTypeList);
|
||||
|
||||
Reference in New Issue
Block a user