mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-11-09 23:20:27 +00:00
Merge pull request #46 from ivanfilippov/new_ui
Update 'new_ui' branch on main repo
This commit is contained in:
commit
a4a48d6b01
17
README.md
17
README.md
@ -5,12 +5,15 @@ PowerDNS Web-GUI - Built by Flask
|
|||||||
- Multiple domain management
|
- Multiple domain management
|
||||||
- Local / LDAP user authentication
|
- Local / LDAP user authentication
|
||||||
- User management
|
- User management
|
||||||
- User access management base on domain
|
- User access management based on domain
|
||||||
- User activity logging
|
- User activity logging
|
||||||
- Dashboard and pdns service statistics
|
- Dashboard and pdns service statistics
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
### PowerDNS Version Support:
|
||||||
|
PowerDNS-Admin supports PowerDNS autoritative server versions **3.4.2** and higher but does **not** yet support PowerDNS 4.0.0
|
||||||
|
|
||||||
### pdns Service
|
### pdns Service
|
||||||
I assume that you have already installed powerdns service. Make sure that your `/etc/pdns/pdns.conf` has these contents
|
I assume that you have already installed powerdns service. Make sure that your `/etc/pdns/pdns.conf` has these contents
|
||||||
```
|
```
|
||||||
@ -30,7 +33,7 @@ MariaDB [(none)]> GRANT ALL PRIVILEGES ON powerdnsadmin.* TO powerdnsadmin@'%' I
|
|||||||
|
|
||||||
### PowerDNS-Admin
|
### PowerDNS-Admin
|
||||||
|
|
||||||
In this installation guide, I am using CentOS 7 and run my python stuffs with *virtualenv*. If you don't have it, let install:
|
In this installation guide, I am using CentOS 7 and run my python stuffs with *virtualenv*. If you don't have it, lets install it:
|
||||||
```
|
```
|
||||||
$ sudo yum install python-pip
|
$ sudo yum install python-pip
|
||||||
$ sudo pip install virtualenv
|
$ sudo pip install virtualenv
|
||||||
@ -55,7 +58,7 @@ Web application configuration is stored in `config.py` file. Let's clone it from
|
|||||||
|
|
||||||
Create database after having proper configs
|
Create database after having proper configs
|
||||||
```
|
```
|
||||||
(flask)% ./createdb.py
|
(flask)% ./create_db.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -64,5 +67,9 @@ Run the application and enjoy!
|
|||||||
(flask)$ ./run.py
|
(flask)$ ./run.py
|
||||||
```
|
```
|
||||||
|
|
||||||
### Screenshot
|
### Screenshots
|
||||||
![Alt text](http://i.imgur.com/wA5qy2d.png)
|
![login page](https://github.com/ngoduykhanh/PowerDNS-Admin/wiki/images/readme_screenshots/fullscreen-login.png?raw=true)
|
||||||
|
![dashboard](https://github.com/ngoduykhanh/PowerDNS-Admin/wiki/images/readme_screenshots/fullscreen-dashboard.png?raw=true)
|
||||||
|
![create domain page](https://github.com/ngoduykhanh/PowerDNS-Admin/wiki/images/readme_screenshots/fullscreen-domaincreate.png?raw=true)
|
||||||
|
![manage domain page](https://github.com/ngoduykhanh/PowerDNS-Admin/wiki/images/readme_screenshots/fullscreen-domainmanage.png?raw=true)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
function applyChanges(data, url, showResult) {
|
function applyChanges(data, url, showResult, refreshPage) {
|
||||||
var success = false;
|
var success = false;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
@ -14,6 +14,9 @@ function applyChanges(data, url, showResult) {
|
|||||||
modal.find('.modal-body p').text("Applied changes successfully");
|
modal.find('.modal-body p').text("Applied changes successfully");
|
||||||
modal.modal('show');
|
modal.modal('show');
|
||||||
}
|
}
|
||||||
|
if (refreshPage) {
|
||||||
|
location.reload(true);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
error : function(jqXHR, status) {
|
error : function(jqXHR, status) {
|
||||||
@ -91,7 +94,7 @@ function editRow(oTable, nRow) {
|
|||||||
jqTds[1].innerHTML = '<select class="form-control" id="record_type" name="record_type" value="' + aData[1] + '"' + '>' + record_types + '</select>';
|
jqTds[1].innerHTML = '<select class="form-control" id="record_type" name="record_type" value="' + aData[1] + '"' + '>' + record_types + '</select>';
|
||||||
jqTds[2].innerHTML = '<select class="form-control" id="record_status" name="record_status" value="' + aData[2] + '"' + '><option value="false">Active</option><option value="true">Disabled</option></select>';
|
jqTds[2].innerHTML = '<select class="form-control" id="record_status" name="record_status" value="' + aData[2] + '"' + '><option value="false">Active</option><option value="true">Disabled</option></select>';
|
||||||
jqTds[3].innerHTML = '<select class="form-control" id="record_ttl" name="record_ttl" value="' + aData[3] + '"' + '><option value="60">1 minute</option><option value="300">5 minutes</option><option value="1800">30 minutes</option><option value="3600">60 minutes</option><option value="86400">24 hours</option></select>';
|
jqTds[3].innerHTML = '<select class="form-control" id="record_ttl" name="record_ttl" value="' + aData[3] + '"' + '><option value="60">1 minute</option><option value="300">5 minutes</option><option value="1800">30 minutes</option><option value="3600">60 minutes</option><option value="86400">24 hours</option></select>';
|
||||||
jqTds[4].innerHTML = '<input type="text" style="display:table-cell; width:100% !important" class="form-control input-small advance-data" value="' + aData[4].replace(/\"/g,""") + '">';
|
jqTds[4].innerHTML = '<input type="text" style="display:table-cell; width:100% !important" id="current_edit_record_data" name="current_edit_record_data" class="form-control input-small advance-data" value="' + aData[4].replace(/\"/g,""") + '">';
|
||||||
jqTds[5].innerHTML = '<button type="button" class="btn btn-flat btn-primary button_save">Save</button>';
|
jqTds[5].innerHTML = '<button type="button" class="btn btn-flat btn-primary button_save">Save</button>';
|
||||||
jqTds[6].innerHTML = '<button type="button" class="btn btn-flat btn-primary button_cancel">Cancel</button>';
|
jqTds[6].innerHTML = '<button type="button" class="btn btn-flat btn-primary button_cancel">Cancel</button>';
|
||||||
|
|
||||||
|
91
app/templates/admin_createuser.html
Normal file
91
app/templates/admin_createuser.html
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}<title>DNS Control Panel - Create User</title>{% endblock %}
|
||||||
|
|
||||||
|
{% block dashboard_stat %}
|
||||||
|
<!-- Content Header (Page header) -->
|
||||||
|
<section class="content-header">
|
||||||
|
<h1>
|
||||||
|
User
|
||||||
|
<small>Create new</small>
|
||||||
|
</h1>
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{{ url_for('dashboard') }}"><i class="fa fa-dashboard"></i>Home</a></li>
|
||||||
|
<li><a href="{{ url_for('dashboard') }}">Admin</a></li>
|
||||||
|
<li class="active">Create user</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="content">
|
||||||
|
<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 user</h3>
|
||||||
|
</div>
|
||||||
|
<!-- /.box-header -->
|
||||||
|
<!-- form start -->
|
||||||
|
<form role="form" method="post" action="{{ url_for('admin_createuser') }}">
|
||||||
|
<div class="box-body">
|
||||||
|
<div class="form-group has-feedback">
|
||||||
|
<label class="control-label" for="firstname">First Name</label>
|
||||||
|
<input type="text" class="form-control" placeholder="First Name"
|
||||||
|
name="firstname" {% if user %}value={{ user.firstname }}{% endif %}> <span
|
||||||
|
class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-feedback">
|
||||||
|
<label class="control-label" for="lastname">Last Name</label>
|
||||||
|
<input type="text" class="form-control" placeholder="Last name"
|
||||||
|
name="lastname" {% if user %}value={{ user.lastname }}{% endif %}> <span
|
||||||
|
class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-feedback {% if duplicate_email %}has-error{% endif %}">
|
||||||
|
<label class="control-label" for="email">E-mail address</label>
|
||||||
|
<input type="email" class="form-control" placeholder="Email"
|
||||||
|
name="email" id="email" {% if user %}value={{ user.email }}{% endif %}> <span
|
||||||
|
class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||||
|
{% if duplicate_email %}
|
||||||
|
<span class="help-block">This e-mail address is already in use.</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<p class="login-box-msg">Enter the account details below</p>
|
||||||
|
<div class="form-group has-feedback {% if duplicate_username %}has-error{% endif %}">
|
||||||
|
<label class="control-label" for="username">Username</label>
|
||||||
|
<input type="text" class="form-control" placeholder="Username"
|
||||||
|
name="username" {% if user %}value={{ user.username }}{% endif %}> <span
|
||||||
|
class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||||
|
{% if duplicate_username %}
|
||||||
|
<span class="help-block">This username is already in use.</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-feedback {% if blank_password %}has-error{% endif %}">
|
||||||
|
<label class="control-label" for="username">Password</label>
|
||||||
|
<input type="password" class="form-control" placeholder="Password"
|
||||||
|
name="password"> <span
|
||||||
|
class="glyphicon glyphicon-lock form-control-feedback"></span>
|
||||||
|
{% if blank_password %}
|
||||||
|
<span class="help-block">The password cannot be blank.</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
<button type="submit" class="btn btn-flat btn-primary">Create User</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</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 user</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
<p>Fill in all the fields to the in the form to the left.</p>
|
||||||
|
<p><strong>Newly created users do not have access to any domains.</strong> You will need to grant access to the user once it is created via the domain management buttons on the dashboard.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
@ -19,6 +19,13 @@
|
|||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
<h3 class="box-title">User Management</h3>
|
<h3 class="box-title">User Management</h3>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
<a href="{{ url_for('admin_createuser') }}">
|
||||||
|
<button type="button" class="btn btn-flat btn-primary pull-left button_add_user">
|
||||||
|
Add User <i class="fa fa-plus"></i>
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<table id="tbl_users" class="table table-bordered table-striped">
|
<table id="tbl_users" class="table table-bordered table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
@ -97,9 +104,8 @@
|
|||||||
modal.find('.modal-body p').text(info);
|
modal.find('.modal-body p').text(info);
|
||||||
modal.find('#button_delete_confirm').click(function() {
|
modal.find('#button_delete_confirm').click(function() {
|
||||||
var postdata = {'action': 'delete_user', 'data': username}
|
var postdata = {'action': 'delete_user', 'data': username}
|
||||||
applyChanges(postdata, '/admin/manageuser');
|
applyChanges(postdata, '/admin/manageuser', false, true);
|
||||||
modal.modal('hide');
|
modal.modal('hide');
|
||||||
location.reload();
|
|
||||||
})
|
})
|
||||||
modal.modal('show');
|
modal.modal('show');
|
||||||
|
|
||||||
|
@ -73,65 +73,13 @@
|
|||||||
|
|
||||||
$(".setting-toggle-button").click(function() {
|
$(".setting-toggle-button").click(function() {
|
||||||
var setting = $(this).prop('id');
|
var setting = $(this).prop('id');
|
||||||
applyChanges('','/admin/setting/' + setting + '/toggle')
|
applyChanges('','/admin/setting/' + setting + '/toggle', false, true)
|
||||||
location.reload();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: allow editing of value field
|
// TODO: allow editing of value field
|
||||||
$(".setting-edit-button").click(function() {
|
$(".setting-edit-button").click(function() {
|
||||||
var setting = $(this).prop('id');
|
var setting = $(this).prop('id');
|
||||||
applyChanges('','/admin/setting/' + setting + '/edit')
|
applyChanges('','/admin/setting/' + setting + '/edit', false, true)
|
||||||
location.reload();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block modals %}
|
|
||||||
<!-- Clear History Confirmation Box -->
|
|
||||||
<div class="modal fade modal-warning" id="modal_clear_history">
|
|
||||||
<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>Are you sure you want to remove all history?</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" onclick="applyChanges('', '/admin/history');location.reload();">Clear
|
|
||||||
History</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-content -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-dialog -->
|
|
||||||
</div>
|
|
||||||
<div class="modal fade" id="modal_history_info">
|
|
||||||
<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">History Details</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-flat btn-default pull-right"
|
|
||||||
data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-content -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-dialog -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal -->
|
|
||||||
{% endblock %}
|
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="navbar-custom-menu">
|
<div class="navbar-custom-menu">
|
||||||
|
{% if current_user.id is defined %}
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<!-- User Account: style can be found in dropdown.less -->
|
<!-- User Account: style can be found in dropdown.less -->
|
||||||
<li class="dropdown user user-menu">
|
<li class="dropdown user user-menu">
|
||||||
@ -71,18 +72,18 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<!-- User image -->
|
<li class="user-header">
|
||||||
<li class="user-header">
|
{% if current_user.avatar %}
|
||||||
{% if current_user.avatar %}
|
<img src="{{ url_for('user_avatar', filename=current_user.avatar) }}" class="img-circle" alt="User Image"/>
|
||||||
<img src="{{ url_for('user_avatar', filename=current_user.avatar) }}" class="img-circle" alt="User Image"/>
|
{% else %}
|
||||||
{% else %}
|
<img src="{{ url_for('static', filename='adminlte2/dist/img/avatar.png') }}" class="img-circle" alt="User Image"/>
|
||||||
<img src="{{ url_for('static', filename='adminlte2/dist/img/avatar.png') }}" class="img-circle" alt="User Image"/>
|
{% endif %}
|
||||||
{% endif %}
|
<p>
|
||||||
<p>
|
{{ current_user.firstname }} {{ current_user.lastname }}
|
||||||
{{ current_user.firstname }} {{ current_user.lastname }}
|
<small>{{ current_user.role.name }}</small>
|
||||||
<small>{{ current_user.role.name }}</small>
|
</p>
|
||||||
</p>
|
</li>
|
||||||
</li>
|
|
||||||
<!-- Menu Footer-->
|
<!-- Menu Footer-->
|
||||||
<li class="user-footer">
|
<li class="user-footer">
|
||||||
<div class="pull-left">
|
<div class="pull-left">
|
||||||
@ -95,6 +96,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
@ -103,7 +105,7 @@
|
|||||||
<aside class="main-sidebar">
|
<aside class="main-sidebar">
|
||||||
<!-- sidebar: style can be found in sidebar.less -->
|
<!-- sidebar: style can be found in sidebar.less -->
|
||||||
<section class="sidebar">
|
<section class="sidebar">
|
||||||
<!-- Sidebar user panel -->
|
{% if current_user.id is defined %}
|
||||||
<div class="user-panel">
|
<div class="user-panel">
|
||||||
<div class="pull-left image">
|
<div class="pull-left image">
|
||||||
{% if current_user.avatar %}
|
{% if current_user.avatar %}
|
||||||
@ -117,7 +119,6 @@
|
|||||||
<a href="#"><i class="fa fa-circle text-success"></i> Logged In</a>
|
<a href="#"><i class="fa fa-circle text-success"></i> Logged In</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.search form -->
|
|
||||||
<!-- sidebar menu: : style can be found in sidebar.less -->
|
<!-- sidebar menu: : style can be found in sidebar.less -->
|
||||||
<ul class="sidebar-menu">
|
<ul class="sidebar-menu">
|
||||||
<li class="header">USER ACTIONS</li>
|
<li class="header">USER ACTIONS</li>
|
||||||
@ -130,6 +131,7 @@
|
|||||||
<li><a href="{{ url_for('admin_history') }}"><i class="fa fa-calendar"></i> <span>History</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>
|
<li><a href="{{ url_for('admin_settings') }}"><i class="fa fa-cog"></i> <span>Settings</span></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
<!-- /.sidebar -->
|
<!-- /.sidebar -->
|
||||||
</aside>
|
</aside>
|
||||||
@ -149,102 +151,8 @@
|
|||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<!-- Main content -->
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="content">
|
|
||||||
<!-- Small boxes (Stat box) -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-3 col-xs-6">
|
|
||||||
<!-- small box -->
|
|
||||||
<div class="small-box bg-aqua">
|
|
||||||
<div class="inner">
|
|
||||||
<h3>150</h3>
|
|
||||||
<p>Domains</p>
|
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-bag"></i>
|
|
||||||
</div>
|
|
||||||
<a href="#" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- ./col -->
|
|
||||||
<div class="col-lg-3 col-xs-6">
|
|
||||||
<!-- small box -->
|
|
||||||
<div class="small-box bg-green">
|
|
||||||
<div class="inner">
|
|
||||||
<h3>53<sup style="font-size: 20px">%</sup></h3>
|
|
||||||
<p>Users</p>
|
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-stats-bars"></i>
|
|
||||||
</div>
|
|
||||||
<a href="#" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- ./col -->
|
|
||||||
<div class="col-lg-3 col-xs-6">
|
|
||||||
<!-- small box -->
|
|
||||||
<div class="small-box bg-yellow">
|
|
||||||
<div class="inner">
|
|
||||||
<h3>44</h3>
|
|
||||||
<p>Histories</p>
|
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-person-add"></i>
|
|
||||||
</div>
|
|
||||||
<a href="#" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- ./col -->
|
|
||||||
<div class="col-lg-3 col-xs-6">
|
|
||||||
<!-- small box -->
|
|
||||||
<div class="small-box bg-red">
|
|
||||||
<div class="inner">
|
|
||||||
<h3>65</h3>
|
|
||||||
<p>Uptime</p>
|
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-pie-graph"></i>
|
|
||||||
</div>
|
|
||||||
<a href="#" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- ./col -->
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
<!-- Main row -->
|
|
||||||
<div class="row">
|
|
||||||
<!-- Left col -->
|
|
||||||
<section class="col-lg-7 connectedSortable">
|
|
||||||
<!-- Custom tabs (Charts with tabs)-->
|
|
||||||
<div class="nav-tabs-custom">
|
|
||||||
<!-- Tabs within a box -->
|
|
||||||
<ul class="nav nav-tabs pull-right">
|
|
||||||
<li class="active"><a href="#revenue-chart" data-toggle="tab">Area</a></li>
|
|
||||||
<li><a href="#sales-chart" data-toggle="tab">Donut</a></li>
|
|
||||||
<li class="pull-left header"><i class="fa fa-inbox"></i> Sales</li>
|
|
||||||
</ul>
|
|
||||||
<div class="tab-content no-padding">
|
|
||||||
<!-- Morris chart - Sales -->
|
|
||||||
<div class="chart tab-pane active" id="revenue-chart" style="position: relative; height: 300px;"></div>
|
|
||||||
<div class="chart tab-pane" id="sales-chart" style="position: relative; height: 300px;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.nav-tabs-custom -->
|
|
||||||
</section>
|
|
||||||
<!-- /.Left col -->
|
|
||||||
<!-- right col (We are only adding the ID to make the widgets sortable)-->
|
|
||||||
<section class="col-lg-5 connectedSortable">
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- right col -->
|
|
||||||
</div>
|
|
||||||
<!-- /.row (main row) -->
|
|
||||||
|
|
||||||
</section>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<!-- /.content -->
|
|
||||||
</div>
|
</div>
|
||||||
<!-- /.content-wrapper -->
|
<!-- /.content-wrapper -->
|
||||||
<footer class="main-footer">
|
<footer class="main-footer">
|
||||||
|
@ -246,6 +246,75 @@
|
|||||||
var domain = $(this).prop('id');
|
var domain = $(this).prop('id');
|
||||||
applyChanges({'domain': domain}, '/domain/' + domain + '/update');
|
applyChanges({'domain': domain}, '/domain/' + domain + '/update');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
{% if record_helper_setting %}
|
||||||
|
//handle wacky record types
|
||||||
|
$(document).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\"> \
|
||||||
|
";
|
||||||
|
} 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');
|
||||||
|
})
|
||||||
|
modal.modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block modals %}
|
{% block modals %}
|
||||||
@ -295,4 +364,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- /.modal-dialog -->
|
<!-- /.modal-dialog -->
|
||||||
</div>
|
</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 %}
|
{% endblock %}
|
||||||
|
57
app/views.py
57
app/views.py
@ -22,6 +22,11 @@ def inject_fullscreen_layout_setting():
|
|||||||
fullscreen_layout_setting = Setting.query.filter(Setting.name == 'fullscreen_layout').first()
|
fullscreen_layout_setting = Setting.query.filter(Setting.name == 'fullscreen_layout').first()
|
||||||
return dict(fullscreen_layout_setting=strtobool(fullscreen_layout_setting.value))
|
return dict(fullscreen_layout_setting=strtobool(fullscreen_layout_setting.value))
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_record_helper_setting():
|
||||||
|
record_helper_setting = Setting.query.filter(Setting.name == 'record_helper').first()
|
||||||
|
return dict(record_helper_setting=strtobool(record_helper_setting.value))
|
||||||
|
|
||||||
# START USER AUTHENTICATION HANDLER
|
# START USER AUTHENTICATION HANDLER
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
@ -54,13 +59,29 @@ def admin_role_required(f):
|
|||||||
# END CUSTOMIZE DECORATOR
|
# END CUSTOMIZE DECORATOR
|
||||||
|
|
||||||
# START VIEWS
|
# START VIEWS
|
||||||
|
@app.errorhandler(400)
|
||||||
|
def http_bad_request(e):
|
||||||
|
return redirect(url_for('error', code=400))
|
||||||
|
|
||||||
|
@app.errorhandler(401)
|
||||||
|
def http_unauthorized(e):
|
||||||
|
return redirect(url_for('error', code=401))
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def http_internal_server_error(e):
|
||||||
|
return redirect(url_for('error', code=404))
|
||||||
|
|
||||||
|
@app.errorhandler(500)
|
||||||
|
def http_page_not_found(e):
|
||||||
|
return redirect(url_for('error', code=500))
|
||||||
|
|
||||||
@app.route('/error/<string:code>')
|
@app.route('/error/<string:code>')
|
||||||
def error(code, msg=None):
|
def error(code, msg=None):
|
||||||
supported_code = ('400', '401', '404', '500')
|
supported_code = ('400', '401', '404', '500')
|
||||||
if code in supported_code:
|
if code in supported_code:
|
||||||
return render_template('%s.html' % code, msg=msg), int(code)
|
return render_template('errors/%s.html' % code, msg=msg), int(code)
|
||||||
else:
|
else:
|
||||||
return render_template('404.html'), 404
|
return render_template('errors/404.html'), 404
|
||||||
|
|
||||||
@app.route('/register', methods=['GET'])
|
@app.route('/register', methods=['GET'])
|
||||||
def register():
|
def register():
|
||||||
@ -195,7 +216,7 @@ def domain_add():
|
|||||||
soa_edit_api = request.form.getlist('radio_type_soa_edit_api')[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:
|
if ' ' in domain_name or not domain_name or not domain_type:
|
||||||
return render_template('400.html', msg="Please correct your input"), 400
|
return render_template('errors/400.html', msg="Please correct your input"), 400
|
||||||
|
|
||||||
if domain_type == 'slave':
|
if domain_type == 'slave':
|
||||||
if request.form.getlist('domain_master_address'):
|
if request.form.getlist('domain_master_address'):
|
||||||
@ -211,7 +232,7 @@ def domain_add():
|
|||||||
history.add()
|
history.add()
|
||||||
return redirect(url_for('dashboard'))
|
return redirect(url_for('dashboard'))
|
||||||
else:
|
else:
|
||||||
return render_template('400.html', msg=result['msg']), 400
|
return render_template('errors/400.html', msg=result['msg']), 400
|
||||||
except:
|
except:
|
||||||
return redirect(url_for('error', code=500))
|
return redirect(url_for('error', code=500))
|
||||||
return render_template('domain_add.html')
|
return render_template('domain_add.html')
|
||||||
@ -368,13 +389,37 @@ def admin():
|
|||||||
|
|
||||||
return render_template('admin.html', domains=domains, users=users, configs=configs, statistics=statistics, uptime=uptime, history_number=history_number)
|
return render_template('admin.html', domains=domains, users=users, configs=configs, statistics=statistics, uptime=uptime, history_number=history_number)
|
||||||
|
|
||||||
|
@app.route('/admin/user/create', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_role_required
|
||||||
|
def admin_createuser():
|
||||||
|
if request.method == 'GET':
|
||||||
|
return render_template('admin_createuser.html')
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
fdata = request.form
|
||||||
|
|
||||||
|
user = User(username=fdata['username'], plain_text_password=fdata['password'], firstname=fdata['firstname'], lastname=fdata['lastname'], email=fdata['email'])
|
||||||
|
|
||||||
|
if fdata['password'] == "":
|
||||||
|
return render_template('admin_createuser.html', user=user, blank_password=True)
|
||||||
|
|
||||||
|
result = user.create_local_user();
|
||||||
|
|
||||||
|
if result == 'Email already existed':
|
||||||
|
return render_template('admin_createuser.html', user=user, duplicate_email=True)
|
||||||
|
|
||||||
|
if result == 'Username already existed':
|
||||||
|
return render_template('admin_createuser.html', user=user, duplicate_username=True)
|
||||||
|
|
||||||
|
return redirect(url_for('admin_manageuser'))
|
||||||
|
|
||||||
@app.route('/admin/manageuser', methods=['GET', 'POST'])
|
@app.route('/admin/manageuser', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@admin_role_required
|
@admin_role_required
|
||||||
def admin_manageuser():
|
def admin_manageuser():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
users = User.query.all()
|
users = User.query.order_by(User.username).all()
|
||||||
return render_template('admin_manageuser.html', users=users)
|
return render_template('admin_manageuser.html', users=users)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -460,7 +505,7 @@ def admin_settings_toggle(setting):
|
|||||||
if (result):
|
if (result):
|
||||||
return make_response(jsonify( { 'status': 'ok', 'msg': 'Toggled setting successfully.' } ), 200)
|
return make_response(jsonify( { 'status': 'ok', 'msg': 'Toggled setting successfully.' } ), 200)
|
||||||
else:
|
else:
|
||||||
return make_response(jsonify( { 'status': 'error', 'msg': 'Can toggle setting.' } ), 500)
|
return make_response(jsonify( { 'status': 'error', 'msg': 'Unable to toggle setting.' } ), 500)
|
||||||
|
|
||||||
@app.route('/user/profile', methods=['GET', 'POST'])
|
@app.route('/user/profile', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -11,10 +11,12 @@ admin_role = Role('Administrator', 'Administrator')
|
|||||||
user_role = Role('User', 'User')
|
user_role = Role('User', 'User')
|
||||||
maintenance_setting = Setting('maintenance', 'False')
|
maintenance_setting = Setting('maintenance', 'False')
|
||||||
fullscreen_layout_setting = Setting('fullscreen_layout', 'True')
|
fullscreen_layout_setting = Setting('fullscreen_layout', 'True')
|
||||||
|
record_helper_setting = Setting('record_helper_layout', 'True')
|
||||||
db.session.add(admin_role)
|
db.session.add(admin_role)
|
||||||
db.session.add(user_role)
|
db.session.add(user_role)
|
||||||
db.session.add(maintenance_setting)
|
db.session.add(maintenance_setting)
|
||||||
db.session.add(fullscreen_layout_setting)
|
db.session.add(fullscreen_layout_setting)
|
||||||
|
db.session.add(record_helper_setting)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
|
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
|
||||||
api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
|
api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
|
||||||
|
Loading…
Reference in New Issue
Block a user