mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-12-27 21:45:39 +00:00
Add first working draft of domain templating functionality
This commit is contained in:
parent
b6ed658cbd
commit
52a5789c85
@ -1039,7 +1039,9 @@ class Record(object):
|
||||
})
|
||||
|
||||
postdata_for_new = {"rrsets": final_records}
|
||||
|
||||
logging.info(postdata_for_new)
|
||||
logging.info(postdata_for_delete)
|
||||
logging.info(urlparse.urljoin(PDNS_STATS_URL, API_EXTENDED_URL + '/servers/localhost/zones/%s' % domain))
|
||||
try:
|
||||
headers = {}
|
||||
headers['X-API-Key'] = PDNS_API_KEY
|
||||
@ -1358,3 +1360,83 @@ class Setting(db.Model):
|
||||
logging.debug(traceback.format_exec())
|
||||
db.session.rollback()
|
||||
return False
|
||||
|
||||
|
||||
class DomainTemplate(db.Model):
|
||||
__tablename__ = "domain_template"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(255), index=True, unique=True)
|
||||
description = db.Column(db.String(255))
|
||||
records = db.relationship('DomainTemplateRecord', back_populates='template', cascade="all, delete-orphan")
|
||||
|
||||
def __repr__(self):
|
||||
return '<DomainTemplate %s>' % self.name
|
||||
|
||||
def __init__(self, name=None, description=None):
|
||||
self.id = None
|
||||
self.name = name
|
||||
self.description = description
|
||||
|
||||
def replace_records(self, records):
|
||||
try:
|
||||
self.records = []
|
||||
for record in records:
|
||||
self.records.append(record)
|
||||
db.session.commit()
|
||||
return {'status': 'ok', 'msg': 'Template records have been modified'}
|
||||
except Exception, e:
|
||||
logging.error('Cannot create template records' + str(e))
|
||||
db.session.rollback()
|
||||
return {'status': 'error', 'msg': 'Can not create template records'}
|
||||
|
||||
def create(self):
|
||||
try:
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
return {'status': 'ok', 'msg': 'Template has been created'}
|
||||
except Exception, e:
|
||||
logging.error('Can not update domain template table.' + str(e))
|
||||
db.session.rollback()
|
||||
return {'status': 'error', 'msg': 'Can not update domain template table'}
|
||||
|
||||
def delete_template(self):
|
||||
try:
|
||||
self.records = []
|
||||
db.session.delete(self)
|
||||
db.session.commit()
|
||||
return {'status': 'ok', 'msg': 'Template has been deleted'}
|
||||
except Exception, e:
|
||||
logging.error('Can not delete domain template.' + str(e))
|
||||
db.session.rollback()
|
||||
return {'status': 'error', 'msg': 'Can not delete domain template'}
|
||||
|
||||
|
||||
class DomainTemplateRecord(db.Model):
|
||||
__tablename__ = "domain_template_record"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(255))
|
||||
type = db.Column(db.String(64))
|
||||
ttl = db.Column(db.Integer)
|
||||
data = db.Column(db.String(255))
|
||||
status = db.Column(db.Boolean)
|
||||
template_id = db.Column(db.Integer, db.ForeignKey('domain_template.id'))
|
||||
template = db.relationship('DomainTemplate', back_populates='records')
|
||||
|
||||
def __repr__(self):
|
||||
return '<DomainTemplateRecord %i>' % self.id
|
||||
|
||||
def __init__(self, id=None, name=None, type=None, ttl=None, data=None, status=None):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.ttl = ttl
|
||||
self.data = data
|
||||
self.status = status
|
||||
|
||||
def apply(self):
|
||||
try:
|
||||
db.session.commit()
|
||||
except Exception, e:
|
||||
logging.error('Can not update domain template table.' + str(e))
|
||||
db.session.rollback()
|
||||
return {'status': 'error', 'msg': 'Can not update domain template table'}
|
||||
|
@ -127,6 +127,7 @@
|
||||
<li><a href="{{ url_for('domain_add') }}"><i class="fa fa-plus"></i> <span>New Domain</span></a></li>
|
||||
<li class="header">ADMINISTRATION</li>
|
||||
<li><a href="{{ url_for('admin') }}"><i class="fa fa-wrench"></i> <span>Admin Console</span></a></li>
|
||||
<li><a href="{{ url_for('templates') }}"><i class="fa fa-clone"></i> <span>Domain Templates</span></a></li>
|
||||
<li><a href="{{ url_for('admin_manageuser') }}"><i class="fa fa-users"></i> <span>Users</span></a></li>
|
||||
<li><a href="{{ url_for('admin_history') }}"><i class="fa fa-calendar"></i> <span>History</span></a></li>
|
||||
<li><a href="{{ url_for('admin_settings') }}"><i class="fa fa-cog"></i> <span>Settings</span></a></li>
|
||||
|
@ -47,6 +47,15 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Select a template</label>
|
||||
<select class="form-control" id="domain_template" name="domain_template">
|
||||
<option value="0">No template</option>
|
||||
{% for template in templates %}
|
||||
<option value="{{ template.id }}">{{ template.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="display: none;" id="domain_master_address_div">
|
||||
<input type="text" class="form-control" name="domain_master_address" id="domain_master_address" placeholder="Enter valid master ip addresses (separated by commas)">
|
||||
</div>
|
||||
|
119
app/templates/template.html
Normal file
119
app/templates/template.html
Normal file
@ -0,0 +1,119 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}<title>DNS Control Panel - Templates</title>{% endblock %}
|
||||
|
||||
{% block dashboard_stat %}
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Templates
|
||||
<small>List</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{{ url_for('templates') }}"><i class="fa fa-dashboard"></i> Templates</a></li>
|
||||
<li class="active">List</li>
|
||||
</ol>
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
{% with errors = get_flashed_messages(category_filter=["error"]) %} {% if errors %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-danger alert-dismissible">
|
||||
<button type="button" class="close" data-dismiss="alert"
|
||||
aria-hidden="true">×</button>
|
||||
<h4>
|
||||
<i class="icon fa fa-ban"></i> Error!
|
||||
</h4>
|
||||
<div class="alert-message block-message error">
|
||||
<a class="close" href="#">x</a>
|
||||
<ul>
|
||||
{%- for msg in errors %}
|
||||
<li>{{ msg }}</li> {% endfor -%}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %} {% endwith %}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Templates</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<a href="{{ url_for('create_template') }}">
|
||||
<button type="button" class="btn btn-flat btn-primary pull-left">
|
||||
Create Template <i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<table id="tbl_template_list" class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Number of Records</th>
|
||||
<th>Edit</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for template in templates %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ template.name }}</strong>
|
||||
</td>
|
||||
<td>
|
||||
{{ template.description }}
|
||||
</td>
|
||||
<td>
|
||||
{{ template.records|count }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('edit_template', template=template.name) }}">
|
||||
<button type="button" class="btn btn-flat btn-warning button_edit" id="">
|
||||
Edit <i class="fa fa-edit"></i>
|
||||
</button>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('delete_template', template=template.name) }}">
|
||||
<button type="button" class="btn btn-flat btn-danger button_delete" id="">
|
||||
Delete <i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
{% endblock %}
|
||||
{% block extrascripts %}
|
||||
<script>
|
||||
// set up history data table
|
||||
$("#tbl_template_list").DataTable({
|
||||
"paging" : true,
|
||||
"lengthChange" : true,
|
||||
"searching" : true,
|
||||
"ordering" : true,
|
||||
"info" : false,
|
||||
"autoWidth" : false
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block modals %}
|
||||
{% endblock %}
|
104
app/templates/template_add.html
Normal file
104
app/templates/template_add.html
Normal file
@ -0,0 +1,104 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}<title>DNS Control Panel - Create Template</title>{% endblock %}
|
||||
|
||||
{% block dashboard_stat %}
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Template
|
||||
<small>Create</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{{ url_for('templates') }}"><i class="fa fa-dashboard"></i> Templates</a></li>
|
||||
<li class="active">Create</li>
|
||||
</ol>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="content">
|
||||
{% with errors = get_flashed_messages(category_filter=["error"]) %} {%
|
||||
if errors %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-danger alert-dismissible">
|
||||
<button type="button" class="close" data-dismiss="alert"
|
||||
aria-hidden="true">×</button>
|
||||
<h4>
|
||||
<i class="icon fa fa-ban"></i> Error!
|
||||
</h4>
|
||||
<div class="alert-message block-message error">
|
||||
<a class="close" href="#">x</a>
|
||||
<ul>
|
||||
{%- for msg in errors %}
|
||||
<li>{{ msg }}</li> {% endfor -%}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %} {% endwith %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Create new template</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<!-- form start -->
|
||||
<form role="form" method="post"
|
||||
action="{{ url_for('create_template') }}">
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="name" id="name"
|
||||
placeholder="Enter a valid template name (required)">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="description"
|
||||
id="description"
|
||||
placeholder="Enter a template description (optional)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-flat btn-primary">Submit</button>
|
||||
<button type="button" class="btn btn-flat btn-default"
|
||||
onclick="window.location.href='{{ url_for('templates') }}'">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Help with creating a new template</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Template name</dt>
|
||||
<dd>Enter your template name, this is the name of the template that
|
||||
will be shown to users. The name should not have any spaces but
|
||||
can have symbols.</dd>
|
||||
<dt>Template description</dt>
|
||||
<dd>Enter your template description, this is to help better
|
||||
identify the template.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% block extrascripts %}
|
||||
<script>
|
||||
$("input[name=radio_type]").change(function() {
|
||||
var type = $(this).val();
|
||||
if (type == "slave") {
|
||||
$("#domain_master_address_div").show();
|
||||
} else {
|
||||
$("#domain_master_address_div").hide();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
415
app/templates/template_edit.html
Normal file
415
app/templates/template_edit.html
Normal file
@ -0,0 +1,415 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}<title>DNS Control Panel - Edit Template</title>{% endblock %}
|
||||
|
||||
{% block dashboard_stat %}
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Edit template <small>{{ template }}</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{{ url_for('dashboard') }}"><i
|
||||
class="fa fa-dashboard"></i> Home</a></li>
|
||||
<li>Templates</li>
|
||||
<li class="active">{{ template }}</li>
|
||||
</ol>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Manage Template Records for {{ template }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<button type="button" class="btn btn-flat btn-primary pull-left button_add_record" id="{{ template }}">
|
||||
Add Record <i class="fa fa-plus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-flat btn-primary pull-right button_apply_changes" id="{{ template }}">
|
||||
Apply Changes <i class="fa fa-floppy-o"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<table id="tbl_records" class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>TTL</th>
|
||||
<th>Data</th>
|
||||
<th>Edit</th>
|
||||
<th>Delete</th>
|
||||
<th>ID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for record in records %}
|
||||
<tr class="odd row_record" id="{{ record.name }}">
|
||||
<td>
|
||||
{{ record.name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ record.type }}
|
||||
</td>
|
||||
<td>
|
||||
{{ record.status }}
|
||||
</td>
|
||||
<td>
|
||||
{{ record.ttl }}
|
||||
</td>
|
||||
<td class="length-break">
|
||||
{{ record.data }}
|
||||
</td>
|
||||
<td width="6%">
|
||||
<button type="button" class="btn btn-flat btn-warning button_edit" id="{{ record.name }}">
|
||||
Edit <i class="fa fa-edit"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td width="6%">
|
||||
<button type="button" class="btn btn-flat btn-danger button_delete" id="{{ record.name }}">
|
||||
Delete <i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
{{ record.id }}
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% block extrascripts %}
|
||||
<script>
|
||||
// superglobals
|
||||
window.records_allow_edit = {{ editable_records|tojson }};
|
||||
window.nEditing = null;
|
||||
window.nNew = false;
|
||||
|
||||
// set up user data table
|
||||
$("#tbl_records").DataTable({
|
||||
"paging" : true,
|
||||
"lengthChange" : true,
|
||||
"searching" : true,
|
||||
"ordering" : true,
|
||||
"info" : true,
|
||||
"autoWidth" : false,
|
||||
{% if default_record_table_size_setting in ['5','15','20'] %}
|
||||
"lengthMenu": [ [5, 15, 20, -1],
|
||||
[5, 15, 20, "All"]],
|
||||
{% else %}
|
||||
"lengthMenu": [ [5, 15, 20, {{ default_record_table_size_setting }}, -1],
|
||||
[5, 15, 20, {{ default_record_table_size_setting }}, "All"]],
|
||||
{% endif %}
|
||||
"pageLength": {{ default_record_table_size_setting }},
|
||||
"language": {
|
||||
"lengthMenu": " _MENU_ records"
|
||||
},
|
||||
"retrieve" : true,
|
||||
"columnDefs": [{
|
||||
"targets": [ 7 ],
|
||||
"visible": false,
|
||||
"searchable": false
|
||||
}]
|
||||
|
||||
});
|
||||
|
||||
// handle delete button
|
||||
$(document.body).on("click", ".button_delete", function(e) {
|
||||
e.stopPropagation();
|
||||
var modal = $("#modal_delete");
|
||||
var table = $("#tbl_records").DataTable();
|
||||
var record = $(this).prop('id');
|
||||
var nRow = $(this).parents('tr')[0];
|
||||
var info = "Are you sure you want to delete " + record + "?";
|
||||
modal.find('.modal-body p').text(info);
|
||||
modal.find('#button_delete_confirm').click(function() {
|
||||
table.row(nRow).remove().draw();
|
||||
modal.modal('hide');
|
||||
})
|
||||
modal.modal('show');
|
||||
|
||||
});
|
||||
// handle edit button
|
||||
$(document.body).on("click", ".button_edit, .row_record", function(e) {
|
||||
e.stopPropagation();
|
||||
if ($(this).is('tr')) {
|
||||
var nRow = $(this)[0];
|
||||
} else {
|
||||
var nRow = $(this).parents('tr')[0];
|
||||
}
|
||||
var table = $("#tbl_records").DataTable();
|
||||
|
||||
if (nEditing == nRow) {
|
||||
/* click on row already being edited, do nothing */
|
||||
} else if (nEditing !== null && nEditing != nRow && nNew == false) {
|
||||
/* Currently editing - but not this row - restore the old before continuing to edit mode */
|
||||
restoreRow(table, nEditing);
|
||||
editRow(table, nRow);
|
||||
nEditing = nRow;
|
||||
} else if (nNew == true) {
|
||||
/* adding a new row, delete it and start editing */
|
||||
table.row(nEditing).remove().draw();
|
||||
nNew = false;
|
||||
editRow(table, nRow);
|
||||
nEditing = nRow;
|
||||
} else {
|
||||
/* No edit in progress - let's start one */
|
||||
editRow(table, nRow);
|
||||
nEditing = nRow;
|
||||
}
|
||||
});
|
||||
|
||||
// handle apply changes button
|
||||
$(document.body).on("click",".button_apply_changes", function() {
|
||||
var modal = $("#modal_apply_changes");
|
||||
var table = $("#tbl_records").DataTable();
|
||||
var template = $(this).prop('id');
|
||||
var info = "Are you sure you want to apply your changes?";
|
||||
modal.find('.modal-body p').text(info);
|
||||
modal.find('#button_apply_confirm').click(function() {
|
||||
var data = getTableData(table);
|
||||
applyChanges(data, '/template/' + template + '/apply', true);
|
||||
modal.modal('hide');
|
||||
})
|
||||
modal.modal('show');
|
||||
|
||||
});
|
||||
|
||||
// handle add record button
|
||||
$(document.body).on("click", ".button_add_record", function (e) {
|
||||
if (nNew || nEditing) {
|
||||
// TODO: replace this alert with modal
|
||||
alert("Previous record not saved. Please save it before adding more record.")
|
||||
return;
|
||||
}
|
||||
var table = $("#tbl_records").DataTable();
|
||||
|
||||
var aiNew = table.row.add(['', 'A', 'Active', 3600, '', '', '', '']).draw();
|
||||
var nRow = aiNew.index();
|
||||
editRow(table, nRow);
|
||||
nEditing = nRow;
|
||||
nNew = true;
|
||||
});
|
||||
|
||||
//handle cancel button
|
||||
$(document.body).on("click", ".button_cancel", function (e) {
|
||||
e.stopPropagation();
|
||||
var oTable = $("#tbl_records").DataTable();
|
||||
if (nNew) {
|
||||
oTable.row(nEditing).remove().draw();
|
||||
nEditing = null;
|
||||
nNew = false;
|
||||
} else {
|
||||
restoreRow(oTable, nEditing);
|
||||
nEditing = null;
|
||||
}
|
||||
});
|
||||
|
||||
//handle save button
|
||||
$(document.body).on("click", ".button_save", function (e) {
|
||||
e.stopPropagation();
|
||||
var table = $("#tbl_records").DataTable();
|
||||
saveRow(table, nEditing);
|
||||
nEditing = null;
|
||||
nNew = false;
|
||||
});
|
||||
|
||||
{% if record_helper_setting %}
|
||||
//handle wacky record types
|
||||
$(document.body).on("focus", "#current_edit_record_data", function (e) {
|
||||
var record_type = $(this).parents("tr").find('#record_type').val();
|
||||
var record_data = $(this);
|
||||
if (record_type == "MX") {
|
||||
var modal = $("#modal_custom_record");
|
||||
if (record_data.val() == "") {
|
||||
var form = " <label for=\"mx_priority\">MX Priority</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_priority\" id=\"mx_priority\" placeholder=\"10\"> \
|
||||
<label for=\"mx_server\">MX Server</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_server\" id=\"mx_server\" placeholder=\"postfix.example.com\"> \
|
||||
";
|
||||
} else {
|
||||
var parts = record_data.val().split(" ");
|
||||
var form = " <label for=\"mx_priority\">MX Priority</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_priority\" id=\"mx_priority\" placeholder=\"10\" value=\"" + parts[0] + "\"> \
|
||||
<label for=\"mx_server\">MX Server</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_server\" id=\"mx_server\" placeholder=\"postfix.example.com\" value=\"" + parts[1] + "\"> \
|
||||
";
|
||||
}
|
||||
modal.find('.modal-body p').html(form);
|
||||
modal.find('#button_save').click(function() {
|
||||
mx_server = modal.find('#mx_server').val();
|
||||
mx_priority = modal.find('#mx_priority').val();
|
||||
data = mx_priority + " " + mx_server;
|
||||
record_data.val(data);
|
||||
modal.modal('hide');
|
||||
})
|
||||
modal.modal('show');
|
||||
} else if (record_type == "SRV") {
|
||||
var modal = $("#modal_custom_record");
|
||||
if (record_data.val() == "") {
|
||||
var form = " <label for=\"srv_priority\">SRV Priority</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_priority\" id=\"srv_priority\" placeholder=\"0\"> \
|
||||
<label for=\"srv_weight\">SRV Weight</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_weight\" id=\"srv_weight\" placeholder=\"10\"> \
|
||||
<label for=\"srv_port\">SRV Port</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_port\" id=\"srv_port\" placeholder=\"5060\"> \
|
||||
<label for=\"srv_target\">SRV Target</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_target\" id=\"srv_target\" placeholder=\"sip.example.com\"> \
|
||||
";
|
||||
modal.modal('show');
|
||||
} else {
|
||||
var parts = record_data.val().split(" ");
|
||||
var form = " <label for=\"srv_priority\">SRV Priority</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_priority\" id=\"srv_priority\" placeholder=\"0\" value=\"" + parts[0] + "\"> \
|
||||
<label for=\"srv_weight\">SRV Weight</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_weight\" id=\"srv_weight\" placeholder=\"10\" value=\"" + parts[1] + "\"> \
|
||||
<label for=\"srv_port\">SRV Port</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_port\" id=\"srv_port\" placeholder=\"5060\" value=\"" + parts[2] + "\"> \
|
||||
<label for=\"srv_target\">SRV Target</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"srv_target\" id=\"srv_target\" placeholder=\"sip.example.com\" value=\"" + parts[3] + "\"> \
|
||||
";
|
||||
}
|
||||
modal.find('.modal-body p').html(form);
|
||||
modal.find('#button_save').click(function() {
|
||||
srv_priority = modal.find('#srv_priority').val();
|
||||
srv_weight = modal.find('#srv_weight').val();
|
||||
srv_port = modal.find('#srv_port').val();
|
||||
srv_target = modal.find('#srv_target').val();
|
||||
data = srv_priority + " " + srv_weight + " " + srv_port + " " + srv_target;
|
||||
record_data.val(data);
|
||||
modal.modal('hide');
|
||||
})
|
||||
} else if (record_type == "SOA") {
|
||||
var modal = $("#modal_custom_record");
|
||||
if (record_data.val() == "") {
|
||||
var form = " <label for=\"soa_primaryns\">Primary Name Server</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_primaryns\" id=\"soa_primaryns\" placeholder=\"ns1.example.com\"> \
|
||||
<label for=\"soa_adminemail\">Primary Contact</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_adminemail\" id=\"soa_adminemail\" placeholder=\"admin.example.com\"> \
|
||||
<label for=\"soa_serial\">Serial</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_serial\" id=\"soa_serial\" placeholder=\"2016010101\"> \
|
||||
<label for=\"soa_zonerefresh\">Zone refresh timer</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_zonerefresh\" id=\"soa_zonerefresh\" placeholder=\"86400\"> \
|
||||
<label for=\"soa_failedzonerefresh\">Failed refresh retry timer</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_failedzonerefresh\" id=\"soa_failedzonerefresh\" placeholder=\"7200\"> \
|
||||
<label for=\"soa_zoneexpiry\">Zone expiry timer</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_zoneexpiry\" id=\"soa_zoneexpiry\" placeholder=\"604800\"> \
|
||||
<label for=\"soa_minimumttl\">Minimum TTL</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_minimumttl\" id=\"soa_minimumttl\" placeholder=\"300\"> \
|
||||
";
|
||||
} else {
|
||||
var parts = record_data.val().split(" ");
|
||||
var form = " <label for=\"soa_primaryns\">Primary Name Server</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_primaryns\" id=\"soa_primaryns\" value=\"" + parts[0] + "\"> \
|
||||
<label for=\"soa_adminemail\">Primary Contact</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_adminemail\" id=\"soa_adminemail\" value=\"" + parts[1] + "\"> \
|
||||
<label for=\"soa_serial\">Serial</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_serial\" id=\"soa_serial\" value=\"" + parts[2] + "\"> \
|
||||
<label for=\"soa_zonerefresh\">Zone refresh timer</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_zonerefresh\" id=\"soa_zonerefresh\" value=\"" + parts[3] + "\"> \
|
||||
<label for=\"soa_failedzonerefresh\">Failed refresh retry timer</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_failedzonerefresh\" id=\"soa_failedzonerefresh\" value=\"" + parts[4] + "\"> \
|
||||
<label for=\"soa_zoneexpiry\">Zone expiry timer</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_zoneexpiry\" id=\"soa_zoneexpiry\" value=\"" + parts[5] + "\"> \
|
||||
<label for=\"soa_minimumttl\">Minimum TTL</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"soa_minimumttl\" id=\"soa_minimumttl\" value=\"" + parts[6] + "\"> \
|
||||
";
|
||||
}
|
||||
modal.find('.modal-body p').html(form);
|
||||
modal.find('#button_save').click(function() {
|
||||
soa_primaryns = modal.find('#soa_primaryns').val();
|
||||
soa_adminemail = modal.find('#soa_adminemail').val();
|
||||
soa_serial = modal.find('#soa_serial').val();
|
||||
soa_zonerefresh = modal.find('#soa_zonerefresh').val();
|
||||
soa_failedzonerefresh = modal.find('#soa_failedzonerefresh').val();
|
||||
soa_zoneexpiry = modal.find('#soa_zoneexpiry').val();
|
||||
soa_minimumttl = modal.find('#soa_minimumttl').val();
|
||||
|
||||
data = soa_primaryns + " " + soa_adminemail + " " + soa_serial + " " + soa_zonerefresh + " " + soa_failedzonerefresh + " " + soa_zoneexpiry + " " + soa_minimumttl;
|
||||
record_data.val(data);
|
||||
modal.modal('hide');
|
||||
})
|
||||
modal.modal('show');
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block modals %}
|
||||
<div class="modal fade modal-warning" id="modal_delete">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Confirmation</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-flat btn-default pull-left"
|
||||
data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-flat btn-danger" id="button_delete_confirm">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.modal-content -->
|
||||
</div>
|
||||
<!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal fade modal-primary" id="modal_apply_changes">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Confirmation</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-flat btn-default pull-left"
|
||||
data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-flat btn-primary" id="button_apply_confirm">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.modal-content -->
|
||||
</div>
|
||||
<!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal fade modal-primary" id="modal_custom_record">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Custom Record</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-flat btn-primary" id="button_save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.modal-content -->
|
||||
</div>
|
||||
<!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endblock %}
|
137
app/views.py
137
app/views.py
@ -11,12 +11,12 @@ from io import BytesIO
|
||||
import jinja2
|
||||
import qrcode as qrc
|
||||
import qrcode.image.svg as qrc_svg
|
||||
from flask import g, request, make_response, jsonify, render_template, session, redirect, url_for, send_from_directory, abort
|
||||
from flask import g, request, make_response, jsonify, render_template, session, redirect, url_for, send_from_directory, abort, flash
|
||||
from flask_login import login_user, logout_user, current_user, login_required
|
||||
from werkzeug import secure_filename
|
||||
from werkzeug.security import gen_salt
|
||||
|
||||
from .models import User, Domain, Record, Server, History, Anonymous, Setting, DomainSetting
|
||||
from .models import User, Domain, Record, Server, History, Anonymous, Setting, DomainSetting, DomainTemplate, DomainTemplateRecord
|
||||
from app import app, login_manager, github
|
||||
from lib import utils
|
||||
|
||||
@ -331,10 +331,12 @@ def domain(domain_name):
|
||||
@login_required
|
||||
@admin_role_required
|
||||
def domain_add():
|
||||
templates = DomainTemplate.query.all()
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
domain_name = request.form.getlist('domain_name')[0]
|
||||
domain_type = request.form.getlist('radio_type')[0]
|
||||
domain_template = request.form.getlist('domain_template')[0]
|
||||
soa_edit_api = request.form.getlist('radio_type_soa_edit_api')[0]
|
||||
|
||||
if ' ' in domain_name or not domain_name or not domain_type:
|
||||
@ -352,12 +354,27 @@ def domain_add():
|
||||
if result['status'] == 'ok':
|
||||
history = History(msg='Add domain %s' % domain_name, detail=str({'domain_type': domain_type, 'domain_master_ips': domain_master_ips}), created_by=current_user.username)
|
||||
history.add()
|
||||
if domain_template != '0':
|
||||
template = DomainTemplate.query.filter(DomainTemplate.id == domain_template).first()
|
||||
template_records = DomainTemplateRecord.query.filter(DomainTemplateRecord.template_id == domain_template).all()
|
||||
record_data = []
|
||||
for template_record in template_records:
|
||||
record_row = {'record_data': template_record.data, 'record_name': template_record.name, 'record_status': template_record.status, 'record_ttl': template_record.ttl, 'record_type': template_record.type}
|
||||
record_data.append(record_row)
|
||||
r = Record()
|
||||
result = r.apply(domain_name, record_data)
|
||||
if result['status'] == 'ok':
|
||||
history = History(msg='Applying template %s to %s, created records successfully.' % (template.name, domain_name), detail=str(result), created_by=current_user.username)
|
||||
history.add()
|
||||
else:
|
||||
history = History(msg='Applying template %s to %s, FAILED to created records.' % (template.name, domain_name), detail=str(result), created_by=current_user.username)
|
||||
history.add()
|
||||
return redirect(url_for('dashboard'))
|
||||
else:
|
||||
return render_template('errors/400.html', msg=result['msg']), 400
|
||||
except:
|
||||
return redirect(url_for('error', code=500))
|
||||
return render_template('domain_add.html')
|
||||
return render_template('domain_add.html', templates=templates)
|
||||
|
||||
|
||||
@app.route('/admin/domain/<string:domain_name>/delete', methods=['GET'])
|
||||
@ -518,6 +535,120 @@ def admin_setdomainsetting(domain_name):
|
||||
return make_response(jsonify( { 'status': 'error', 'msg': 'There is something wrong, please contact Administrator.' } ), 400)
|
||||
|
||||
|
||||
@app.route('/templates', methods=['GET', 'POST'])
|
||||
@app.route('/templates/list', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@admin_role_required
|
||||
def templates():
|
||||
templates = DomainTemplate.query.all()
|
||||
return render_template('template.html', templates=templates)
|
||||
|
||||
|
||||
@app.route('/template/create', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@admin_role_required
|
||||
def create_template():
|
||||
if request.method == 'GET':
|
||||
return render_template('template_add.html')
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
name = request.form.getlist('name')[0]
|
||||
description = request.form.getlist('description')[0]
|
||||
|
||||
if ' ' in name or not name or not type:
|
||||
flash("Please correct your input", 'error')
|
||||
return redirect(url_for('create_template'))
|
||||
|
||||
if DomainTemplate.query.filter(DomainTemplate.name == name).first():
|
||||
flash("A template with the name %s already exists!" % name, 'error')
|
||||
return redirect(url_for('create_template'))
|
||||
t = DomainTemplate(name=name, description=description)
|
||||
result = t.create()
|
||||
if result['status'] == 'ok':
|
||||
history = History(msg='Add domain template %s' % name, detail=str({'name': name, 'description': description}), created_by=current_user.username)
|
||||
history.add()
|
||||
return redirect(url_for('templates'))
|
||||
else:
|
||||
flash(result['msg'], 'error')
|
||||
return redirect(url_for('create_template'))
|
||||
except Exception:
|
||||
print traceback.format_exc()
|
||||
return redirect(url_for('error', code=500))
|
||||
return redirect(url_for('templates'))
|
||||
|
||||
|
||||
@app.route('/template/<string:template>/edit', methods=['GET'])
|
||||
@login_required
|
||||
@admin_role_required
|
||||
def edit_template(template):
|
||||
try:
|
||||
t = DomainTemplate.query.filter(DomainTemplate.name == template).first()
|
||||
if t is not None:
|
||||
records = []
|
||||
for jr in t.records:
|
||||
if jr.type in app.config['RECORDS_ALLOW_EDIT']:
|
||||
record = DomainTemplateRecord(name=jr.name, type=jr.type, status='Disabled' if jr.status else 'Active', ttl=jr.ttl, data=jr.data)
|
||||
records.append(record)
|
||||
|
||||
return render_template('template_edit.html', template=t.name, records=records, editable_records=app.config['RECORDS_ALLOW_EDIT'])
|
||||
except Exception:
|
||||
print traceback.format_exc()
|
||||
return redirect(url_for('error', code=500))
|
||||
return redirect(url_for('templates'))
|
||||
|
||||
|
||||
@app.route('/template/<string:template>/apply', methods=['POST'], strict_slashes=False)
|
||||
@login_required
|
||||
def apply_records(template):
|
||||
try:
|
||||
pdata = request.data
|
||||
jdata = json.loads(pdata)
|
||||
records = []
|
||||
|
||||
for j in jdata:
|
||||
name = '@' if j['record_name'] in ['@', ''] else j['record_name']
|
||||
type = j['record_type']
|
||||
data = j['record_data']
|
||||
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, status=disabled, ttl=ttl)
|
||||
records.append(dtr)
|
||||
|
||||
t = DomainTemplate.query.filter(DomainTemplate.name == template).first()
|
||||
result = t.replace_records(records)
|
||||
if result['status'] == 'ok':
|
||||
history = History(msg='Apply domain template record changes to domain template %s' % template, detail=str(jdata), created_by=current_user.username)
|
||||
history.add()
|
||||
return make_response(jsonify(result), 200)
|
||||
else:
|
||||
return make_response(jsonify(result), 400)
|
||||
except:
|
||||
print traceback.format_exc()
|
||||
return make_response(jsonify({'status': 'error', 'msg': 'Error when applying new changes'}), 500)
|
||||
|
||||
|
||||
@app.route('/template/<string:template>/delete', methods=['GET'])
|
||||
@login_required
|
||||
@admin_role_required
|
||||
def delete_template(template):
|
||||
try:
|
||||
t = DomainTemplate.query.filter(DomainTemplate.name == template).first()
|
||||
if t is not None:
|
||||
result = t.delete_template()
|
||||
if result['status'] == 'ok':
|
||||
history = History(msg='Deleted domain template %s' % template, detail=str({'name': template}), created_by=current_user.username)
|
||||
history.add()
|
||||
return redirect(url_for('templates'))
|
||||
else:
|
||||
flash(result['msg'], 'error')
|
||||
return redirect(url_for('templates'))
|
||||
except Exception:
|
||||
print traceback.format_exc()
|
||||
return redirect(url_for('error', code=500))
|
||||
return redirect(url_for('templates'))
|
||||
|
||||
|
||||
@app.route('/admin', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@admin_role_required
|
||||
|
26
create_db.py
26
create_db.py
@ -4,7 +4,7 @@ from migrate.versioning import api
|
||||
from config import SQLALCHEMY_DATABASE_URI
|
||||
from config import SQLALCHEMY_MIGRATE_REPO
|
||||
from app import db
|
||||
from app.models import Role, Setting
|
||||
from app.models import Role, Setting, DomainTemplate
|
||||
import os.path
|
||||
import time
|
||||
import sys
|
||||
@ -65,6 +65,23 @@ def init_settings(db, setting_names):
|
||||
for setting in settings:
|
||||
db.session.add(setting)
|
||||
|
||||
|
||||
def init_domain_templates(db, domain_template_names):
|
||||
|
||||
# Get key name of data
|
||||
name_of_domain_templates = map(lambda r: r.name, domain_template_names)
|
||||
|
||||
# Query to get current data
|
||||
rows = db.session.query(DomainTemplate).filter(DomainTemplate.name.in_(name_of_domain_templates)).all()
|
||||
|
||||
# Check which data that need to insert
|
||||
name_of_rows = map(lambda r: r.name, rows)
|
||||
domain_templates = filter(lambda r: r.name not in name_of_rows, domain_template_names)
|
||||
|
||||
# Insert data
|
||||
for domain_template in domain_templates:
|
||||
db.session.add(domain_template)
|
||||
|
||||
def init_records():
|
||||
# Create initial user roles and turn off maintenance mode
|
||||
init_roles(db, [
|
||||
@ -80,7 +97,12 @@ def init_records():
|
||||
Setting('default_domain_table_size', '10'),
|
||||
Setting('auto_ptr','False')
|
||||
])
|
||||
|
||||
# TODO: add sample records to sample templates
|
||||
init_domain_templates(db, [
|
||||
DomainTemplate('basic_template_1', 'Basic Template #1'),
|
||||
DomainTemplate('basic_template_2', 'Basic Template #2'),
|
||||
DomainTemplate('basic_template_3', 'Basic Template #3')
|
||||
])
|
||||
db_commit = db.session.commit()
|
||||
commit_version_control(db_commit)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user