From bb34daa33329b00c4096d99abf536ddb03c80be6 Mon Sep 17 00:00:00 2001 From: Rauno Tuul Date: Tue, 28 Mar 2023 16:41:08 +0300 Subject: [PATCH 1/4] Activity pages history base_query unification and perfomance improvement for standard user --- powerdnsadmin/routes/admin.py | 49 +++++++++++------------------------ 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index 3e44fd6..2ae07b3 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -1159,22 +1159,22 @@ def history_table(): # ajax call data lim = int(Setting().get('max_history_records')) # max num of records if request.method == 'GET': - if current_user.role.name in ['Administrator', 'Operator']: - base_query = History.query - else: + base_query = History.query \ + .with_hint(History, "FORCE INDEX (ix_history_created_on)", 'mysql') + if current_user.role.name not in ['Administrator', 'Operator']: # if the user isn't an administrator or operator, # allow_user_view_history must be enabled to get here, # so include history for the zones for the user - base_query = db.session.query(History) \ - .join(Domain, History.domain_id == Domain.id) \ + allowed_domain_id_subquery = db.session.query(Domain.id) \ .outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \ .outerjoin(Account, Domain.account_id == Account.id) \ .outerjoin(AccountUser, Account.id == AccountUser.account_id) \ - .filter( - db.or_( + .filter(db.or_( DomainUser.user_id == current_user.id, AccountUser.user_id == current_user.id - )) + )) \ + .subquery() + base_query = base_query.filter(History.domain_id.in_(allowed_domain_id_subquery)) domain_name = request.args.get('domain_name_filter') if request.args.get('domain_name_filter') != None \ and len( @@ -1290,11 +1290,9 @@ def history_table(): # ajax call data ) ).order_by(History.created_on.desc()) \ .limit(lim).all() - elif user_name != None and current_user.role.name in ['Administrator', - 'Operator']: # only admins can see the user login-logouts + elif user_name != None and current_user.role.name in ['Administrator', 'Operator']: # only admins can see the user login-logouts - histories = History.query \ - .filter( + histories = base_query.filter( db.and_( db.or_( History.msg.like( @@ -1317,10 +1315,8 @@ def history_table(): # ajax call data temp.append(h) break histories = temp - elif (changed_by != None or max_date != None) and current_user.role.name in ['Administrator', - 'Operator']: # select changed by and date filters only - histories = History.query \ - .filter( + elif (changed_by != None or max_date != None) and current_user.role.name in ['Administrator', 'Operator']: # select changed by and date filters only + histories = base_query.filter( db.and_( History.created_on <= max_date if max_date != None else True, History.created_on >= min_date if min_date != None else True, @@ -1328,10 +1324,8 @@ def history_table(): # ajax call data ) ) \ .order_by(History.created_on.desc()).limit(lim).all() - elif ( - changed_by != None or max_date != None): # special filtering for user because one user does not have access to log-ins logs - histories = base_query \ - .filter( + elif (changed_by != None or max_date != None): # special filtering for user because one user does not have access to log-ins logs + histories = base_query.filter( db.and_( History.created_on <= max_date if max_date != None else True, History.created_on >= min_date if min_date != None else True, @@ -1347,20 +1341,7 @@ def history_table(): # ajax call data ) ).order_by(History.created_on.desc()).limit(lim).all() else: # default view - if current_user.role.name in ['Administrator', 'Operator']: - histories = History.query.order_by(History.created_on.desc()).limit(lim).all() - else: - histories = db.session.query(History) \ - .join(Domain, History.domain_id == Domain.id) \ - .outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \ - .outerjoin(Account, Domain.account_id == Account.id) \ - .outerjoin(AccountUser, Account.id == AccountUser.account_id) \ - .order_by(History.created_on.desc()) \ - .filter( - db.or_( - DomainUser.user_id == current_user.id, - AccountUser.user_id == current_user.id - )).limit(lim).all() + histories = base_query.order_by(History.created_on.desc()).limit(lim).all() detailedHistories = convert_histories(histories) From e6c0b4c15fe84aef3cd25cbbd81ab03fccfbdc65 Mon Sep 17 00:00:00 2001 From: Rauno Tuul Date: Thu, 30 Mar 2023 16:23:03 +0300 Subject: [PATCH 2/4] Performance gain in activity records list as in #1381 --- powerdnsadmin/routes/domain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerdnsadmin/routes/domain.py b/powerdnsadmin/routes/domain.py index 593e91d..546419c 100644 --- a/powerdnsadmin/routes/domain.py +++ b/powerdnsadmin/routes/domain.py @@ -235,14 +235,14 @@ def changelog(domain_name): ).all() if StrictVersion(Setting().get('pdns_version')) >= StrictVersion('4.0.0'): + pretty_v6 = Setting().get('pretty_ipv6_ptr') for r in rrsets: if r['type'] in records_allow_to_edit: r_name = r['name'].rstrip('.') # If it is reverse zone and pretty_ipv6_ptr setting # is enabled, we reformat the name for ipv6 records. - if Setting().get('pretty_ipv6_ptr') and r[ - 'type'] == 'PTR' and 'ip6.arpa' in r_name and '*' not in r_name: + if pretty_v6 and r['type'] == 'PTR' and 'ip6.arpa' in r_name and '*' not in r_name: r_name = dns.reversename.to_address( dns.name.from_text(r_name)) From fe10665e19fdff8065fd4519541bf3a73822d62d Mon Sep 17 00:00:00 2001 From: Rauno Tuul Date: Tue, 4 Apr 2023 15:32:52 +0300 Subject: [PATCH 3/4] Refactored zone history retrieval, parsing and displaying code. --- powerdnsadmin/routes/admin.py | 131 +++++----- powerdnsadmin/routes/domain.py | 106 ++------- .../templates/admin_history_table.html | 33 ++- .../templates/applied_change_macro.html | 223 +++++++++--------- powerdnsadmin/templates/domain_changelog.html | 34 +-- 5 files changed, 224 insertions(+), 303 deletions(-) diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index 3e44fd6..36b1eb4 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -107,66 +107,58 @@ def get_record_changes(del_rrset, add_rrset): return changeset +def filter_rr_list_by_name_and_type(rrset, record_name, record_type): + return list(filter(lambda rr: rr['name'] == record_name and rr['type'] == record_type, rrset)) + + # out_changes is a list of HistoryRecordEntry objects in which we will append the new changes # a HistoryRecordEntry represents a pair of add_rrset and del_rrset -def extract_changelogs_from_a_history_entry(out_changes, history_entry, change_num, record_name=None, record_type=None): - if history_entry.detail is None: - return +def extract_changelogs_from_history(histories, record_name=None, record_type=None): + out_changes = [] - if "add_rrsets" in history_entry.detail: - detail_dict = json.loads(history_entry.detail) - else: # not a record entry - return + for entry in histories: + changes = [] - add_rrsets = detail_dict['add_rrsets'] - del_rrsets = detail_dict['del_rrsets'] - - for add_rrset in add_rrsets: - exists = False - for del_rrset in del_rrsets: - if del_rrset['name'] == add_rrset['name'] and del_rrset['type'] == add_rrset['type']: - exists = True - if change_num not in out_changes: - out_changes[change_num] = [] - out_changes[change_num].append(HistoryRecordEntry(history_entry, del_rrset, add_rrset, "*")) - break - if not exists: # this is a new record - if change_num not in out_changes: - out_changes[change_num] = [] - out_changes[change_num].append( - HistoryRecordEntry(history_entry, {}, add_rrset, "+")) # (add_rrset, del_rrset, change_type) - for del_rrset in del_rrsets: - exists = False - for add_rrset in add_rrsets: - if del_rrset['name'] == add_rrset['name'] and del_rrset['type'] == add_rrset['type']: - exists = True # no need to add in the out_changes set - break - if not exists: # this is a deletion - if change_num not in out_changes: - out_changes[change_num] = [] - out_changes[change_num].append(HistoryRecordEntry(history_entry, del_rrset, {}, "-")) - - # Sort them by the record name - if change_num in out_changes: - out_changes[change_num].sort(key=lambda change: - change.del_rrset['name'] if change.del_rrset else change.add_rrset['name'] - ) - - # only used for changelog per record - if record_name != None and record_type != None: # then get only the records with the specific (record_name, record_type) tuple - if change_num in out_changes: - changes_i = out_changes[change_num] - else: - return - for hre in changes_i: # for each history record entry in changes_i - if 'type' in hre.add_rrset and hre.add_rrset['name'] == record_name and hre.add_rrset[ - 'type'] == record_type: + if "add_rrsets" in entry.detail: + details = json.loads(entry.detail) + if not details['add_rrsets'] and not details['del_rrsets']: continue - elif 'type' in hre.del_rrset and hre.del_rrset['name'] == record_name and hre.del_rrset[ - 'type'] == record_type: + else: # not a record entry + continue + + # filter only the records with the specific record_name, record_type + if record_name != None and record_type != None: + details['add_rrsets'] = list(filter_rr_list_by_name_and_type(details['add_rrsets'], record_name, record_type)) + details['del_rrsets'] = list(filter_rr_list_by_name_and_type(details['del_rrsets'], record_name, record_type)) + + if not details['add_rrsets'] and not details['del_rrsets']: continue - else: - out_changes[change_num].remove(hre) + + # same record name and type RR are being deleted and created in same entry. + del_add_changes = set([(r['name'], r['type']) for r in details['add_rrsets']]).intersection([(r['name'], r['type']) for r in details['del_rrsets']]) + for del_add_change in del_add_changes: + changes.append(HistoryRecordEntry( + entry, + filter_rr_list_by_name_and_type(details['del_rrsets'], del_add_change[0], del_add_change[1]).pop(0), + filter_rr_list_by_name_and_type(details['add_rrsets'], del_add_change[0], del_add_change[1]).pop(0), + "*") + ) + + for rrset in details['add_rrsets']: + if (rrset['name'], rrset['type']) not in del_add_changes: + changes.append(HistoryRecordEntry(entry, {}, rrset, "+")) + + for rrset in details['del_rrsets']: + if (rrset['name'], rrset['type']) not in del_add_changes: + changes.append(HistoryRecordEntry(entry, rrset, {}, "-")) + + # sort changes by the record name + if changes: + changes.sort(key=lambda change: + change.del_rrset['name'] if change.del_rrset else change.add_rrset['name'] + ) + out_changes.extend(changes) + return out_changes # records with same (name,type) are considered as a single HistoryRecordEntry @@ -184,21 +176,16 @@ class HistoryRecordEntry: self.changed_fields = [] # contains a subset of : [ttl, name, type] self.changeSet = [] # all changes for the records of this add_rrset-del_rrset pair - if change_type == "+": # addition + if change_type == "+" or change_type == "-": self.changed_fields.append("name") self.changed_fields.append("type") self.changed_fields.append("ttl") - self.changeSet = get_record_changes(del_rrset, add_rrset) - elif change_type == "-": # removal - self.changed_fields.append("name") - self.changed_fields.append("type") - self.changed_fields.append("ttl") - self.changeSet = get_record_changes(del_rrset, add_rrset) elif change_type == "*": # edit of unchanged if add_rrset['ttl'] != del_rrset['ttl']: self.changed_fields.append("ttl") - self.changeSet = get_record_changes(del_rrset, add_rrset) + + self.changeSet = get_record_changes(del_rrset, add_rrset) def toDict(self): return { @@ -882,9 +869,7 @@ class DetailedHistory(): ip_address=detail_dict['ip_address']) elif 'add_rrsets' in detail_dict: # this is a zone record change - # changes_set = [] self.detailed_msg = "" - # extract_changelogs_from_a_history_entry(changes_set, history, 0) elif 'name' in detail_dict and 'template' in history.msg: # template creation / deletion self.detailed_msg = render_template_string(""" @@ -997,20 +982,14 @@ class DetailedHistory(): # convert a list of History objects into DetailedHistory objects def convert_histories(histories): - changes_set = dict() detailedHistories = [] - j = 0 - for i in range(len(histories)): - if histories[i].detail and ('add_rrsets' in histories[i].detail or 'del_rrsets' in histories[i].detail): - extract_changelogs_from_a_history_entry(changes_set, histories[i], j) - if j in changes_set: - detailedHistories.append(DetailedHistory(histories[i], changes_set[j])) - else: # no changes were found - detailedHistories.append(DetailedHistory(histories[i], None)) - j += 1 - + for history in histories: + if history.detail and ('add_rrsets' in history.detail or 'del_rrsets' in history.detail): + history_as_list = list() + history_as_list.append(history) + detailedHistories.append(DetailedHistory(history, extract_changelogs_from_history(history_as_list))) else: - detailedHistories.append(DetailedHistory(histories[i], None)) + detailedHistories.append(DetailedHistory(history, None)) return detailedHistories diff --git a/powerdnsadmin/routes/domain.py b/powerdnsadmin/routes/domain.py index 593e91d..289926c 100644 --- a/powerdnsadmin/routes/domain.py +++ b/powerdnsadmin/routes/domain.py @@ -25,7 +25,7 @@ from ..models.domain_setting import DomainSetting from ..models.base import db from ..models.domain_user import DomainUser from ..models.account_user import AccountUser -from .admin import extract_changelogs_from_a_history_entry +from .admin import extract_changelogs_from_history from ..decorators import history_access_required domain_bp = Blueprint('domain', __name__, @@ -201,17 +201,6 @@ def changelog(domain_name): if not domain: abort(404) - # Query domain's rrsets from PowerDNS API - rrsets = Record().get_rrsets(domain.name) - current_app.logger.debug("Fetched rrsets: \n{}".format(pretty_json(rrsets))) - - # API server might be down, misconfigured - if not rrsets and domain.type != 'Slave': - abort(500) - - records_allow_to_edit = Setting().get_records_allow_to_edit() - records = [] - # get all changelogs for this domain, in descening order if current_user.role.name in [ 'Administrator', 'Operator' ]: histories = History.query.filter(History.domain_id == domain.id).order_by(History.created_on.desc()).all() @@ -230,49 +219,13 @@ def changelog(domain_name): DomainUser.user_id == current_user.id, AccountUser.user_id == current_user.id ), - History.domain_id == domain.id + History.domain_id == domain.id, + History.detail.isnot(None) ) ).all() - if StrictVersion(Setting().get('pdns_version')) >= StrictVersion('4.0.0'): - for r in rrsets: - if r['type'] in records_allow_to_edit: - r_name = r['name'].rstrip('.') + changes_set = extract_changelogs_from_history(histories) - # If it is reverse zone and pretty_ipv6_ptr setting - # is enabled, we reformat the name for ipv6 records. - if Setting().get('pretty_ipv6_ptr') and r[ - 'type'] == 'PTR' and 'ip6.arpa' in r_name and '*' not in r_name: - r_name = dns.reversename.to_address( - dns.name.from_text(r_name)) - - # Create the list of records in format that - # PDA jinja2 template can understand. - index = 0 - for record in r['records']: - if (len(r['comments'])>index): - c=r['comments'][index]['content'] - else: - c='' - record_entry = RecordEntry( - name=r_name, - type=r['type'], - status='Disabled' if record['disabled'] else 'Active', - ttl=r['ttl'], - data=record['content'], - comment=c, - is_allowed_edit=True) - index += 1 - records.append(record_entry) - else: - # Unsupported version - abort(500) - - changes_set = dict() - for i in range(len(histories)): - extract_changelogs_from_a_history_entry(changes_set, histories[i], i) - if i in changes_set and len(changes_set[i]) == 0: # if empty, then remove the key - changes_set.pop(i) return render_template('domain_changelog.html', domain=domain, allHistoryChanges=changes_set) """ @@ -289,17 +242,18 @@ def record_changelog(domain_name, record_name, record_type): domain = Domain.query.filter(Domain.name == domain_name).first() if not domain: abort(404) - # Query domain's rrsets from PowerDNS API - rrsets = Record().get_rrsets(domain.name) - current_app.logger.debug("Fetched rrsets: \n{}".format(pretty_json(rrsets))) - - # API server might be down, misconfigured - if not rrsets and domain.type != 'Slave': - abort(500) # get all changelogs for this domain, in descening order if current_user.role.name in [ 'Administrator', 'Operator' ]: - histories = History.query.filter(History.domain_id == domain.id).order_by(History.created_on.desc()).all() + histories = History.query \ + .filter( + db.and_( + History.domain_id == domain.id, + History.detail.like("%{}%".format(record_name)) + ) + ) \ + .order_by(History.created_on.desc()) \ + .all() else: # if the user isn't an administrator or operator, # allow_user_view_history must be enabled to get here, @@ -309,43 +263,23 @@ def record_changelog(domain_name, record_name, record_type): .outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \ .outerjoin(Account, Domain.account_id == Account.id) \ .outerjoin(AccountUser, Account.id == AccountUser.account_id) \ - .order_by(History.created_on.desc()) \ .filter( db.and_(db.or_( DomainUser.user_id == current_user.id, AccountUser.user_id == current_user.id ), - History.domain_id == domain.id + History.domain_id == domain.id, + History.detail.like("%{}%".format(record_name)) ) - ).all() + ) \ + .order_by(History.created_on.desc()) \ + .all() - changes_set_of_record = dict() - for i in range(len(histories)): - extract_changelogs_from_a_history_entry(changes_set_of_record, histories[i], i, record_name, record_type) - if i in changes_set_of_record and len(changes_set_of_record[i]) == 0: # if empty, then remove the key - changes_set_of_record.pop(i) + changes_set = extract_changelogs_from_history(histories, record_name, record_type) - indexes_to_pop = [] - for change_num in changes_set_of_record: - changes_i = changes_set_of_record[change_num] - for hre in changes_i: # for each history record entry in changes_i - if 'type' in hre.add_rrset and hre.add_rrset['name'] == record_name and hre.add_rrset['type'] == record_type: - continue - elif 'type' in hre.del_rrset and hre.del_rrset['name'] == record_name and hre.del_rrset['type'] == record_type: - continue - else: - changes_set_of_record[change_num].remove(hre) - if change_num in changes_set_of_record and len(changes_set_of_record[change_num]) == 0: # if empty, then remove the key - indexes_to_pop.append(change_num) - - for i in indexes_to_pop: - changes_set_of_record.pop(i) - - return render_template('domain_changelog.html', domain=domain, allHistoryChanges=changes_set_of_record, + return render_template('domain_changelog.html', domain=domain, allHistoryChanges=changes_set, record_name = record_name, record_type = record_type) - - @domain_bp.route('/add', methods=['GET', 'POST']) @login_required @can_create_domain diff --git a/powerdnsadmin/templates/admin_history_table.html b/powerdnsadmin/templates/admin_history_table.html index 8f1d25f..a941ce1 100644 --- a/powerdnsadmin/templates/admin_history_table.html +++ b/powerdnsadmin/templates/admin_history_table.html @@ -10,26 +10,41 @@ - - + + {% for history in histories %} - - + + + + + + + + {%- endmacro %} diff --git a/powerdnsadmin/templates/domain_changelog.html b/powerdnsadmin/templates/domain_changelog.html index 4cdd2be..31a01b4 100644 --- a/powerdnsadmin/templates/domain_changelog.html +++ b/powerdnsadmin/templates/domain_changelog.html @@ -49,6 +49,12 @@ + + + + + + @@ -56,22 +62,14 @@ {% for applied_change in allHistoryChanges %} + {% call applied_change_macro.applied_change_template(applied_change) %} + {% endcall %} - - - - - {% endfor %}
Changed byContent TimeContentChanged by Detail
{{ history.history.created_by }}{{ history.history.msg }} {{ history.history.created_on }}{{ history.history.msg }}{{ history.history.created_by }} @@ -52,7 +67,7 @@ $(document).ready(function () { table = $('#tbl_history').DataTable({ "order": [ - [2, "desc"] + [0, "desc"] ], "searching": true, "columnDefs": [{ @@ -60,7 +75,7 @@ "render": function (data, type, row) { return moment.utc(data).local().format('YYYY-MM-DD HH:mm:ss'); }, - "targets": 2 + "targets": 0 }], "info": true, "autoWidth": false, diff --git a/powerdnsadmin/templates/applied_change_macro.html b/powerdnsadmin/templates/applied_change_macro.html index d4272bd..1dcb136 100644 --- a/powerdnsadmin/templates/applied_change_macro.html +++ b/powerdnsadmin/templates/applied_change_macro.html @@ -1,114 +1,121 @@ -{% macro applied_change_template(change_set) -%} +{% macro applied_change_template(hist_rec_entry) -%} {{ caller() }} -{% for hist_rec_entry in change_set %} - - - - - - + - - - - - - - - {% for changes in hist_rec_entry.changeSet %} - - - - - - {% endfor %} - -
- {% if hist_rec_entry.change_type == '-' %} - {{ - hist_rec_entry.del_rrset['name'] }} {{ hist_rec_entry.del_rrset['type'] - }} - {% elif hist_rec_entry.change_type == '+' %} - {{ - hist_rec_entry.add_rrset['name'] }} {{ hist_rec_entry.add_rrset['type'] - }} - {% else %} - {{ - hist_rec_entry.add_rrset['name'] }} {{ hist_rec_entry.add_rrset['type'] - }} - {% endif %} - , TTL - {% if not 'ttl' in hist_rec_entry.changed_fields %} - {{ - hist_rec_entry.add_rrset['ttl'] - }} - {% else %} - {% if hist_rec_entry.change_type in ['-', '*'] %} - {{ - hist_rec_entry.del_rrset['ttl'] - }} - {% endif %} - {% if hist_rec_entry.change_type in ['+', '*'] %} - {{ - hist_rec_entry.add_rrset['ttl'] - }} - {% endif %} - {% endif %} + +{% if hist_rec_entry.change_type == '-' %} +
{{ + hist_rec_entry.del_rrset['name'] + }} +{% elif hist_rec_entry.change_type == '+' %} +
{{ + hist_rec_entry.add_rrset['name'] + }} +{% else %} +
{{ + hist_rec_entry.add_rrset['name'] + }} +{% endif %} +
+
+{% if hist_rec_entry.change_type == '-' %} +
{{ + hist_rec_entry.del_rrset['type'] + }} +{% elif hist_rec_entry.change_type == '+' %} +
{{ + hist_rec_entry.add_rrset['type'] + }} +{% else %} +
{{ + hist_rec_entry.add_rrset['type'] + }} +{% endif %} +
+
StatusDataComment
- {% if changes[2] == "unchanged" or - (changes[2] == "edit" and changes[0]['disabled'] == changes[1]['disabled']) %} -
{{ - "Disabled" if changes[1]['disabled'] else "Activated" - }}
- {% else %} - {% if changes[2] in ["deletion", "edit"] %} -
{{ - "Disabled" if changes[0]['disabled'] else "Activated" - }}
- {% endif %} - {% if changes[2] in ["addition", "edit"] %} -
{{ - "Disabled" if changes[1]['disabled'] else "Activated" - }}
- {% endif %} - {% endif %} -
- {% if changes[2] == "unchanged" or - (changes[2] == "edit" and changes[0]['content'] == changes[1]['content']) %} -
{{ - changes[1]['content'] - }}
- {% else %} - {% if changes[2] in ["deletion", "edit"] %} -
{{ - changes[0]['content'] - }}
- {% endif %} - {% if changes[2] in ["addition", "edit"] %} -
{{ - changes[1]['content'] - }}
- {% endif %} - {% endif %} -
- {% if changes[2] == "unchanged" or - (changes[2] == "edit" and changes[0]['comment'] == changes[1]['comment']) %} -
{{ - changes[1]['comment'] - }}
- {% else %} - {% if changes[2] in ["deletion", "edit"] and changes[0]['comment'] %} -
{{ - changes[0]['comment'] - }}
- {% endif %} - {% if changes[2] in ["addition", "edit"] and changes[1]['comment'] %} -
{{ - changes[1]['comment'] - }}
- {% endif %} - {% endif %} -
+
+{% if not 'ttl' in hist_rec_entry.changed_fields %} +
{{ + hist_rec_entry.add_rrset['ttl'] + }}
+{% else %} + {% if hist_rec_entry.change_type in ['+', '*'] %} +
{{ + hist_rec_entry.add_rrset['ttl'] + }}
+ {% endif %} + {% if hist_rec_entry.change_type in ['-', '*'] %} +
{{ + hist_rec_entry.del_rrset['ttl'] + }}
+ {% endif %} +{% endif %} +
+{% for changes in hist_rec_entry.changeSet %} + {% if changes[2] == "unchanged" or (changes[2] == "edit" and changes[0]['content'] == changes[1]['content']) %} +
{{ + changes[1]['content'] + }}
+ {% else %} + {% if changes[2] in ["deletion", "edit"] %} +
{{ + changes[0]['content'] + }}
+ {% endif %} + {% if changes[2] in ["addition", "edit"] %} +
{{ + changes[1]['content'] + }}
+ {% endif %} + {% endif %} {% endfor %} +
+{% for changes in hist_rec_entry.changeSet %} + {% if changes[2] == "unchanged" or + (changes[2] == "edit" and changes[0]['disabled'] == changes[1]['disabled']) %} +
{{ + "Disabled" if changes[1]['disabled'] else "Activated" + }}
+ {% else %} + {% if changes[2] in ["deletion", "edit"] %} +
{{ + "Disabled" if changes[0]['disabled'] else "Activated" + }}
+ {% endif %} + {% if changes[2] in ["addition", "edit"] %} +
{{ + "Disabled" if changes[1]['disabled'] else "Activated" + }}
+ {% endif %} + {% endif %} +{% endfor %} +
+{% for changes in hist_rec_entry.changeSet %} + {% if changes[2] == "unchanged" or + (changes[2] == "edit" and changes[0]['comment'] == changes[1]['comment']) %} +
{{ + changes[1]['comment'] + }}
+ {% else %} + {% if changes[2] in ["deletion", "edit"] and changes[0]['comment'] %} +
{{ + changes[0]['comment'] + }}
+ {% endif %} + {% if changes[2] in ["addition", "edit"] and changes[1]['comment'] %} +
{{ + changes[1]['comment'] + }}
+ {% endif %} + {% endif %} +{% endfor %} +
Changed onNameTypeTTLDataStatusComment Changed by
- {{ allHistoryChanges[applied_change][0].history_entry.created_on }} + {{ applied_change.history_entry.created_on }} - {{allHistoryChanges[applied_change][0].history_entry.created_by }} + {{ applied_change.history_entry.created_by }}
-
- {% call applied_change_macro.applied_change_template(allHistoryChanges[applied_change]) %} - {% endcall %} -
-
@@ -106,18 +104,6 @@ }); } - // handle click on history record - $(document.body).on("click", ".row_record", function (e) { - e.stopPropagation(); - var nextRow = $(this).next('tr') - if (nextRow.css("visibility") == "visible") - nextRow.css("visibility", "collapse") - else - nextRow.css("visibility", "visible") - - }); - - var els = document.getElementsByClassName("changed_on"); for (var i = 0; i < els.length; i++) { // els[i].innerHTML = moment.utc(els[i].innerHTML).local().format('YYYY-MM-DD HH:mm:ss'); From d27fa2aa966246131835cb4f3b814a93d408a925 Mon Sep 17 00:00:00 2001 From: Rauno Tuul Date: Tue, 4 Apr 2023 22:27:21 +0300 Subject: [PATCH 4/4] minor syntax improvement to use single history object as list --- powerdnsadmin/routes/admin.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index fa0aa38..86f6ca4 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -985,9 +985,7 @@ def convert_histories(histories): detailedHistories = [] for history in histories: if history.detail and ('add_rrsets' in history.detail or 'del_rrsets' in history.detail): - history_as_list = list() - history_as_list.append(history) - detailedHistories.append(DetailedHistory(history, extract_changelogs_from_history(history_as_list))) + detailedHistories.append(DetailedHistory(history, extract_changelogs_from_history([history]))) else: detailedHistories.append(DetailedHistory(history, None)) return detailedHistories