mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-12-04 19:15:30 +00:00
557 lines
27 KiB
HTML
557 lines
27 KiB
HTML
{% extends "base.html" %}
|
|
{% set active_page = "admin_history" %}
|
|
{% block title %}<title>Activity - {{ SITE_NAME }}</title>{% endblock %}
|
|
|
|
{% block dashboard_stat %}
|
|
<div class="content-header">
|
|
<div class="container-fluid">
|
|
<div class="row mb-2">
|
|
<div class="col-sm-6">
|
|
<h1 class="m-0 text-dark">Activity</h1>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<ol class="breadcrumb float-sm-right">
|
|
<li class="breadcrumb-item"><a href="{{ url_for('dashboard.dashboard') }}">Home</a></li>
|
|
<li class="breadcrumb-item active">Activity</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
{% import 'applied_change_macro.html' as applied_change_macro %}
|
|
<section class="content">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card card-outline card-secondary">
|
|
<div class="card-header with-border">
|
|
<h3 class="card-title">Activity Search</h3>
|
|
{% if current_user.role.name == 'Administrator' %}
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-danger" data-toggle="modal"
|
|
data-target="#modal_clear_history" title="Clear Activity">
|
|
<i class="fa-solid fa-trash"></i>
|
|
Clear Activity
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<form id="history-search-form" autocomplete="off">
|
|
<div class="card-body clearfix">
|
|
<ul class="nav nav-tabs" id="custom-content-below-tab" role="tablist">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" href="#tabs-act" data-toggle="pill" role="tab">
|
|
Search for All Activity
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="#tabs-domain" data-toggle="pill" role="tab">
|
|
Search By Zone
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link with-border" href="#tabs-account" data-toggle="pill"
|
|
role="tab">
|
|
Search By Account
|
|
</a>
|
|
</li>
|
|
{% if current_user.role.name != 'User' %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="#tabs-auth" data-toggle="pill" role="tab">
|
|
Search for User Authentication
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
<div class="tab-content">
|
|
<div class="tab-pane" id="tabs-act">
|
|
</div>
|
|
<div class="tab-pane" id="tabs-domain">
|
|
<td>
|
|
<label>Zone Name</label>
|
|
</td>
|
|
<td>
|
|
<div class="autocomplete" style="width:250px;">
|
|
<input type="text" class="form-control" id="domain_name_filter"
|
|
name="domain_name_filter"
|
|
placeholder="Enter * to search for any zone" value="">
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div style="position: relative; top:10px;">
|
|
<td>Record Changelog only  </td>
|
|
<td>
|
|
<input type="checkbox" id="domain_changelog_only_checkbox"
|
|
name="domain_changelog_only_checkbox"
|
|
class="checkbox"
|
|
style="border:2px dotted #00f;display:block;background:#ff0000;">
|
|
</td>
|
|
</div>
|
|
</td>
|
|
</div>
|
|
<div class="tab-pane" id="tabs-account">
|
|
<td><label>Account Name</label></td>
|
|
<td>
|
|
<div class="autocomplete" style="width:250px;">
|
|
<input type="text" class="form-control" id="account_name_filter"
|
|
name="account_name_filter"
|
|
placeholder="Enter * to search for any account" value="">
|
|
</div>
|
|
</td>
|
|
</div>
|
|
<div class="tab-pane" id="tabs-auth">
|
|
<td><label>Username</label></td>
|
|
<td>
|
|
<div class="autocomplete" style="width:250px;">
|
|
<input type="text" class="form-control" id="auth_name_filter"
|
|
name="auth_name_filter"
|
|
placeholder="Enter * to search for any username" value="">
|
|
</div>
|
|
</td>
|
|
|
|
<td>
|
|
<div style="position: relative; top:10px;">
|
|
<td>Authenticator Types:  </td>
|
|
<td>  All</td>
|
|
<td>
|
|
<input type="checkbox" checked id="auth_all_checkbox" name="auth_all_checkbox"
|
|
class="checkbox"
|
|
style="border:2px dotted #00f;display:block;background:#ff0000;">
|
|
</td>
|
|
<td>  LOCAL</td>
|
|
<td>
|
|
<input type="checkbox" checked id="auth_local_only_checkbox"
|
|
name="auth_local_only_checkbox"
|
|
class="checkbox"
|
|
style="border:2px dotted #00f;display:block;background:#ff0000;">
|
|
</td>
|
|
<td>  OAuth</td>
|
|
<td>
|
|
<input type="checkbox" checked id="auth_oauth_only_checkbox"
|
|
name="auth_oauth_only_checkbox"
|
|
class="checkbox"
|
|
style="border:2px dotted #00f;display:block;background:#ff0000;">
|
|
</td>
|
|
<td>  SAML</td>
|
|
<td>
|
|
<input type="checkbox" checked id="auth_saml_only_checkbox"
|
|
name="auth_saml_only_checkbox"
|
|
class="checkbox"
|
|
style="border:2px dotted #00f;display:block;background:#ff0000;">
|
|
</td>
|
|
</div>
|
|
</td>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<table id="Filters-Table">
|
|
<thead>
|
|
<th>Filters</th>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><label>Changed by:  </label></td>
|
|
<td>
|
|
<div class="autocomplete" style="width:250px;">
|
|
<input type="text" style=" border:1px solid #d2d6de; width:250px; height: 34px;"
|
|
id="user_name_filter" name="user_name_filter" value="">
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="position: relative; top:10px;">
|
|
<label>Minimum date:  </label>
|
|
</td>
|
|
<td style="position: relative; top:10px;">
|
|
<input type="text" id="min" name="min" class="datepicker" autocomplete="off"
|
|
style=" border:1px solid #d2d6de; width:250px; height: 34px;">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="position: relative; top:20px;">
|
|
<label>Maximum date:  </label>
|
|
</td>
|
|
<td style="position: relative; top:20px;">
|
|
<input type="text" id="max" name="max" class="datepicker" autocomplete="off"
|
|
style=" border:1px solid #d2d6de; width:250px; height: 34px;">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td> </td>
|
|
</tr>
|
|
<tr>
|
|
<td> </td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<button type="submit" id="search-submit" name="search-submit"
|
|
class="btn btn-primary button-filter"><i class="fa fa-search"></i> Search
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<button id="clear-filters" name="clear-filters"
|
|
class="btn btn-warning button-clearf"><i class="fa fa-trash"></i> Clear
|
|
Filters
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</form>
|
|
<div id="table_from_ajax"></div>
|
|
</div>
|
|
</section>
|
|
{% endblock %}
|
|
|
|
{% block extrascripts %}
|
|
<script>
|
|
|
|
/* Don't let user search with a blank main field */
|
|
var canSearch = true;
|
|
|
|
$(document).ready(function () {
|
|
$.ajax({
|
|
url: '{{ url_for("admin.history_table") }}',
|
|
type: "get",
|
|
success: function (response) {
|
|
console.log('Submission was successful.');
|
|
$("#table_from_ajax").html(response);
|
|
},
|
|
error: function (xhr) {
|
|
console.log("Sending data: ", data, " failed")
|
|
}
|
|
});
|
|
|
|
var minDate = $('#min');
|
|
var maxDate = $('#max');
|
|
domain_changelog = $('domain_changelog_only_checkbox');
|
|
|
|
// Show/hide filters
|
|
$('#domain_name_filter, #account_name_filter, #auth_name_filter').on('keyup change', function (e) {
|
|
if ($('#domain_name_filter').val() == "" && $('#account_name_filter').val() == "" && $('#auth_name_filter').val() == "")
|
|
canSearch = false;
|
|
else
|
|
canSearch = true;
|
|
});
|
|
|
|
// Handle giving later mindate than current max
|
|
$('#min').on('change', function () {
|
|
if (minDate.val() > maxDate.val())
|
|
$('#max').datepicker('setDate', minDate.val());
|
|
});
|
|
|
|
// Handle giving earlier maxdate than current min
|
|
$('#max').on('keyup change', function () {
|
|
if (maxDate.val() < minDate.val())
|
|
$('#min').datepicker('setDate', maxDate.val());
|
|
});
|
|
|
|
$(function () {
|
|
$(".datepicker").datepicker({
|
|
changeMonth: true,
|
|
changeYear: true,
|
|
format: "yyyy-mm-dd",
|
|
endDate: '+0'
|
|
});
|
|
// $(".datepicker").datepicker("option", "format", "yy-mm-dd")
|
|
|
|
});
|
|
});
|
|
|
|
$('.checkbox,.radio').iCheck({
|
|
checkboxClass: 'icheckbox_square-blue',
|
|
radioClass: 'iradio_square-blue',
|
|
increaseArea: '20%'
|
|
});
|
|
|
|
//Handle "ALL" Checkbox
|
|
$('#auth_all_checkbox').on('ifChecked', function () {
|
|
$('#auth_local_only_checkbox').iCheck('check');
|
|
$('#auth_oauth_only_checkbox').iCheck('check');
|
|
$('#auth_saml_only_checkbox').iCheck('check');
|
|
});
|
|
|
|
$('#auth_all_checkbox').on('ifUnchecked', function () {
|
|
//check if all were checked
|
|
if ($('#auth_local_only_checkbox').is(':checked') && $('#auth_oauth_only_checkbox').is(':checked') && $('#auth_saml_only_checkbox').is(':checked')) {
|
|
$('#auth_local_only_checkbox').iCheck('uncheck');
|
|
$('#auth_oauth_only_checkbox').iCheck('uncheck');
|
|
$('#auth_saml_only_checkbox').iCheck('uncheck');
|
|
}
|
|
});
|
|
|
|
//Handle other auth checkboxes
|
|
$('#auth_local_only_checkbox').on('ifChecked', function () {
|
|
//check if all others were checked
|
|
if ($('#auth_oauth_only_checkbox').is(':checked') && $('#auth_saml_only_checkbox').is(':checked'))
|
|
$('#auth_all_checkbox').iCheck('check');
|
|
});
|
|
$('#auth_local_only_checkbox').on('ifUnchecked', function () {
|
|
$('#auth_all_checkbox').iCheck('uncheck');
|
|
});
|
|
|
|
$('#auth_oauth_only_checkbox').on('ifChecked', function () {
|
|
if ($('#auth_local_only_checkbox').is(':checked') && $('#auth_saml_only_checkbox').is(':checked'))
|
|
$('#auth_all_checkbox').iCheck('check');
|
|
});
|
|
$('#auth_oauth_only_checkbox').on('ifUnchecked', function () {
|
|
$('#auth_all_checkbox').iCheck('uncheck');
|
|
});
|
|
|
|
$('#auth_saml_only_checkbox').on('ifChecked', function () {
|
|
if ($('#auth_local_only_checkbox').is(':checked') && $('#auth_oauth_only_checkbox').is(':checked'))
|
|
$('#auth_all_checkbox').iCheck('check');
|
|
});
|
|
$('#auth_saml_only_checkbox').on('ifUnchecked', function () {
|
|
$('#auth_all_checkbox').iCheck('uncheck');
|
|
});
|
|
|
|
$(document.body).on("click", ".button-clearf", function (e) {
|
|
e.preventDefault();
|
|
|
|
$('#user_name_filter').val('');
|
|
$('#min').val('');
|
|
$('#max').val('');
|
|
$('#domain_name_filter').val('');
|
|
$('#account_name_filter').val('');
|
|
$('#auth_name_filter').val('');
|
|
$('#auth_all_checkbox').iCheck('check');
|
|
$('#domain_changelog_only_checkbox').iCheck('uncheck');
|
|
});
|
|
|
|
var all_doms = "{{all_domain_names}}".split(" ");
|
|
var all_accounts = "{{all_account_names}}".split(" ");
|
|
var all_usernames = "{{all_usernames}}".split(" ");
|
|
all_doms.pop(); // remove last element which is " "
|
|
all_accounts.pop();
|
|
all_usernames.pop();
|
|
|
|
function autocomplete(inp, arr) {
|
|
/*the autocomplete function takes two arguments,
|
|
the text field element and an array of possible autocompleted values:*/
|
|
var currentFocus;
|
|
/*execute a function when someone writes in the text field:*/
|
|
inp.addEventListener("input", function (e) {
|
|
var a, b, i, val = this.value;
|
|
/*close any already open lists of autocompleted values*/
|
|
closeAllLists();
|
|
if (!val) {
|
|
return false;
|
|
}
|
|
currentFocus = -1;
|
|
/*create a DIV element that will contain the items (values):*/
|
|
a = document.createElement("DIV");
|
|
a.setAttribute("id", this.id + "autocomplete-list");
|
|
a.setAttribute("class", "autocomplete-items");
|
|
/*append the DIV element as a child of the autocomplete container:*/
|
|
this.parentNode.appendChild(a);
|
|
/*for each item in the array...*/
|
|
for (i = 0; i < arr.length; i++) {
|
|
/*check if the item starts with the same letters as the text field value:*/
|
|
if (arr[i].substr(0, val.length).toUpperCase() == val.toUpperCase()) {
|
|
/*create a DIV element for each matching element:*/
|
|
b = document.createElement("DIV");
|
|
/*make the matching letters bold:*/
|
|
b.innerHTML = "<strong>" + arr[i].substr(0, val.length) + "</strong>";
|
|
b.innerHTML += arr[i].substr(val.length);
|
|
/*insert a input field that will hold the current array item's value:*/
|
|
b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
|
|
/*execute a function when someone clicks on the item value (DIV element):*/
|
|
b.addEventListener("click", function (e) {
|
|
/*insert the value for the autocomplete text field:*/
|
|
inp.value = this.getElementsByTagName("input")[0].value;
|
|
/*close the list of autocompleted values,
|
|
(or any other open lists of autocompleted values:*/
|
|
closeAllLists();
|
|
});
|
|
a.appendChild(b);
|
|
}
|
|
}
|
|
});
|
|
/*execute a function presses a key on the keyboard:*/
|
|
inp.addEventListener("keydown", function (e) {
|
|
var x = document.getElementById(this.id + "autocomplete-list");
|
|
if (x) x = x.getElementsByTagName("div");
|
|
if (e.keyCode == 40) {
|
|
/*If the arrow DOWN key is pressed,
|
|
increase the currentFocus variable:*/
|
|
currentFocus++;
|
|
/*and and make the current item more visible:*/
|
|
addActive(x);
|
|
} else if (e.keyCode == 38) { //up
|
|
/*If the arrow UP key is pressed,
|
|
decrease the currentFocus variable:*/
|
|
currentFocus--;
|
|
/*and and make the current item more visible:*/
|
|
addActive(x);
|
|
} else if (e.keyCode == 13) {
|
|
/*If the ENTER key is pressed, prevent the form from being submitted,*/
|
|
e.preventDefault();
|
|
if (currentFocus > -1) {
|
|
/*and simulate a click on the "active" item:*/
|
|
if (x) x[currentFocus].click();
|
|
}
|
|
}
|
|
});
|
|
|
|
function addActive(x) {
|
|
/*a function to classify an item as "active":*/
|
|
if (!x) return false;
|
|
/*start by removing the "active" class on all items:*/
|
|
removeActive(x);
|
|
if (currentFocus >= x.length) currentFocus = 0;
|
|
if (currentFocus < 0) currentFocus = (x.length - 1);
|
|
/*add class "autocomplete-active":*/
|
|
x[currentFocus].classList.add("autocomplete-active");
|
|
}
|
|
|
|
function removeActive(x) {
|
|
/*a function to remove the "active" class from all autocomplete items:*/
|
|
for (var i = 0; i < x.length; i++) {
|
|
x[i].classList.remove("autocomplete-active");
|
|
}
|
|
}
|
|
|
|
function closeAllLists(elmnt) {
|
|
/*close all autocomplete lists in the document,
|
|
except the one passed as an argument:*/
|
|
var x = document.getElementsByClassName("autocomplete-items");
|
|
for (var i = 0; i < x.length; i++) {
|
|
if (elmnt != x[i] && elmnt != inp) {
|
|
x[i].parentNode.removeChild(x[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*execute a function when someone clicks in the document:*/
|
|
document.addEventListener("click", function (e) {
|
|
closeAllLists(e.target);
|
|
});
|
|
}
|
|
|
|
/*initiate the autocomplete function on the "myInput" element, and pass along the countries array as possible autocomplete values:*/
|
|
autocomplete(document.getElementById("domain_name_filter"), all_doms);
|
|
autocomplete(document.getElementById("account_name_filter"), all_accounts);
|
|
autocomplete(document.getElementById("auth_name_filter"), all_usernames);
|
|
autocomplete(document.getElementById("user_name_filter"), all_usernames);
|
|
|
|
|
|
// prevent multiple filter field at the same time
|
|
$('#domain_tab').click(function () {
|
|
$('#account_name_filter').val('');
|
|
$('#auth_name_filter').val('');
|
|
$('#user_name_filter').removeAttr('disabled');
|
|
canSearch = false;
|
|
main_field = "Zone Name"
|
|
});
|
|
|
|
$('#account_tab').click(function () {
|
|
$('#domain_name_filter').val('');
|
|
$('#auth_name_filter').val('');
|
|
$('#user_name_filter').removeAttr('disabled');
|
|
canSearch = false;
|
|
main_field = "Account Name"
|
|
});
|
|
|
|
$('#user_auth_tab').click(function () {
|
|
$('#domain_name_filter').val('');
|
|
$('#account_name_filter').val('');
|
|
$('#user_name_filter').val('');
|
|
$('#user_name_filter').attr('disabled', 'disabled');
|
|
canSearch = false;
|
|
main_field = "Username"
|
|
});
|
|
|
|
$('#activity_tab').click(function () {
|
|
$('#domain_name_filter').val('');
|
|
$('#account_name_filter').val('');
|
|
$('#auth_name_filter').val('');
|
|
$('#user_name_filter').removeAttr('disabled');
|
|
$('#search-submit').removeAttr('disabled', 'disabled');
|
|
canSearch = true;
|
|
main_field = ""
|
|
});
|
|
|
|
// if search submit is pressed, and max date not initialized
|
|
// then initialize it
|
|
$('#search-submit').on('click', function () {
|
|
if ($('#max').val() === "" || $('#max').val() === undefined)
|
|
$('#max').datepicker('setDate', 'now');
|
|
});
|
|
|
|
$("#history-search-form").submit(function (e) { // ajax call to load results on submition
|
|
e.preventDefault(); // prevent page reloading
|
|
|
|
if (!canSearch) {
|
|
showErrorModal("Please fill out the " + main_field + " field.");
|
|
} else {
|
|
var form = $(this);
|
|
var tzoffset = (new Date()).getTimezoneOffset();
|
|
$.ajax({
|
|
url: '{{ url_for("admin.history_table") }}',
|
|
type: "get",
|
|
data: form.serialize() + "&tzoffset=" + tzoffset,
|
|
success: function (response) {
|
|
console.log('Submission was successful.');
|
|
$("#table_from_ajax").html(response);
|
|
|
|
},
|
|
error: function (xhr) {
|
|
console.log("Sending data: ", data, " failed")
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
</script>
|
|
{% 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">
|
|
<h4 class="modal-title">Confirmation</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</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-primary" data-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-danger float-right"
|
|
onclick="applyChanges({'_csrf_token': '{{ csrf_token() }}'}, $SCRIPT_ROOT + '/admin/history', false, true);">
|
|
Clear History
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- History Details Box -->
|
|
<div class="modal fade" id="modal_history_info">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">History Details</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="modal-info-content"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-default float-right" data-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|