From bca3c45e37cb010e7d7cf85d420b29d82aa4b935 Mon Sep 17 00:00:00 2001 From: Khanh Ngo Date: Mon, 9 Dec 2019 17:50:48 +0700 Subject: [PATCH] Add record comment --- ..._add_comment_column_in_domain_template_.py | 30 +++++++ .../models/domain_template_record.py | 3 + powerdnsadmin/models/record.py | 81 ++++++++++++------- powerdnsadmin/models/record_entry.py | 2 + powerdnsadmin/routes/admin.py | 11 ++- powerdnsadmin/routes/domain.py | 25 ++++-- powerdnsadmin/static/custom/js/custom.js | 11 ++- powerdnsadmin/static/generated/main.js | 8 +- powerdnsadmin/templates/domain.html | 35 ++++---- powerdnsadmin/templates/template_edit.html | 16 ++-- 10 files changed, 158 insertions(+), 64 deletions(-) create mode 100644 migrations/versions/856bb94b7040_add_comment_column_in_domain_template_.py diff --git a/migrations/versions/856bb94b7040_add_comment_column_in_domain_template_.py b/migrations/versions/856bb94b7040_add_comment_column_in_domain_template_.py new file mode 100644 index 0000000..4cb5a55 --- /dev/null +++ b/migrations/versions/856bb94b7040_add_comment_column_in_domain_template_.py @@ -0,0 +1,30 @@ +"""Add comment column in domain template record table + +Revision ID: 856bb94b7040 +Revises: 0fb6d23a4863 +Create Date: 2019-12-09 17:17:46.257906 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '856bb94b7040' +down_revision = '0fb6d23a4863' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('domain_template_record', + sa.Column('comment', sa.Text(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('domain_template_record') as batch_op: + batch_op.drop_column('comment') + # ### end Alembic commands ### diff --git a/powerdnsadmin/models/domain_template_record.py b/powerdnsadmin/models/domain_template_record.py index 993c5ed..9290a51 100644 --- a/powerdnsadmin/models/domain_template_record.py +++ b/powerdnsadmin/models/domain_template_record.py @@ -8,6 +8,7 @@ class DomainTemplateRecord(db.Model): type = db.Column(db.String(64)) ttl = db.Column(db.Integer) data = db.Column(db.Text) + comment = db.Column(db.Text) status = db.Column(db.Boolean) template_id = db.Column(db.Integer, db.ForeignKey('domain_template.id')) template = db.relationship('DomainTemplate', back_populates='records') @@ -21,12 +22,14 @@ class DomainTemplateRecord(db.Model): type=None, ttl=None, data=None, + comment=None, status=None): self.id = id self.name = name self.type = type self.ttl = ttl self.data = data + self.comment = comment self.status = status def apply(self): diff --git a/powerdnsadmin/models/record.py b/powerdnsadmin/models/record.py index 5723df2..1b6355c 100644 --- a/powerdnsadmin/models/record.py +++ b/powerdnsadmin/models/record.py @@ -20,12 +20,19 @@ class Record(object): This is not a model, it's just an object which be assigned data from PowerDNS API """ - def __init__(self, name=None, type=None, status=None, ttl=None, data=None): + def __init__(self, + name=None, + type=None, + status=None, + ttl=None, + data=None, + comment_data=None): self.name = name self.type = type self.status = status self.ttl = ttl self.data = data + self.comment_data = comment_data # PDNS configs self.PDNS_STATS_URL = Setting().get('pdns_api_url') self.PDNS_API_KEY = Setting().get('pdns_api_key') @@ -48,7 +55,8 @@ class Record(object): jdata = utils.fetch_json(urljoin( self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), - timeout=int(Setting().get('pdns_api_timeout')), + timeout=int( + Setting().get('pdns_api_timeout')), headers=headers) except Exception as e: current_app.logger.error( @@ -59,16 +67,24 @@ class Record(object): if self.NEW_SCHEMA: rrsets = jdata['rrsets'] for rrset in rrsets: - r_name = rrset['name'].rstrip('.') - if self.PRETTY_IPV6_PTR: # only if activated - if rrset['type'] == 'PTR': # only ptr - if 'ip6.arpa' in r_name: # only if v6-ptr - r_name = dns.reversename.to_address( - dns.name.from_text(r_name)) + if rrset['records']: + r_name = rrset['name'].rstrip('.') + if self.PRETTY_IPV6_PTR: # only if activated + if rrset['type'] == 'PTR': # only ptr + if 'ip6.arpa' in r_name: # only if v6-ptr + r_name = dns.reversename.to_address( + dns.name.from_text(r_name)) - rrset['name'] = r_name - rrset['content'] = rrset['records'][0]['content'] - rrset['disabled'] = rrset['records'][0]['disabled'] + rrset['name'] = r_name + rrset['content'] = rrset['records'][0]['content'] + rrset['disabled'] = rrset['records'][0]['disabled'] + + # Get the record's comment. PDNS support multiple comments + # per record. However, we are only interested in the 1st + # one, for now. + rrset['comment_data'] = {"content": "", "account": ""} + if rrset['comments']: + rrset['comment_data'] = rrset['comments'][0] return {'records': rrsets} return jdata @@ -108,7 +124,8 @@ class Record(object): "records": [{ "content": self.data, "disabled": self.status, - }] + }], + "comments": [self.comment_data] }] } else: @@ -126,7 +143,8 @@ class Record(object): "name": self.name, "ttl": self.ttl, "type": self.type - }] + }], + "comments": [self.comment_data] }] } @@ -135,7 +153,8 @@ class Record(object): self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, - timeout=int(Setting().get('pdns_api_timeout')), + timeout=int( + Setting().get('pdns_api_timeout')), method='PATCH', data=data) current_app.logger.debug(jdata) @@ -208,6 +227,7 @@ class Record(object): "disabled": True if r['record_status'] == 'Disabled' else False, "ttl": int(r['record_ttl']) if r['record_ttl'] else 3600, + "comment_data": r['comment_data'] } records.append(record) @@ -256,8 +276,10 @@ class Record(object): r['ttl'], "records": [{ "content": r['content'], - "disabled": r['disabled'], - }] + "disabled": r['disabled'] + }], + "comments": + r['comment_data'] } else: record = { @@ -275,7 +297,9 @@ class Record(object): "type": r['type'], "priority": 10, # priority field for pdns 3.4.1. https://doc.powerdns.com/md/authoritative/upgrading/ - }] + }], + "comments": + r['comment_data'] } records.append(record) @@ -320,6 +344,7 @@ class Record(object): "content": temp_content, "disabled": temp_disabled }) + new_record['comments'] = item['comments'] final_records.append(new_record) else: @@ -357,14 +382,14 @@ class Record(object): headers=headers, method='PATCH', data=postdata_for_delete) - jdata2 = utils.fetch_json( - urljoin( - self.PDNS_STATS_URL, self.API_EXTENDED_URL + - '/servers/localhost/zones/{0}'.format(domain)), - headers=headers, - timeout=int(Setting().get('pdns_api_timeout')), - method='PATCH', - data=postdata_for_new) + jdata2 = utils.fetch_json(urljoin( + self.PDNS_STATS_URL, self.API_EXTENDED_URL + + '/servers/localhost/zones/{0}'.format(domain)), + headers=headers, + timeout=int( + Setting().get('pdns_api_timeout')), + method='PATCH', + data=postdata_for_new) if 'error' in jdata1.keys(): current_app.logger.error('Cannot apply record changes.') @@ -471,7 +496,8 @@ class Record(object): self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, - timeout=int(Setting().get('pdns_api_timeout')), + timeout=int( + Setting().get('pdns_api_timeout')), method='PATCH', data=data) current_app.logger.debug(jdata) @@ -587,7 +613,8 @@ class Record(object): self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, - timeout=int(Setting().get('pdns_api_timeout')), + timeout=int( + Setting().get('pdns_api_timeout')), method='GET') serial = jdata['serial'] diff --git a/powerdnsadmin/models/record_entry.py b/powerdnsadmin/models/record_entry.py index e129dc1..5b8584b 100644 --- a/powerdnsadmin/models/record_entry.py +++ b/powerdnsadmin/models/record_entry.py @@ -9,12 +9,14 @@ class RecordEntry(object): status=None, ttl=None, data=None, + comment=None, is_allowed_edit=False): self.name = name self.type = type self.status = status self.ttl = ttl self.data = data + self.comment = comment self._is_allowed_edit = is_allowed_edit self._is_allowed_delete = is_allowed_edit and self.type != 'SOA' diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index f23b93a..41ae62c 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -851,7 +851,8 @@ def create_template_from_zone(): status=True if subrecord['disabled'] else False, ttl=jr['ttl'], - data=subrecord['content']) + data=subrecord['content'], + comment=jr['comment_data']['content']) records.append(record) else: for jr in jrecords: @@ -863,7 +864,8 @@ def create_template_from_zone(): type=jr['type'], status=True if jr['disabled'] else False, ttl=jr['ttl'], - data=jr['content']) + data=jr['content'], + comment=jr['comment_data']['content']) records.append(record) result_records = t.replace_records(records) @@ -918,7 +920,8 @@ def edit_template(template): type=jr.type, status='Disabled' if jr.status else 'Active', ttl=jr.ttl, - data=jr.data) + data=jr.data, + comment=jr.comment if jr.comment else '') records.append(record) return render_template('template_edit.html', @@ -948,12 +951,14 @@ def apply_records(template): name = '@' if j['record_name'] in ['@', ''] else j['record_name'] type = j['record_type'] data = j['record_data'] + comment = j['record_comment'] disabled = True if j['record_status'] == 'Disabled' else False ttl = int(j['record_ttl']) if j['record_ttl'] else 3600 dtr = DomainTemplateRecord(name=name, type=type, data=data, + comment=comment, status=disabled, ttl=ttl) records.append(dtr) diff --git a/powerdnsadmin/routes/domain.py b/powerdnsadmin/routes/domain.py index 67ed4cc..8aec6c0 100644 --- a/powerdnsadmin/routes/domain.py +++ b/powerdnsadmin/routes/domain.py @@ -59,6 +59,7 @@ def domain(domain_name): subrecord['disabled'] else 'Active', ttl=jr['ttl'], data=subrecord['content'], + comment=jr['comment_data']['content'], is_allowed_edit=True) records.append(record) if not re.search('ip6\.arpa|in-addr\.arpa$', domain_name): @@ -80,6 +81,7 @@ def domain(domain_name): status='Disabled' if jr['disabled'] else 'Active', ttl=jr['ttl'], data=jr['content'], + comment=jr['comment_data']['content'], is_allowed_edit=True) records.append(record) if not re.search('ip6\.arpa|in-addr\.arpa$', domain_name): @@ -108,8 +110,9 @@ def add(): account_id = request.form.getlist('accountid')[0] if ' ' in domain_name or not domain_name or not domain_type: - return render_template('errors/400.html', - msg="Please enter a valid domain name"), 400 + return render_template( + 'errors/400.html', + msg="Please enter a valid domain name"), 400 if domain_type == 'slave': if request.form.getlist('domain_master_address'): @@ -140,8 +143,7 @@ def add(): history.add() # grant user access to the domain - Domain(name=domain_name).grant_privileges( - [current_user.id]) + Domain(name=domain_name).grant_privileges([current_user.id]) # apply template if needed if domain_template != '0': @@ -157,7 +159,8 @@ def add(): 'record_name': template_record.name, 'record_status': template_record.status, 'record_ttl': template_record.ttl, - 'record_type': template_record.type + 'record_type': template_record.type, + 'comment_data': [{'content': template_record.comment, 'account': ''}] } record_data.append(record_row) r = Record() @@ -341,6 +344,18 @@ def record_apply(domain_name): 'Domain name {0} does not exist'.format(domain_name) }), 404) + # Modify the record's comment data. We append + # the "current_user" into account field as it + # a field with user-defined meaning + for sr in submitted_record: + if sr.get('record_comment'): + sr['comment_data'] = [{ + 'content': sr['record_comment'], + 'account': current_user.username + }] + else: + sr['comment_data'] = [] + r = Record() result = r.apply(domain_name, submitted_record) if result['status'] == 'ok': diff --git a/powerdnsadmin/static/custom/js/custom.js b/powerdnsadmin/static/custom/js/custom.js index 4f295bb..d9ad202 100644 --- a/powerdnsadmin/static/custom/js/custom.js +++ b/powerdnsadmin/static/custom/js/custom.js @@ -75,6 +75,7 @@ function getTableData(table) { record["record_status"] = r[2].trim(); record["record_ttl"] = r[3].trim(); record["record_data"] = r[4].trim(); + record["record_comment"] = r[5].trim(); records.push(record); }); return records @@ -95,13 +96,14 @@ function saveRow(oTable, nRow) { oTable.cell(nRow,2).data(status); oTable.cell(nRow,3).data(jqSelect[2].value); oTable.cell(nRow,4).data(jqInputs[1].value); + oTable.cell(nRow,5).data(jqInputs[2].value); var record = jqInputs[0].value; var button_edit = "" var button_delete = "" - oTable.cell(nRow,5).data(button_edit); - oTable.cell(nRow,6).data(button_delete); + oTable.cell(nRow,6).data(button_edit); + oTable.cell(nRow,7).data(button_delete); oTable.draw(); } @@ -145,8 +147,9 @@ function editRow(oTable, nRow) { jqTds[2].innerHTML = ''; jqTds[3].innerHTML = ''; jqTds[4].innerHTML = ''; - jqTds[5].innerHTML = ''; - jqTds[6].innerHTML = ''; + jqTds[5].innerHTML = ''; + jqTds[6].innerHTML = ''; + jqTds[7].innerHTML = ''; // set current value of dropdown column if (aData[2] == 'Active'){ diff --git a/powerdnsadmin/static/generated/main.js b/powerdnsadmin/static/generated/main.js index d0e051c..b348332 100644 --- a/powerdnsadmin/static/generated/main.js +++ b/powerdnsadmin/static/generated/main.js @@ -5193,17 +5193,17 @@ function applyRecordChanges(data,domain){$.ajax({type:"POST",url:$SCRIPT_ROOT+'/ var modal=$("#modal_success");modal.find('.modal-body p').text("Applied changes successfully");modal.modal('show');},error:function(jqXHR,status){console.log(jqXHR);var modal=$("#modal_error");var responseJson=jQuery.parseJSON(jqXHR.responseText);modal.find('.modal-body p').text(responseJson['msg']);modal.modal('show');}});} function getTableData(table){var records=[] table.rows().every(function(){var r=this.data();var record={} -record["record_name"]=r[0].trim();record["record_type"]=r[1].trim();record["record_status"]=r[2].trim();record["record_ttl"]=r[3].trim();record["record_data"]=r[4].trim();records.push(record);});return records} +record["record_name"]=r[0].trim();record["record_type"]=r[1].trim();record["record_status"]=r[2].trim();record["record_ttl"]=r[3].trim();record["record_data"]=r[4].trim();record["record_comment"]=r[5].trim();records.push(record);});return records} function saveRow(oTable,nRow){var status='Disabled';var jqInputs=$(oTable.row(nRow).node()).find("input");var jqSelect=$(oTable.row(nRow).node()).find("select");if(jqSelect[1].value=='false'){status='Active';} -oTable.cell(nRow,0).data(jqInputs[0].value);oTable.cell(nRow,1).data(jqSelect[0].value);oTable.cell(nRow,2).data(status);oTable.cell(nRow,3).data(jqSelect[2].value);oTable.cell(nRow,4).data(jqInputs[1].value);var record=jqInputs[0].value;var button_edit="" +oTable.cell(nRow,0).data(jqInputs[0].value);oTable.cell(nRow,1).data(jqSelect[0].value);oTable.cell(nRow,2).data(status);oTable.cell(nRow,3).data(jqSelect[2].value);oTable.cell(nRow,4).data(jqInputs[1].value);oTable.cell(nRow,5).data(jqInputs[2].value);var record=jqInputs[0].value;var button_edit="" var button_delete="" -oTable.cell(nRow,5).data(button_edit);oTable.cell(nRow,6).data(button_delete);oTable.draw();} +oTable.cell(nRow,6).data(button_edit);oTable.cell(nRow,7).data(button_delete);oTable.draw();} function restoreRow(oTable,nRow){var aData=oTable.row(nRow).data();oTable.row(nRow).data(aData);oTable.draw();} function sec2str(t){var d=Math.floor(t/86400),h=Math.floor(t/3600)%24,m=Math.floor(t/60)%60,s=t%60;return(d>0?d+' days ':'')+(h>0?h+' hours ':'')+(m>0?m+' minutes ':'')+(s>0?s+' seconds':'');} function editRow(oTable,nRow){var isDisabled='true';var aData=oTable.row(nRow).data();var jqTds=oTable.cells(nRow,'').nodes();var record_types="";var ttl_opts="";var ttl_not_found=true;for(var i=0;i"+record_type+"";} for(var i=0;i"+ttl_options[i][1]+"";if(ttl_options[i][0]==aData[3]){ttl_not_found=false;}} if(ttl_not_found){ttl_opts+="";} -jqTds[0].innerHTML='';jqTds[1].innerHTML='';jqTds[2].innerHTML='';jqTds[3].innerHTML='';jqTds[4].innerHTML='';jqTds[5].innerHTML='';jqTds[6].innerHTML='';if(aData[2]=='Active'){isDisabled='false';} +jqTds[0].innerHTML='';jqTds[1].innerHTML='';jqTds[2].innerHTML='';jqTds[3].innerHTML='';jqTds[4].innerHTML='';jqTds[5].innerHTML='';jqTds[6].innerHTML='';jqTds[7].innerHTML='';if(aData[2]=='Active'){isDisabled='false';} SelectElement('record_type',aData[1]);SelectElement('record_status',isDisabled);SelectElement('record_ttl',aData[3]);} function SelectElement(elementID,valueToSelect) {var element=document.getElementById(elementID);element.value=valueToSelect;} diff --git a/powerdnsadmin/templates/domain.html b/powerdnsadmin/templates/domain.html index 341dda0..5f3a3d8 100644 --- a/powerdnsadmin/templates/domain.html +++ b/powerdnsadmin/templates/domain.html @@ -43,6 +43,7 @@ Status TTL Data + Comment Edit Delete @@ -65,24 +66,28 @@ {{ record.data }} + + {{ record.comment }} + {% if domain.type != 'Slave' %} - {% if record.is_allowed_edit() %} - - {% else %} - - {% endif %} + {% if record.is_allowed_edit() %} + + {% else %} + + {% endif %} - {% if record.is_allowed_delete() %} - - {% endif %} + {% if record.is_allowed_delete() %} + + {% endif %} + {% else %} - + {% endif %} @@ -133,20 +138,20 @@ "columnDefs": [ { type: 'natural', - targets: [0, 4] + targets: [0, 5] }, { // hidden column so that we can add new records on top - // regardless of whatever sorting is done + // regardless of whatever sorting is done. See orderFixed visible: false, - targets: [ 7 ] + targets: [ 8 ] }, { className: "length-break", - targets: [ 4 ] + targets: [ 5 ] } ], - "orderFixed": [[7, 'asc']] + "orderFixed": [[8, 'asc']] }); // handle delete button @@ -238,7 +243,7 @@ // add new row var default_type = records_allow_edit[0] - var nRow = jQuery('#tbl_records').dataTable().fnAddData(['', default_type, 'Active', 3600, '', '', '', '0']); + var nRow = jQuery('#tbl_records').dataTable().fnAddData(['', default_type, 'Active', 3600, '', '', '', '', '0']); editRow($("#tbl_records").DataTable(), nRow); document.getElementById("edit-row-focus").focus(); nEditing = nRow; diff --git a/powerdnsadmin/templates/template_edit.html b/powerdnsadmin/templates/template_edit.html index 8706563..8c22ca9 100644 --- a/powerdnsadmin/templates/template_edit.html +++ b/powerdnsadmin/templates/template_edit.html @@ -41,6 +41,7 @@ Status TTL Data + Comment Edit Delete ID @@ -64,6 +65,9 @@ {{ record.data }} + + {{ record.comment }} +