Fix status check colors, add SMTP relay stub
This commit is contained in:
parent
0d17caccfe
commit
974c9bba61
4 changed files with 506 additions and 484 deletions
|
@ -12,6 +12,9 @@ charset = utf-8
|
|||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.html]
|
||||
indent_style = tab
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
|
|
@ -1,396 +1,409 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{hostname}} - Mail-in-a-Box Control Panel</title>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title>{{hostname}} - Mail-in-a-Box Control Panel</title>
|
||||
|
||||
<link rel="stylesheet" href="/admin/assets/bootstrap/css/bootstrap.min.css">
|
||||
<style>
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
|
||||
p {
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
<link rel="stylesheet" href="/admin/assets/bootstrap/css/bootstrap.min.css">
|
||||
<style>
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 1em 0;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 130%;
|
||||
border-bottom: 1px solid black;
|
||||
padding-bottom: 3px;
|
||||
margin-bottom: 13px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.panel-heading h3 {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
h2 {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 110%;
|
||||
margin-bottom: 13px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
h4:first-child {
|
||||
margin-top: 6px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 130%;
|
||||
border-bottom: 1px solid black;
|
||||
padding-bottom: 3px;
|
||||
margin-bottom: 13px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.admin_panel {
|
||||
display: none;
|
||||
}
|
||||
.panel-heading h3 {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table.table {
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
h4 {
|
||||
font-size: 110%;
|
||||
margin-bottom: 13px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
ol li {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/admin/assets/bootstrap/css/bootstrap-theme.min.css">
|
||||
</head>
|
||||
<body>
|
||||
h4:first-child {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
<!--[if lt IE 8]><p>Internet Explorer version 8 or any modern web browser is required to use this website, sorry.<![endif]-->
|
||||
<!--[if gt IE 7]><!-->
|
||||
.admin_panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
<div class="navbar navbar-inverse navbar-static-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">{{hostname}}</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">System <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#system_status" onclick="return show_panel(this);">Status Checks</a></li>
|
||||
<li><a href="#tls" onclick="return show_panel(this);">TLS (SSL) Certificates</a></li>
|
||||
<li><a href="#system_backup" onclick="return show_panel(this);">Backup Status</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header">Advanced Pages</li>
|
||||
<li><a href="#custom_dns" onclick="return show_panel(this);">Custom DNS</a></li>
|
||||
<li><a href="#external_dns" onclick="return show_panel(this);">External DNS</a></li>
|
||||
<li><a href="/admin/munin" target="_blank">Munin Monitoring</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Mail <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li>
|
||||
<li><a href="#users" onclick="return show_panel(this);">Users</a></li>
|
||||
<li><a href="#aliases" onclick="return show_panel(this);">Aliases</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#sync_guide" onclick="return show_panel(this);">Contacts/Calendar</a></li>
|
||||
<li><a href="#web" onclick="return show_panel(this);">Web</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="#" onclick="do_logout(); return false;" style="color: white">Log out</a></li>
|
||||
</ul>
|
||||
</div><!--/.navbar-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
table.table {
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<div id="panel_system_status" class="admin_panel">
|
||||
{% include "system-status.html" %}
|
||||
</div>
|
||||
ol li {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/admin/assets/bootstrap/css/bootstrap-theme.min.css">
|
||||
</head>
|
||||
|
||||
<div id="panel_system_backup" class="admin_panel">
|
||||
{% include "system-backup.html" %}
|
||||
</div>
|
||||
<body>
|
||||
|
||||
<div id="panel_external_dns" class="admin_panel">
|
||||
{% include "external-dns.html" %}
|
||||
</div>
|
||||
<!--[if lt IE 8]><p>Internet Explorer version 8 or any modern web browser is required to use this website, sorry.<![endif]-->
|
||||
<!--[if gt IE 7]><!-->
|
||||
|
||||
<div id="panel_custom_dns" class="admin_panel">
|
||||
{% include "custom-dns.html" %}
|
||||
</div>
|
||||
<div class="navbar navbar-inverse navbar-static-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
|
||||
data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">{{hostname}}</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">System <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#system_status" onclick="return show_panel(this);">Status Checks</a></li>
|
||||
<li><a href="#tls" onclick="return show_panel(this);">TLS (SSL) Certificates</a></li>
|
||||
<li><a href="#system_backup" onclick="return show_panel(this);">Backup Status</a></li>
|
||||
<li><a href="#smtp_relays" onclick="return show_panel(this);">SMTP Relays</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header">Advanced Pages</li>
|
||||
<li><a href="#custom_dns" onclick="return show_panel(this);">Custom DNS</a></li>
|
||||
<li><a href="#external_dns" onclick="return show_panel(this);">External DNS</a></li>
|
||||
<li><a href="/admin/munin" target="_blank">Munin Monitoring</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Mail <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li>
|
||||
<li><a href="#users" onclick="return show_panel(this);">Users</a></li>
|
||||
<li><a href="#aliases" onclick="return show_panel(this);">Aliases</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#sync_guide" onclick="return show_panel(this);">Contacts/Calendar</a></li>
|
||||
<li><a href="#web" onclick="return show_panel(this);">Web</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="#" onclick="do_logout(); return false;" style="color: white">Log out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!--/.navbar-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="panel_login" class="admin_panel">
|
||||
{% include "login.html" %}
|
||||
</div>
|
||||
<div class="container">
|
||||
<div id="panel_system_status" class="admin_panel">
|
||||
{% include "system-status.html" %}
|
||||
</div>
|
||||
|
||||
<div id="panel_mail-guide" class="admin_panel">
|
||||
{% include "mail-guide.html" %}
|
||||
</div>
|
||||
<div id="panel_system_backup" class="admin_panel">
|
||||
{% include "system-backup.html" %}
|
||||
</div>
|
||||
|
||||
<div id="panel_users" class="admin_panel">
|
||||
{% include "users.html" %}
|
||||
</div>
|
||||
<div id="panel_external_dns" class="admin_panel">
|
||||
{% include "external-dns.html" %}
|
||||
</div>
|
||||
|
||||
<div id="panel_aliases" class="admin_panel">
|
||||
{% include "aliases.html" %}
|
||||
</div>
|
||||
<div id="panel_custom_dns" class="admin_panel">
|
||||
{% include "custom-dns.html" %}
|
||||
</div>
|
||||
|
||||
<div id="panel_sync_guide" class="admin_panel">
|
||||
{% include "sync-guide.html" %}
|
||||
</div>
|
||||
<div id="panel_login" class="admin_panel">
|
||||
{% include "login.html" %}
|
||||
</div>
|
||||
|
||||
<div id="panel_web" class="admin_panel">
|
||||
{% include "web.html" %}
|
||||
</div>
|
||||
<div id="panel_mail-guide" class="admin_panel">
|
||||
{% include "mail-guide.html" %}
|
||||
</div>
|
||||
|
||||
<div id="panel_tls" class="admin_panel">
|
||||
{% include "ssl.html" %}
|
||||
</div>
|
||||
<div id="panel_users" class="admin_panel">
|
||||
{% include "users.html" %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div id="panel_aliases" class="admin_panel">
|
||||
{% include "aliases.html" %}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>This is a <a href="https://mailinabox.email">Mail-in-a-Box</a>.</p>
|
||||
</footer>
|
||||
</div> <!-- /container -->
|
||||
<div id="panel_sync_guide" class="admin_panel">
|
||||
{% include "sync-guide.html" %}
|
||||
</div>
|
||||
|
||||
<div id="ajax_loading_indicator" style="display: none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; text-align: center; background-color: rgba(255,255,255,.75)">
|
||||
<div style="margin: 20% auto">
|
||||
<div><span class="fa fa-spinner fa-pulse"></span></div>
|
||||
<div>Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_web" class="admin_panel">
|
||||
{% include "web.html" %}
|
||||
</div>
|
||||
|
||||
<div id="global_modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="errorModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="errorModalTitle"> </h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p> </p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal">Yes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_tls" class="admin_panel">
|
||||
{% include "ssl.html" %}
|
||||
</div>
|
||||
|
||||
<script src="/admin/assets/jquery.min.js"></script>
|
||||
<script src="/admin/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<hr>
|
||||
|
||||
<script>
|
||||
var global_modal_state = null;
|
||||
var global_modal_funcs = null;
|
||||
<footer>
|
||||
<p>This is a <a href="https://mailinabox.email">Mail-in-a-Box</a>.</p>
|
||||
</footer>
|
||||
</div> <!-- /container -->
|
||||
|
||||
$(function() {
|
||||
$('#global_modal').on('shown.bs.modal', function (e) {
|
||||
// set focus to first input in the global modal's body
|
||||
var input = $('#global_modal .modal-body input');
|
||||
if (input.length > 0) $(input[0]).focus();
|
||||
})
|
||||
$('#global_modal .btn-danger').click(function() {
|
||||
// Don't take action now. Wait for the modal to be totally hidden
|
||||
// so that we don't attempt to show another modal while this one
|
||||
// is closing.
|
||||
global_modal_state = 0; // OK
|
||||
})
|
||||
$('#global_modal .btn-default').click(function() {
|
||||
global_modal_state = 1; // Cancel
|
||||
})
|
||||
$('#global_modal').on('hidden.bs.modal', function (e) {
|
||||
// do the cancel function
|
||||
if (global_modal_state == null) global_modal_state = 1; // cancel if the user hit ESC or clicked outside of the modal
|
||||
if (global_modal_funcs && global_modal_funcs[global_modal_state])
|
||||
global_modal_funcs[global_modal_state]();
|
||||
})
|
||||
})
|
||||
<div id="ajax_loading_indicator"
|
||||
style="display: none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; text-align: center; background-color: rgba(255,255,255,.75)">
|
||||
<div style="margin: 20% auto">
|
||||
<div><span class="fa fa-spinner fa-pulse"></span></div>
|
||||
<div>Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
function show_modal_error(title, message, callback) {
|
||||
$('#global_modal h4').text(title);
|
||||
$('#global_modal .modal-body').html("<p/>");
|
||||
if (typeof question == 'string') {
|
||||
$('#global_modal p').text(message);
|
||||
$('#global_modal .modal-dialog').addClass("modal-sm");
|
||||
} else {
|
||||
$('#global_modal p').html("").append(message);
|
||||
$('#global_modal .modal-dialog').removeClass("modal-sm");
|
||||
}
|
||||
$('#global_modal .btn-default').show().text("OK");
|
||||
$('#global_modal .btn-danger').hide();
|
||||
global_modal_funcs = [callback, callback];
|
||||
global_modal_state = null;
|
||||
$('#global_modal').modal({});
|
||||
return false; // handy when called from onclick
|
||||
}
|
||||
<div id="global_modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="errorModalTitle"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="errorModalTitle"> </h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p> </p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal">Yes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
function show_modal_confirm(title, question, verb, yes_callback, cancel_callback) {
|
||||
$('#global_modal h4').text(title);
|
||||
if (typeof question == 'string') {
|
||||
$('#global_modal .modal-dialog').addClass("modal-sm");
|
||||
$('#global_modal .modal-body').html("<p/>");
|
||||
$('#global_modal p').text(question);
|
||||
} else {
|
||||
$('#global_modal .modal-dialog').removeClass("modal-sm");
|
||||
$('#global_modal .modal-body').html("").append(question);
|
||||
}
|
||||
if (typeof verb == 'string') {
|
||||
$('#global_modal .btn-default').show().text("Cancel");
|
||||
$('#global_modal .btn-danger').show().text(verb);
|
||||
} else {
|
||||
$('#global_modal .btn-default').show().text(verb[1]);
|
||||
$('#global_modal .btn-danger').show().text(verb[0]);
|
||||
}
|
||||
global_modal_funcs = [yes_callback, cancel_callback];
|
||||
global_modal_state = null;
|
||||
$('#global_modal').modal({});
|
||||
return false; // handy when called from onclick
|
||||
}
|
||||
<script src="/admin/assets/jquery.min.js"></script>
|
||||
<script src="/admin/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
|
||||
var ajax_num_executing_requests = 0;
|
||||
function ajax_with_indicator(options) {
|
||||
setTimeout("if (ajax_num_executing_requests > 0) $('#ajax_loading_indicator').fadeIn()", 100);
|
||||
function hide_loading_indicator() {
|
||||
ajax_num_executing_requests--;
|
||||
if (ajax_num_executing_requests == 0)
|
||||
$('#ajax_loading_indicator').stop(true).hide(); // stop() prevents an ongoing fade from causing the thing to be shown again after this call
|
||||
}
|
||||
var old_success = options.success;
|
||||
var old_error = options.error;
|
||||
options.success = function(data) {
|
||||
hide_loading_indicator();
|
||||
if (data.status == "error")
|
||||
show_modal_error("Error", data.message);
|
||||
else if (old_success)
|
||||
old_success(data);
|
||||
};
|
||||
options.error = function(jqxhr) {
|
||||
hide_loading_indicator();
|
||||
if (!old_error)
|
||||
show_modal_error("Error", "Something went wrong, sorry.")
|
||||
else
|
||||
old_error(jqxhr.responseText, jqxhr);
|
||||
};
|
||||
ajax_num_executing_requests++;
|
||||
$.ajax(options);
|
||||
return false; // handy when called from onclick
|
||||
}
|
||||
<script>
|
||||
var global_modal_state = null;
|
||||
var global_modal_funcs = null;
|
||||
|
||||
var api_credentials = ["", ""];
|
||||
function api(url, method, data, callback, callback_error) {
|
||||
// from http://www.webtoolkit.info/javascript-base64.html
|
||||
function base64encode(input) {
|
||||
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
while (i < input.length) {
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
output = output +
|
||||
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
|
||||
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
|
||||
}
|
||||
$(function () {
|
||||
$('#global_modal').on('shown.bs.modal', function (e) {
|
||||
// set focus to first input in the global modal's body
|
||||
var input = $('#global_modal .modal-body input');
|
||||
if (input.length > 0) $(input[0]).focus();
|
||||
})
|
||||
$('#global_modal .btn-danger').click(function () {
|
||||
// Don't take action now. Wait for the modal to be totally hidden
|
||||
// so that we don't attempt to show another modal while this one
|
||||
// is closing.
|
||||
global_modal_state = 0; // OK
|
||||
})
|
||||
$('#global_modal .btn-default').click(function () {
|
||||
global_modal_state = 1; // Cancel
|
||||
})
|
||||
$('#global_modal').on('hidden.bs.modal', function (e) {
|
||||
// do the cancel function
|
||||
if (global_modal_state == null) global_modal_state = 1; // cancel if the user hit ESC or clicked outside of the modal
|
||||
if (global_modal_funcs && global_modal_funcs[global_modal_state])
|
||||
global_modal_funcs[global_modal_state]();
|
||||
})
|
||||
})
|
||||
|
||||
return output;
|
||||
}
|
||||
function show_modal_error(title, message, callback) {
|
||||
$('#global_modal h4').text(title);
|
||||
$('#global_modal .modal-body').html("<p/>");
|
||||
if (typeof question == 'string') {
|
||||
$('#global_modal p').text(message);
|
||||
$('#global_modal .modal-dialog').addClass("modal-sm");
|
||||
} else {
|
||||
$('#global_modal p').html("").append(message);
|
||||
$('#global_modal .modal-dialog').removeClass("modal-sm");
|
||||
}
|
||||
$('#global_modal .btn-default').show().text("OK");
|
||||
$('#global_modal .btn-danger').hide();
|
||||
global_modal_funcs = [callback, callback];
|
||||
global_modal_state = null;
|
||||
$('#global_modal').modal({});
|
||||
return false; // handy when called from onclick
|
||||
}
|
||||
|
||||
function default_error(text, xhr) {
|
||||
if (xhr.status != 403) // else handled below
|
||||
show_modal_error("Error", "Something went wrong, sorry.")
|
||||
}
|
||||
function show_modal_confirm(title, question, verb, yes_callback, cancel_callback) {
|
||||
$('#global_modal h4').text(title);
|
||||
if (typeof question == 'string') {
|
||||
$('#global_modal .modal-dialog').addClass("modal-sm");
|
||||
$('#global_modal .modal-body').html("<p/>");
|
||||
$('#global_modal p').text(question);
|
||||
} else {
|
||||
$('#global_modal .modal-dialog').removeClass("modal-sm");
|
||||
$('#global_modal .modal-body').html("").append(question);
|
||||
}
|
||||
if (typeof verb == 'string') {
|
||||
$('#global_modal .btn-default').show().text("Cancel");
|
||||
$('#global_modal .btn-danger').show().text(verb);
|
||||
} else {
|
||||
$('#global_modal .btn-default').show().text(verb[1]);
|
||||
$('#global_modal .btn-danger').show().text(verb[0]);
|
||||
}
|
||||
global_modal_funcs = [yes_callback, cancel_callback];
|
||||
global_modal_state = null;
|
||||
$('#global_modal').modal({});
|
||||
return false; // handy when called from onclick
|
||||
}
|
||||
|
||||
ajax_with_indicator({
|
||||
url: "/admin" + url,
|
||||
method: method,
|
||||
cache: false,
|
||||
data: data,
|
||||
var ajax_num_executing_requests = 0;
|
||||
function ajax_with_indicator(options) {
|
||||
setTimeout("if (ajax_num_executing_requests > 0) $('#ajax_loading_indicator').fadeIn()", 100);
|
||||
function hide_loading_indicator() {
|
||||
ajax_num_executing_requests--;
|
||||
if (ajax_num_executing_requests == 0)
|
||||
$('#ajax_loading_indicator').stop(true).hide(); // stop() prevents an ongoing fade from causing the thing to be shown again after this call
|
||||
}
|
||||
var old_success = options.success;
|
||||
var old_error = options.error;
|
||||
options.success = function (data) {
|
||||
hide_loading_indicator();
|
||||
if (data.status == "error")
|
||||
show_modal_error("Error", data.message);
|
||||
else if (old_success)
|
||||
old_success(data);
|
||||
};
|
||||
options.error = function (jqxhr) {
|
||||
hide_loading_indicator();
|
||||
if (!old_error)
|
||||
show_modal_error("Error", "Something went wrong, sorry.")
|
||||
else
|
||||
old_error(jqxhr.responseText, jqxhr);
|
||||
};
|
||||
ajax_num_executing_requests++;
|
||||
$.ajax(options);
|
||||
return false; // handy when called from onclick
|
||||
}
|
||||
|
||||
// the custom DNS api sends raw POST/PUT bodies --- prevent URL-encoding
|
||||
processData: typeof data != "string",
|
||||
mimeType: typeof data == "string" ? "text/plain; charset=ascii" : null,
|
||||
var api_credentials = ["", ""];
|
||||
function api(url, method, data, callback, callback_error) {
|
||||
// from http://www.webtoolkit.info/javascript-base64.html
|
||||
function base64encode(input) {
|
||||
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
while (i < input.length) {
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
output = output +
|
||||
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
|
||||
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
|
||||
}
|
||||
|
||||
beforeSend: function(xhr) {
|
||||
// We don't store user credentials in a cookie to avoid the hassle of CSRF
|
||||
// attacks. The Authorization header only gets set in our AJAX calls triggered
|
||||
// by user actions.
|
||||
xhr.setRequestHeader(
|
||||
'Authorization',
|
||||
'Basic ' + base64encode(api_credentials[0] + ':' + api_credentials[1]));
|
||||
},
|
||||
success: callback,
|
||||
error: callback_error || default_error,
|
||||
statusCode: {
|
||||
403: function(xhr) {
|
||||
// Credentials are no longer valid. Try to login again.
|
||||
var p = current_panel;
|
||||
show_panel('login');
|
||||
switch_back_to_panel = p;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
var current_panel = null;
|
||||
var switch_back_to_panel = null;
|
||||
function show_panel(panelid) {
|
||||
if (panelid.getAttribute)
|
||||
// we might be passed an HTMLElement <a>.
|
||||
panelid = panelid.getAttribute('href').substring(1);
|
||||
function default_error(text, xhr) {
|
||||
if (xhr.status != 403) // else handled below
|
||||
show_modal_error("Error", "Something went wrong, sorry.")
|
||||
}
|
||||
|
||||
$('.admin_panel').hide();
|
||||
$('#panel_' + panelid).show();
|
||||
if (typeof localStorage != 'undefined')
|
||||
localStorage.setItem("miab-cp-lastpanel", panelid);
|
||||
if (window["show_" + panelid])
|
||||
window["show_" + panelid]();
|
||||
ajax_with_indicator({
|
||||
url: "/admin" + url,
|
||||
method: method,
|
||||
cache: false,
|
||||
data: data,
|
||||
|
||||
current_panel = panelid;
|
||||
switch_back_to_panel = null;
|
||||
// the custom DNS api sends raw POST/PUT bodies --- prevent URL-encoding
|
||||
processData: typeof data != "string",
|
||||
mimeType: typeof data == "string" ? "text/plain; charset=ascii" : null,
|
||||
|
||||
return false; // when called from onclick, cancel navigation
|
||||
}
|
||||
beforeSend: function (xhr) {
|
||||
// We don't store user credentials in a cookie to avoid the hassle of CSRF
|
||||
// attacks. The Authorization header only gets set in our AJAX calls triggered
|
||||
// by user actions.
|
||||
xhr.setRequestHeader(
|
||||
'Authorization',
|
||||
'Basic ' + base64encode(api_credentials[0] + ':' + api_credentials[1]));
|
||||
},
|
||||
success: callback,
|
||||
error: callback_error || default_error,
|
||||
statusCode: {
|
||||
403: function (xhr) {
|
||||
// Credentials are no longer valid. Try to login again.
|
||||
var p = current_panel;
|
||||
show_panel('login');
|
||||
switch_back_to_panel = p;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(function() {
|
||||
// Recall saved user credentials.
|
||||
if (typeof sessionStorage != 'undefined' && sessionStorage.getItem("miab-cp-credentials"))
|
||||
api_credentials = sessionStorage.getItem("miab-cp-credentials").split(":");
|
||||
else if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-credentials"))
|
||||
api_credentials = localStorage.getItem("miab-cp-credentials").split(":");
|
||||
var current_panel = null;
|
||||
var switch_back_to_panel = null;
|
||||
function show_panel(panelid) {
|
||||
if (panelid.getAttribute)
|
||||
// we might be passed an HTMLElement <a>.
|
||||
panelid = panelid.getAttribute('href').substring(1);
|
||||
|
||||
// Recall what the user was last looking at.
|
||||
if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-lastpanel")) {
|
||||
show_panel(localStorage.getItem("miab-cp-lastpanel"));
|
||||
} else {
|
||||
show_panel('login');
|
||||
}
|
||||
})
|
||||
$('.admin_panel').hide();
|
||||
$('#panel_' + panelid).show();
|
||||
if (typeof localStorage != 'undefined')
|
||||
localStorage.setItem("miab-cp-lastpanel", panelid);
|
||||
if (window["show_" + panelid])
|
||||
window["show_" + panelid]();
|
||||
|
||||
current_panel = panelid;
|
||||
switch_back_to_panel = null;
|
||||
|
||||
return false; // when called from onclick, cancel navigation
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// Recall saved user credentials.
|
||||
if (typeof sessionStorage != 'undefined' && sessionStorage.getItem("miab-cp-credentials"))
|
||||
api_credentials = sessionStorage.getItem("miab-cp-credentials").split(":");
|
||||
else if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-credentials"))
|
||||
api_credentials = localStorage.getItem("miab-cp-credentials").split(":");
|
||||
|
||||
// Recall what the user was last looking at.
|
||||
if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-lastpanel")) {
|
||||
show_panel(localStorage.getItem("miab-cp-lastpanel"));
|
||||
} else {
|
||||
show_panel('login');
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
6
management/templates/smtp-relays.html
Normal file
6
management/templates/smtp-relays.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<style>
|
||||
</style>
|
||||
|
||||
<h2>SMTP Relays</h2>
|
||||
|
||||
<p>Coming Soon™</p>
|
|
@ -1,169 +1,169 @@
|
|||
<h2>System Status Checks</h2>
|
||||
|
||||
<style>
|
||||
#system-checks .heading td {
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
padding-top: 1.5em;
|
||||
}
|
||||
#system-checks .heading td {
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
padding-top: 1.5em;
|
||||
}
|
||||
|
||||
#system-checks .heading.first td {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
#system-checks .heading.first td {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#system-checks .status-error td {
|
||||
color: rgb(180, 0, 0);
|
||||
}
|
||||
#system-checks .status-error td {
|
||||
color: rgb(140, 0, 0);
|
||||
}
|
||||
|
||||
#system-checks .status-warning td {
|
||||
color: rgb(180, 180, 0);
|
||||
}
|
||||
#system-checks .status-warning td {
|
||||
color: rgb(170, 120, 0);
|
||||
}
|
||||
|
||||
#system-checks .status-ok td {
|
||||
color: rgb(0, 180, 0);
|
||||
}
|
||||
#system-checks .status-ok td {
|
||||
color: rgb(0, 140, 0);
|
||||
}
|
||||
|
||||
#system-checks div.extra {
|
||||
display: none;
|
||||
margin-top: 1em;
|
||||
max-width: 50em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#system-checks div.extra {
|
||||
display: none;
|
||||
margin-top: 1em;
|
||||
max-width: 50em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#system-checks a.showhide {
|
||||
display: none;
|
||||
font-size: 85%;
|
||||
}
|
||||
#system-checks a.showhide {
|
||||
display: none;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
#system-checks .pre {
|
||||
margin: 1em;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
#system-checks .pre {
|
||||
margin: 1em;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-push-9 col-md-3">
|
||||
<div class="col-md-push-9 col-md-3">
|
||||
|
||||
<div id="system-reboot-required" style="display: none; margin-bottom: 1em;">
|
||||
<button type="button" class="btn btn-danger" onclick="confirm_reboot(); return false;">Reboot Box</button>
|
||||
<div>No reboot is necessary.</div>
|
||||
</div>
|
||||
<div id="system-reboot-required" style="display: none; margin-bottom: 1em;">
|
||||
<button type="button" class="btn btn-danger" onclick="confirm_reboot(); return false;">Reboot Box</button>
|
||||
<div>No reboot is necessary.</div>
|
||||
</div>
|
||||
|
||||
<div id="system-privacy-setting" style="display: none">
|
||||
<div><a onclick="return enable_privacy(!current_privacy_setting)" href="#"><span>Enable/Disable</span>
|
||||
New-Version Check</a></div>
|
||||
<p style="line-height: 125%"><small>(When enabled, status checks phone-home to check for a new release of
|
||||
Mail-in-a-Box.)</small></p>
|
||||
</div>
|
||||
<div id="system-privacy-setting" style="display: none">
|
||||
<div><a onclick="return enable_privacy(!current_privacy_setting)" href="#"><span>Enable/Disable</span>
|
||||
New-Version Check</a></div>
|
||||
<p style="line-height: 125%"><small>(When enabled, status checks phone-home to check for a new release of
|
||||
Mail-in-a-Box.)</small></p>
|
||||
</div>
|
||||
|
||||
</div> <!-- /col -->
|
||||
<div class="col-md-pull-3 col-md-8">
|
||||
</div> <!-- /col -->
|
||||
<div class="col-md-pull-3 col-md-8">
|
||||
|
||||
<table id="system-checks" class="table" style="max-width: 60em">
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<table id="system-checks" class="table" style="max-width: 60em">
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div> <!-- /col -->
|
||||
</div> <!-- /col -->
|
||||
</div> <!-- /row -->
|
||||
|
||||
<script>
|
||||
function show_system_status() {
|
||||
$('#system-checks tbody').html("<tr><td colspan='2' class='text-muted'>Loading...</td></tr>")
|
||||
function show_system_status() {
|
||||
$('#system-checks tbody').html("<tr><td colspan='2' class='text-muted'>Loading...</td></tr>")
|
||||
|
||||
api(
|
||||
"/system/privacy",
|
||||
"GET",
|
||||
{},
|
||||
function (r) {
|
||||
current_privacy_setting = r;
|
||||
$('#system-privacy-setting').show();
|
||||
$('#system-privacy-setting a span').text(r ? "Enable" : "Disable");
|
||||
$('#system-privacy-setting p').toggle(r);
|
||||
});
|
||||
api(
|
||||
"/system/privacy",
|
||||
"GET",
|
||||
{},
|
||||
function (r) {
|
||||
current_privacy_setting = r;
|
||||
$('#system-privacy-setting').show();
|
||||
$('#system-privacy-setting a span').text(r ? "Enable" : "Disable");
|
||||
$('#system-privacy-setting p').toggle(r);
|
||||
});
|
||||
|
||||
api(
|
||||
"/system/reboot",
|
||||
"GET",
|
||||
{},
|
||||
function (r) {
|
||||
$('#system-reboot-required').show(); // show when r becomes available
|
||||
$('#system-reboot-required').find('button').toggle(r);
|
||||
$('#system-reboot-required').find('div').toggle(!r);
|
||||
});
|
||||
api(
|
||||
"/system/reboot",
|
||||
"GET",
|
||||
{},
|
||||
function (r) {
|
||||
$('#system-reboot-required').show(); // show when r becomes available
|
||||
$('#system-reboot-required').find('button').toggle(r);
|
||||
$('#system-reboot-required').find('div').toggle(!r);
|
||||
});
|
||||
|
||||
api(
|
||||
"/system/status",
|
||||
"POST",
|
||||
{},
|
||||
function (r) {
|
||||
$('#system-checks tbody').html("");
|
||||
for (var i = 0; i < r.length; i++) {
|
||||
var n = $("<tr><td class='status'/><td class='message'><p style='margin: 0'/><div class='extra'/><a class='showhide' href='#'/></tr>");
|
||||
if (i == 0) n.addClass('first')
|
||||
if (r[i].type == "heading")
|
||||
n.addClass(r[i].type)
|
||||
else
|
||||
n.addClass("status-" + r[i].type)
|
||||
if (r[i].type == "ok") n.find('td.status').text("✓")
|
||||
if (r[i].type == "error") n.find('td.status').text("✖")
|
||||
if (r[i].type == "warning") n.find('td.status').text("?")
|
||||
n.find('td.message p').text(r[i].text)
|
||||
$('#system-checks tbody').append(n);
|
||||
api(
|
||||
"/system/status",
|
||||
"POST",
|
||||
{},
|
||||
function (r) {
|
||||
$('#system-checks tbody').html("");
|
||||
for (var i = 0; i < r.length; i++) {
|
||||
var n = $("<tr><td class='status'/><td class='message'><p style='margin: 0'/><div class='extra'/><a class='showhide' href='#'/></tr>");
|
||||
if (i == 0) n.addClass('first')
|
||||
if (r[i].type == "heading")
|
||||
n.addClass(r[i].type)
|
||||
else
|
||||
n.addClass("status-" + r[i].type)
|
||||
if (r[i].type == "ok") n.find('td.status').text("✓")
|
||||
if (r[i].type == "error") n.find('td.status').text("✖")
|
||||
if (r[i].type == "warning") n.find('td.status').text("?")
|
||||
n.find('td.message p').text(r[i].text)
|
||||
$('#system-checks tbody').append(n);
|
||||
|
||||
if (r[i].extra.length > 0) {
|
||||
n.find('a.showhide').show().text("show more").click(function () {
|
||||
$(this).hide();
|
||||
$(this).parent().find('.extra').fadeIn();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
if (r[i].extra.length > 0) {
|
||||
n.find('a.showhide').show().text("show more").click(function () {
|
||||
$(this).hide();
|
||||
$(this).parent().find('.extra').fadeIn();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
for (var j = 0; j < r[i].extra.length; j++) {
|
||||
for (var j = 0; j < r[i].extra.length; j++) {
|
||||
|
||||
var m = $("<div/>").text(r[i].extra[j].text)
|
||||
if (r[i].extra[j].monospace)
|
||||
m.addClass("pre");
|
||||
n.find('> td.message > div').append(m);
|
||||
}
|
||||
}
|
||||
})
|
||||
var m = $("<div/>").text(r[i].extra[j].text)
|
||||
if (r[i].extra[j].monospace)
|
||||
m.addClass("pre");
|
||||
n.find('> td.message > div').append(m);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var current_privacy_setting = null;
|
||||
function enable_privacy(status) {
|
||||
api(
|
||||
"/system/privacy",
|
||||
"POST",
|
||||
{
|
||||
value: (status ? "private" : "off")
|
||||
},
|
||||
function (res) {
|
||||
show_system_status();
|
||||
});
|
||||
return false; // disable link
|
||||
}
|
||||
var current_privacy_setting = null;
|
||||
function enable_privacy(status) {
|
||||
api(
|
||||
"/system/privacy",
|
||||
"POST",
|
||||
{
|
||||
value: (status ? "private" : "off")
|
||||
},
|
||||
function (res) {
|
||||
show_system_status();
|
||||
});
|
||||
return false; // disable link
|
||||
}
|
||||
|
||||
function confirm_reboot() {
|
||||
show_modal_confirm(
|
||||
"Reboot",
|
||||
$("<p>This will reboot your Mail-in-a-Box <code>{{hostname}}</code>.</p> <p>Until the machine is fully restarted, your users will not be able to send and receive email, and you will not be able to connect to this control panel or with SSH. The reboot cannot be cancelled.</p>"),
|
||||
"Reboot Now",
|
||||
function () {
|
||||
api(
|
||||
"/system/reboot",
|
||||
"POST",
|
||||
{},
|
||||
function (r) {
|
||||
var msg = "<p>Please reload this page after a minute or so.</p>";
|
||||
if (r) msg = "<p>The reboot command said:</p> <pre>" + $("<pre/>").text(r).html() + "</pre>"; // successful reboots don't produce any output; the output must be HTML-escaped
|
||||
show_modal_error("Reboot", msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
function confirm_reboot() {
|
||||
show_modal_confirm(
|
||||
"Reboot",
|
||||
$("<p>This will reboot your Mail-in-a-Box <code>{{hostname}}</code>.</p> <p>Until the machine is fully restarted, your users will not be able to send and receive email, and you will not be able to connect to this control panel or with SSH. The reboot cannot be cancelled.</p>"),
|
||||
"Reboot Now",
|
||||
function () {
|
||||
api(
|
||||
"/system/reboot",
|
||||
"POST",
|
||||
{},
|
||||
function (r) {
|
||||
var msg = "<p>Please reload this page after a minute or so.</p>";
|
||||
if (r) msg = "<p>The reboot command said:</p> <pre>" + $("<pre/>").text(r).html() + "</pre>"; // successful reboots don't produce any output; the output must be HTML-escaped
|
||||
show_modal_error("Reboot", msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Reference in a new issue