From 6653dbb2e2357462d22685a06f688f1fb02ed3cd Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Sun, 28 Feb 2021 09:35:40 -0500 Subject: [PATCH] Sort the Custom DNS by zone and qname, and add an option to go back to the old sort order (creation order) Update the zone grouping style on the users and aliases page to match. Fixes #1927 --- CHANGELOG.md | 1 + management/daemon.py | 55 ++++++++++++++++++++++------ management/dns_update.py | 4 +- management/templates/aliases.html | 4 +- management/templates/custom-dns.html | 48 ++++++++++++++---------- management/templates/users.html | 5 +-- 6 files changed, 80 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fd456b..91d1d82d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Control panel: * Backblaze B2 is now a supported backup protocol. * Fixed an issue in the daily mail reports. +* Sort the Custom DNS by zone and qname, and add an option to go back to the old sort order (creation order). Mail: diff --git a/management/daemon.py b/management/daemon.py index a0cfefa6..8490ee44 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -277,17 +277,50 @@ def dns_set_secondary_nameserver(): @app.route('/dns/custom') @authorized_personnel_only def dns_get_records(qname=None, rtype=None): - from dns_update import get_custom_dns_config - return json_response([ - { - "qname": r[0], - "rtype": r[1], - "value": r[2], - } - for r in get_custom_dns_config(env) - if r[0] != "_secondary_nameserver" - and (not qname or r[0] == qname) - and (not rtype or r[1] == rtype) ]) + # Get the current set of custom DNS records. + from dns_update import get_custom_dns_config, get_dns_zones + records = get_custom_dns_config(env, only_real_records=True) + + # Filter per the arguments for the more complex GET routes below. + records = [r for r in records + if (not qname or r[0] == qname) + and (not rtype or r[1] == rtype) ] + + # Make a better data structure. + records = [ + { + "qname": r[0], + "rtype": r[1], + "value": r[2], + "sort-order": { }, + } for r in records ] + + # To help with grouping by zone in qname sorting, label each record with which zone it is in. + # There's an inconsistency in how we handle zones in get_dns_zones and in sort_domains, so + # do this first before sorting the domains within the zones. + zones = utils.sort_domains([z[0] for z in get_dns_zones(env)], env) + for r in records: + for z in zones: + if r["qname"] == z or r["qname"].endswith("." + z): + r["zone"] = z + break + + # Add sorting information. The 'created' order follows the order in the YAML file on disk, + # which tracs the order entries were added in the control panel since we append to the end. + # The 'qname' sort order sorts by our standard domain name sort (by zone then by qname), + # then by rtype, and last by the original order in the YAML file (since sorting by value + # may not make sense, unless we parse IP addresses, for example). + for i, r in enumerate(records): + r["sort-order"]["created"] = i + domain_sort_order = utils.sort_domains([r["qname"] for r in records], env) + for i, r in enumerate(sorted(records, key = lambda r : ( + zones.index(r["zone"]), + domain_sort_order.index(r["qname"]), + r["rtype"]))): + r["sort-order"]["qname"] = i + + # Return. + return json_response(records) @app.route('/dns/custom/', methods=['GET', 'POST', 'PUT', 'DELETE']) @app.route('/dns/custom//', methods=['GET', 'POST', 'PUT', 'DELETE']) diff --git a/management/dns_update.py b/management/dns_update.py index 781fb1dc..b2901bc8 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -753,7 +753,7 @@ def write_opendkim_tables(domains, env): ######################################################################## -def get_custom_dns_config(env): +def get_custom_dns_config(env, only_real_records=False): try: custom_dns = rtyaml.load(open(os.path.join(env['STORAGE_ROOT'], 'dns/custom.yaml'))) if not isinstance(custom_dns, dict): raise ValueError() # caught below @@ -761,6 +761,8 @@ def get_custom_dns_config(env): return [ ] for qname, value in custom_dns.items(): + if qname == "_secondary_nameserver" and only_real_records: continue # skip fake record + # Short form. Mapping a domain name to a string is short-hand # for creating A records. if isinstance(value, str): diff --git a/management/templates/aliases.html b/management/templates/aliases.html index 848fcf49..3d37c4fd 100644 --- a/management/templates/aliases.html +++ b/management/templates/aliases.html @@ -153,8 +153,8 @@ function show_aliases() { function(r) { $('#alias_table tbody').html(""); for (var i = 0; i < r.length; i++) { - var hdr = $("

"); - hdr.find('h4').text(r[i].domain); + var hdr = $(""); + hdr.find('th').text(r[i].domain); $('#alias_table tbody').append(hdr); for (var k = 0; k < r[i].aliases.length; k++) { diff --git a/management/templates/custom-dns.html b/management/templates/custom-dns.html index b1b98b9b..c59624eb 100644 --- a/management/templates/custom-dns.html +++ b/management/templates/custom-dns.html @@ -57,7 +57,13 @@ - +
+ sort by: + domain name + | + created +
+ @@ -192,36 +198,38 @@ function show_current_custom_dns() { $('#custom-dns-current').fadeIn(); else $('#custom-dns-current').fadeOut(); - - var reverse_fqdn = function(el) { - el.qname = el.qname.split('.').reverse().join('.'); - return el; - } - var sort = function(a, b) { - if(a.qname === b.qname) { - if(a.rtype === b.rtype) { - return a.value > b.value ? 1 : -1; - } - return a.rtype > b.rtype ? 1 : -1; - } - return a.qname > b.qname ? 1 : -1; - } + window.miab_custom_dns_data = data; + show_current_custom_dns_update_after_sort(); + }); +} - data = data.map(reverse_fqdn).sort(sort).map(reverse_fqdn); +function show_current_custom_dns_update_after_sort() { + var data = window.miab_custom_dns_data; + var sort_key = window.miab_custom_dns_data_sort_order || "qname"; - $('#custom-dns-current').find("tbody").text(''); + data.sort(function(a, b) { return a["sort-order"][sort_key] - b["sort-order"][sort_key] }); + + var tbody = $('#custom-dns-current').find("tbody"); + tbody.text(''); + var last_zone = null; for (var i = 0; i < data.length; i++) { + if (sort_key == "qname" && data[i].zone != last_zone) { + var r = $(""); + r.find("th").text(data[i].zone); + tbody.append(r); + last_zone = data[i].zone; + } + var tr = $(""); - $('#custom-dns-current').find("tbody").append(tr); + tbody.append(tr); tr.attr('data-qname', data[i].qname); tr.attr('data-rtype', data[i].rtype); tr.attr('data-value', data[i].value); tr.append($('')); } - }); } function delete_custom_dns_record(elem) { diff --git a/management/templates/users.html b/management/templates/users.html index 4b349875..24adf4a1 100644 --- a/management/templates/users.html +++ b/management/templates/users.html @@ -1,7 +1,6 @@

Users