mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-11-09 15:10:27 +00:00
Zone rrset changelog display improvement (#1507)
This commit is contained in:
commit
b60a74d764
@ -107,66 +107,58 @@ def get_record_changes(del_rrset, add_rrset):
|
|||||||
return changeset
|
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
|
# 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
|
# 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):
|
def extract_changelogs_from_history(histories, record_name=None, record_type=None):
|
||||||
if history_entry.detail is None:
|
out_changes = []
|
||||||
return
|
|
||||||
|
|
||||||
if "add_rrsets" in history_entry.detail:
|
for entry in histories:
|
||||||
detail_dict = json.loads(history_entry.detail)
|
changes = []
|
||||||
|
|
||||||
|
if "add_rrsets" in entry.detail:
|
||||||
|
details = json.loads(entry.detail)
|
||||||
|
if not details['add_rrsets'] and not details['del_rrsets']:
|
||||||
|
continue
|
||||||
else: # not a record entry
|
else: # not a record entry
|
||||||
return
|
continue
|
||||||
|
|
||||||
add_rrsets = detail_dict['add_rrsets']
|
# filter only the records with the specific record_name, record_type
|
||||||
del_rrsets = detail_dict['del_rrsets']
|
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))
|
||||||
|
|
||||||
for add_rrset in add_rrsets:
|
if not details['add_rrsets'] and not details['del_rrsets']:
|
||||||
exists = False
|
continue
|
||||||
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
|
# same record name and type RR are being deleted and created in same entry.
|
||||||
if change_num in out_changes:
|
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']])
|
||||||
out_changes[change_num].sort(key=lambda change:
|
for del_add_change in del_add_changes:
|
||||||
change.del_rrset['name'] if change.del_rrset else change.add_rrset['name']
|
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),
|
||||||
|
"*")
|
||||||
)
|
)
|
||||||
|
|
||||||
# only used for changelog per record
|
for rrset in details['add_rrsets']:
|
||||||
if record_name != None and record_type != None: # then get only the records with the specific (record_name, record_type) tuple
|
if (rrset['name'], rrset['type']) not in del_add_changes:
|
||||||
if change_num in out_changes:
|
changes.append(HistoryRecordEntry(entry, {}, rrset, "+"))
|
||||||
changes_i = out_changes[change_num]
|
|
||||||
else:
|
for rrset in details['del_rrsets']:
|
||||||
return
|
if (rrset['name'], rrset['type']) not in del_add_changes:
|
||||||
for hre in changes_i: # for each history record entry in changes_i
|
changes.append(HistoryRecordEntry(entry, rrset, {}, "-"))
|
||||||
if 'type' in hre.add_rrset and hre.add_rrset['name'] == record_name and hre.add_rrset[
|
|
||||||
'type'] == record_type:
|
# sort changes by the record name
|
||||||
continue
|
if changes:
|
||||||
elif 'type' in hre.del_rrset and hre.del_rrset['name'] == record_name and hre.del_rrset[
|
changes.sort(key=lambda change:
|
||||||
'type'] == record_type:
|
change.del_rrset['name'] if change.del_rrset else change.add_rrset['name']
|
||||||
continue
|
)
|
||||||
else:
|
out_changes.extend(changes)
|
||||||
out_changes[change_num].remove(hre)
|
return out_changes
|
||||||
|
|
||||||
|
|
||||||
# records with same (name,type) are considered as a single HistoryRecordEntry
|
# records with same (name,type) are considered as a single HistoryRecordEntry
|
||||||
@ -184,20 +176,15 @@ class HistoryRecordEntry:
|
|||||||
self.changed_fields = [] # contains a subset of : [ttl, name, type]
|
self.changed_fields = [] # contains a subset of : [ttl, name, type]
|
||||||
self.changeSet = [] # all changes for the records of this add_rrset-del_rrset pair
|
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("name")
|
||||||
self.changed_fields.append("type")
|
self.changed_fields.append("type")
|
||||||
self.changed_fields.append("ttl")
|
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
|
elif change_type == "*": # edit of unchanged
|
||||||
if add_rrset['ttl'] != del_rrset['ttl']:
|
if add_rrset['ttl'] != del_rrset['ttl']:
|
||||||
self.changed_fields.append("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):
|
def toDict(self):
|
||||||
@ -882,9 +869,7 @@ class DetailedHistory():
|
|||||||
ip_address=detail_dict['ip_address'])
|
ip_address=detail_dict['ip_address'])
|
||||||
|
|
||||||
elif 'add_rrsets' in detail_dict: # this is a zone record change
|
elif 'add_rrsets' in detail_dict: # this is a zone record change
|
||||||
# changes_set = []
|
|
||||||
self.detailed_msg = ""
|
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
|
elif 'name' in detail_dict and 'template' in history.msg: # template creation / deletion
|
||||||
self.detailed_msg = render_template_string("""
|
self.detailed_msg = render_template_string("""
|
||||||
@ -999,20 +984,12 @@ class DetailedHistory():
|
|||||||
|
|
||||||
# convert a list of History objects into DetailedHistory objects
|
# convert a list of History objects into DetailedHistory objects
|
||||||
def convert_histories(histories):
|
def convert_histories(histories):
|
||||||
changes_set = dict()
|
|
||||||
detailedHistories = []
|
detailedHistories = []
|
||||||
j = 0
|
for history in histories:
|
||||||
for i in range(len(histories)):
|
if history.detail and ('add_rrsets' in history.detail or 'del_rrsets' in history.detail):
|
||||||
if histories[i].detail and ('add_rrsets' in histories[i].detail or 'del_rrsets' in histories[i].detail):
|
detailedHistories.append(DetailedHistory(history, extract_changelogs_from_history([history])))
|
||||||
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
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
detailedHistories.append(DetailedHistory(histories[i], None))
|
detailedHistories.append(DetailedHistory(history, None))
|
||||||
return detailedHistories
|
return detailedHistories
|
||||||
|
|
||||||
|
|
||||||
@ -1161,22 +1138,22 @@ def history_table(): # ajax call data
|
|||||||
lim = int(Setting().get('max_history_records')) # max num of records
|
lim = int(Setting().get('max_history_records')) # max num of records
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
if current_user.role.name in ['Administrator', 'Operator']:
|
base_query = History.query \
|
||||||
base_query = History.query
|
.with_hint(History, "FORCE INDEX (ix_history_created_on)", 'mysql')
|
||||||
else:
|
if current_user.role.name not in ['Administrator', 'Operator']:
|
||||||
# if the user isn't an administrator or operator,
|
# if the user isn't an administrator or operator,
|
||||||
# allow_user_view_history must be enabled to get here,
|
# allow_user_view_history must be enabled to get here,
|
||||||
# so include history for the zones for the user
|
# so include history for the zones for the user
|
||||||
base_query = db.session.query(History) \
|
allowed_domain_id_subquery = db.session.query(Domain.id) \
|
||||||
.join(Domain, History.domain_id == Domain.id) \
|
|
||||||
.outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \
|
.outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \
|
||||||
.outerjoin(Account, Domain.account_id == Account.id) \
|
.outerjoin(Account, Domain.account_id == Account.id) \
|
||||||
.outerjoin(AccountUser, Account.id == AccountUser.account_id) \
|
.outerjoin(AccountUser, Account.id == AccountUser.account_id) \
|
||||||
.filter(
|
.filter(db.or_(
|
||||||
db.or_(
|
|
||||||
DomainUser.user_id == current_user.id,
|
DomainUser.user_id == current_user.id,
|
||||||
AccountUser.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 \
|
domain_name = request.args.get('domain_name_filter') if request.args.get('domain_name_filter') != None \
|
||||||
and len(
|
and len(
|
||||||
@ -1294,11 +1271,9 @@ def history_table(): # ajax call data
|
|||||||
)
|
)
|
||||||
).order_by(History.created_on.desc()) \
|
).order_by(History.created_on.desc()) \
|
||||||
.limit(lim).all()
|
.limit(lim).all()
|
||||||
elif user_name != None and current_user.role.name in ['Administrator',
|
elif user_name != None and current_user.role.name in ['Administrator', 'Operator']: # only admins can see the user login-logouts
|
||||||
'Operator']: # only admins can see the user login-logouts
|
|
||||||
|
|
||||||
histories = History.query \
|
histories = base_query.filter(
|
||||||
.filter(
|
|
||||||
db.and_(
|
db.and_(
|
||||||
db.or_(
|
db.or_(
|
||||||
History.msg.like(
|
History.msg.like(
|
||||||
@ -1321,10 +1296,8 @@ def history_table(): # ajax call data
|
|||||||
temp.append(h)
|
temp.append(h)
|
||||||
break
|
break
|
||||||
histories = temp
|
histories = temp
|
||||||
elif (changed_by != None or max_date != None) and current_user.role.name in ['Administrator',
|
elif (changed_by != None or max_date != None) and current_user.role.name in ['Administrator', 'Operator']: # select changed by and date filters only
|
||||||
'Operator']: # select changed by and date filters only
|
histories = base_query.filter(
|
||||||
histories = History.query \
|
|
||||||
.filter(
|
|
||||||
db.and_(
|
db.and_(
|
||||||
History.created_on <= max_date if max_date != None else True,
|
History.created_on <= max_date if max_date != None else True,
|
||||||
History.created_on >= min_date if min_date != None else True,
|
History.created_on >= min_date if min_date != None else True,
|
||||||
@ -1332,10 +1305,8 @@ def history_table(): # ajax call data
|
|||||||
)
|
)
|
||||||
) \
|
) \
|
||||||
.order_by(History.created_on.desc()).limit(lim).all()
|
.order_by(History.created_on.desc()).limit(lim).all()
|
||||||
elif (
|
elif (changed_by != None or max_date != None): # special filtering for user because one user does not have access to log-ins logs
|
||||||
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(
|
||||||
histories = base_query \
|
|
||||||
.filter(
|
|
||||||
db.and_(
|
db.and_(
|
||||||
History.created_on <= max_date if max_date != None else True,
|
History.created_on <= max_date if max_date != None else True,
|
||||||
History.created_on >= min_date if min_date != None else True,
|
History.created_on >= min_date if min_date != None else True,
|
||||||
@ -1351,20 +1322,7 @@ def history_table(): # ajax call data
|
|||||||
)
|
)
|
||||||
).order_by(History.created_on.desc()).limit(lim).all()
|
).order_by(History.created_on.desc()).limit(lim).all()
|
||||||
else: # default view
|
else: # default view
|
||||||
if current_user.role.name in ['Administrator', 'Operator']:
|
histories = base_query.order_by(History.created_on.desc()).limit(lim).all()
|
||||||
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()
|
|
||||||
|
|
||||||
detailedHistories = convert_histories(histories)
|
detailedHistories = convert_histories(histories)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ from ..models.domain_setting import DomainSetting
|
|||||||
from ..models.base import db
|
from ..models.base import db
|
||||||
from ..models.domain_user import DomainUser
|
from ..models.domain_user import DomainUser
|
||||||
from ..models.account_user import AccountUser
|
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
|
from ..decorators import history_access_required
|
||||||
domain_bp = Blueprint('domain',
|
domain_bp = Blueprint('domain',
|
||||||
__name__,
|
__name__,
|
||||||
@ -201,17 +201,6 @@ def changelog(domain_name):
|
|||||||
if not domain:
|
if not domain:
|
||||||
abort(404)
|
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
|
# get all changelogs for this domain, in descening order
|
||||||
if current_user.role.name in [ 'Administrator', 'Operator' ]:
|
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(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,
|
DomainUser.user_id == current_user.id,
|
||||||
AccountUser.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()
|
).all()
|
||||||
|
|
||||||
if StrictVersion(Setting().get('pdns_version')) >= StrictVersion('4.0.0'):
|
changes_set = extract_changelogs_from_history(histories)
|
||||||
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:
|
|
||||||
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)
|
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()
|
domain = Domain.query.filter(Domain.name == domain_name).first()
|
||||||
if not domain:
|
if not domain:
|
||||||
abort(404)
|
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
|
# get all changelogs for this domain, in descening order
|
||||||
if current_user.role.name in [ 'Administrator', 'Operator' ]:
|
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:
|
else:
|
||||||
# if the user isn't an administrator or operator,
|
# if the user isn't an administrator or operator,
|
||||||
# allow_user_view_history must be enabled to get here,
|
# 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(DomainUser, Domain.id == DomainUser.domain_id) \
|
||||||
.outerjoin(Account, Domain.account_id == Account.id) \
|
.outerjoin(Account, Domain.account_id == Account.id) \
|
||||||
.outerjoin(AccountUser, Account.id == AccountUser.account_id) \
|
.outerjoin(AccountUser, Account.id == AccountUser.account_id) \
|
||||||
.order_by(History.created_on.desc()) \
|
|
||||||
.filter(
|
.filter(
|
||||||
db.and_(db.or_(
|
db.and_(db.or_(
|
||||||
DomainUser.user_id == current_user.id,
|
DomainUser.user_id == current_user.id,
|
||||||
AccountUser.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()
|
changes_set = extract_changelogs_from_history(histories, record_name, record_type)
|
||||||
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)
|
|
||||||
|
|
||||||
indexes_to_pop = []
|
return render_template('domain_changelog.html', domain=domain, allHistoryChanges=changes_set,
|
||||||
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,
|
|
||||||
record_name = record_name, record_type = record_type)
|
record_name = record_name, record_type = record_type)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@domain_bp.route('/add', methods=['GET', 'POST'])
|
@domain_bp.route('/add', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@can_create_domain
|
@can_create_domain
|
||||||
|
@ -10,26 +10,41 @@
|
|||||||
<table id="tbl_history" class="table table-bordered table-striped">
|
<table id="tbl_history" class="table table-bordered table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Changed by</th>
|
|
||||||
<th>Content</th>
|
|
||||||
<th>Time</th>
|
<th>Time</th>
|
||||||
|
<th>Content</th>
|
||||||
|
<th>Changed by</th>
|
||||||
<th>Detail</th>
|
<th>Detail</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for history in histories %}
|
{% for history in histories %}
|
||||||
<tr class="odd gradeX">
|
<tr class="odd gradeX">
|
||||||
<td>{{ history.history.created_by }}</td>
|
|
||||||
<td>{{ history.history.msg }}</td>
|
|
||||||
<td>{{ history.history.created_on }}</td>
|
<td>{{ history.history.created_on }}</td>
|
||||||
|
<td>{{ history.history.msg }}</td>
|
||||||
|
<td>{{ history.history.created_by }}</td>
|
||||||
<td width="6%">
|
<td width="6%">
|
||||||
<div id="history-info-div-{{ loop.index0 }}" style="display: none;">
|
<div id="history-info-div-{{ loop.index0 }}" style="display: none;">
|
||||||
{{ history.detailed_msg | safe }}
|
{{ history.detailed_msg | safe }}
|
||||||
{% if history.change_set %}
|
{% if history.change_set %}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div id="change_index_definition"></div>
|
<table class="table table-bordered table-striped">
|
||||||
{% call applied_change_macro.applied_change_template(history.change_set) %}
|
<thead><tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>TTL</th>
|
||||||
|
<th>Data</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Comment</th>
|
||||||
|
</tr></thead>
|
||||||
|
<tbody>
|
||||||
|
{% for applied_change in history.change_set %}
|
||||||
|
<tr>
|
||||||
|
{% call applied_change_macro.applied_change_template(applied_change) %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@ -52,7 +67,7 @@
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
table = $('#tbl_history').DataTable({
|
table = $('#tbl_history').DataTable({
|
||||||
"order": [
|
"order": [
|
||||||
[2, "desc"]
|
[0, "desc"]
|
||||||
],
|
],
|
||||||
"searching": true,
|
"searching": true,
|
||||||
"columnDefs": [{
|
"columnDefs": [{
|
||||||
@ -60,7 +75,7 @@
|
|||||||
"render": function (data, type, row) {
|
"render": function (data, type, row) {
|
||||||
return moment.utc(data).local().format('YYYY-MM-DD HH:mm:ss');
|
return moment.utc(data).local().format('YYYY-MM-DD HH:mm:ss');
|
||||||
},
|
},
|
||||||
"targets": 2
|
"targets": 0
|
||||||
}],
|
}],
|
||||||
"info": true,
|
"info": true,
|
||||||
"autoWidth": false,
|
"autoWidth": false,
|
||||||
|
@ -1,55 +1,82 @@
|
|||||||
{% macro applied_change_template(change_set) -%}
|
{% macro applied_change_template(hist_rec_entry) -%}
|
||||||
{{ caller() }}
|
{{ caller() }}
|
||||||
{% for hist_rec_entry in change_set %}
|
|
||||||
<table id="tbl_records" class="table table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col" colspan="3">
|
|
||||||
{% if hist_rec_entry.change_type == '-' %}
|
|
||||||
<span class="diff diff-deletion">{{
|
|
||||||
hist_rec_entry.del_rrset['name'] }} {{ hist_rec_entry.del_rrset['type']
|
|
||||||
}}</span>
|
|
||||||
{% elif hist_rec_entry.change_type == '+' %}
|
|
||||||
<span class="diff diff-addition">{{
|
|
||||||
hist_rec_entry.add_rrset['name'] }} {{ hist_rec_entry.add_rrset['type']
|
|
||||||
}}</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="diff diff-unchanged">{{
|
|
||||||
hist_rec_entry.add_rrset['name'] }} {{ hist_rec_entry.add_rrset['type']
|
|
||||||
}}</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
, TTL
|
<td>
|
||||||
{% if not 'ttl' in hist_rec_entry.changed_fields %}
|
{% if hist_rec_entry.change_type == '-' %}
|
||||||
<span class="diff diff-unchanged">{{
|
<div class="diff diff-deletion">{{
|
||||||
|
hist_rec_entry.del_rrset['name']
|
||||||
|
}}
|
||||||
|
{% elif hist_rec_entry.change_type == '+' %}
|
||||||
|
<div class="diff diff-addition">{{
|
||||||
|
hist_rec_entry.add_rrset['name']
|
||||||
|
}}
|
||||||
|
{% else %}
|
||||||
|
<div class="diff diff-unchanged">{{
|
||||||
|
hist_rec_entry.add_rrset['name']
|
||||||
|
}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{% if hist_rec_entry.change_type == '-' %}
|
||||||
|
<div class="diff diff-deletion">{{
|
||||||
|
hist_rec_entry.del_rrset['type']
|
||||||
|
}}
|
||||||
|
{% elif hist_rec_entry.change_type == '+' %}
|
||||||
|
<div class="diff diff-addition">{{
|
||||||
|
hist_rec_entry.add_rrset['type']
|
||||||
|
}}
|
||||||
|
{% else %}
|
||||||
|
<div class="diff diff-unchanged">{{
|
||||||
|
hist_rec_entry.add_rrset['type']
|
||||||
|
}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{% if not 'ttl' in hist_rec_entry.changed_fields %}
|
||||||
|
<div class="diff diff-unchanged">{{
|
||||||
hist_rec_entry.add_rrset['ttl']
|
hist_rec_entry.add_rrset['ttl']
|
||||||
}}</span>
|
}}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if hist_rec_entry.change_type in ['-', '*'] %}
|
|
||||||
<span class="diff diff-deletion">{{
|
|
||||||
hist_rec_entry.del_rrset['ttl']
|
|
||||||
}}</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if hist_rec_entry.change_type in ['+', '*'] %}
|
{% if hist_rec_entry.change_type in ['+', '*'] %}
|
||||||
<span class="diff diff-addition">{{
|
<div class="diff diff-addition">{{
|
||||||
hist_rec_entry.add_rrset['ttl']
|
hist_rec_entry.add_rrset['ttl']
|
||||||
}}</span>
|
}}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if hist_rec_entry.change_type in ['-', '*'] %}
|
||||||
|
<div class="diff diff-deletion">{{
|
||||||
|
hist_rec_entry.del_rrset['ttl']
|
||||||
|
}}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td style="word-break: break-all">
|
||||||
|
{% for changes in hist_rec_entry.changeSet %}
|
||||||
|
{% if changes[2] == "unchanged" or (changes[2] == "edit" and changes[0]['content'] == changes[1]['content']) %}
|
||||||
|
<div class="diff diff-unchanged">{{
|
||||||
|
changes[1]['content']
|
||||||
|
}}</div>
|
||||||
|
{% else %}
|
||||||
|
{% if changes[2] in ["deletion", "edit"] %}
|
||||||
|
<div class="diff diff-deletion">{{
|
||||||
|
changes[0]['content']
|
||||||
|
}}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if changes[2] in ["addition", "edit"] %}
|
||||||
|
<div class="diff diff-addition">{{
|
||||||
|
changes[1]['content']
|
||||||
|
}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
|
||||||
</th>
|
<td>
|
||||||
</tr>
|
{% for changes in hist_rec_entry.changeSet %}
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th scope="col" style="width: 150px;">Status</th>
|
|
||||||
<th scope="col" style="width: 400px;">Data</th>
|
|
||||||
<th scope="col" style="width: 400px;">Comment</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for changes in hist_rec_entry.changeSet %}
|
|
||||||
<tr>
|
|
||||||
<td style="word-break: break-all">
|
|
||||||
{% if changes[2] == "unchanged" or
|
{% if changes[2] == "unchanged" or
|
||||||
(changes[2] == "edit" and changes[0]['disabled'] == changes[1]['disabled']) %}
|
(changes[2] == "edit" and changes[0]['disabled'] == changes[1]['disabled']) %}
|
||||||
<div class="diff diff-unchanged">{{
|
<div class="diff diff-unchanged">{{
|
||||||
@ -67,27 +94,11 @@
|
|||||||
}}</div>
|
}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
{% endfor %}
|
||||||
<td style="word-break: break-all">
|
</td>
|
||||||
{% if changes[2] == "unchanged" or
|
|
||||||
(changes[2] == "edit" and changes[0]['content'] == changes[1]['content']) %}
|
<td style="word-break: break-all">
|
||||||
<div class="diff diff-unchanged">{{
|
{% for changes in hist_rec_entry.changeSet %}
|
||||||
changes[1]['content']
|
|
||||||
}}</div>
|
|
||||||
{% else %}
|
|
||||||
{% if changes[2] in ["deletion", "edit"] %}
|
|
||||||
<div class="diff diff-deletion">{{
|
|
||||||
changes[0]['content']
|
|
||||||
}}</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if changes[2] in ["addition", "edit"] %}
|
|
||||||
<div class="diff diff-addition">{{
|
|
||||||
changes[1]['content']
|
|
||||||
}}</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td style="word-break: break-all">
|
|
||||||
{% if changes[2] == "unchanged" or
|
{% if changes[2] == "unchanged" or
|
||||||
(changes[2] == "edit" and changes[0]['comment'] == changes[1]['comment']) %}
|
(changes[2] == "edit" and changes[0]['comment'] == changes[1]['comment']) %}
|
||||||
<div class="diff diff-unchanged">{{
|
<div class="diff diff-unchanged">{{
|
||||||
@ -105,10 +116,6 @@
|
|||||||
}}</div>
|
}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</td>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
@ -49,6 +49,12 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Changed on</th>
|
<th>Changed on</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>TTL</th>
|
||||||
|
<th>Data</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Comment</th>
|
||||||
<th>Changed by</th>
|
<th>Changed by</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -56,22 +62,14 @@
|
|||||||
{% for applied_change in allHistoryChanges %}
|
{% for applied_change in allHistoryChanges %}
|
||||||
<tr class="odd row_record" id="{{ domain.name }}">
|
<tr class="odd row_record" id="{{ domain.name }}">
|
||||||
<td id="changed_on" class="changed_on">
|
<td id="changed_on" class="changed_on">
|
||||||
{{ allHistoryChanges[applied_change][0].history_entry.created_on }}
|
{{ applied_change.history_entry.created_on }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
{% call applied_change_macro.applied_change_template(applied_change) %}
|
||||||
{{allHistoryChanges[applied_change][0].history_entry.created_by }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<!-- Nested Table -->
|
|
||||||
<tr style='visibility:collapse'>
|
|
||||||
<td colspan="2">
|
|
||||||
<div class="content">
|
|
||||||
{% call applied_change_macro.applied_change_template(allHistoryChanges[applied_change]) %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</div>
|
<td>
|
||||||
|
{{ applied_change.history_entry.created_by }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- end nested table -->
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -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");
|
var els = document.getElementsByClassName("changed_on");
|
||||||
for (var i = 0; i < els.length; i++) {
|
for (var i = 0; i < els.length; i++) {
|
||||||
// els[i].innerHTML = moment.utc(els[i].innerHTML).local().format('YYYY-MM-DD HH:mm:ss');
|
// els[i].innerHTML = moment.utc(els[i].innerHTML).local().format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
Loading…
Reference in New Issue
Block a user