123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- /*
- The MIT License (MIT)
-
- Copyright (C) 2012-2013 Anton Simonov <untone@gmail.com>
- Copyright (C) 2014-2017 Vsevolod Stakhov <vsevolod@highsecure.ru>
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
-
- /* global jQuery:false, Visibility:false */
-
- define(["jquery", "d3pie", "visibility", "nprogress", "app/stats", "app/graph", "app/config",
- "app/symbols", "app/history", "app/upload"],
- // eslint-disable-next-line max-params
- function ($, D3pie, visibility, NProgress, tab_stat, tab_graph, tab_config,
- tab_symbols, tab_history, tab_upload) {
- "use strict";
- // begin
- var graphs = {};
- var tables = {};
- var neighbours = []; // list of clusters
- var checked_server = "All SERVERS";
- var ui = {};
- var timer_id = [];
- var selData = null; // Graph's dataset selector state
-
- NProgress.configure({
- minimum: 0.01,
- showSpinner: false,
- });
-
- function cleanCredentials() {
- sessionStorage.clear();
- $("#statWidgets").empty();
- $("#listMaps").empty();
- $("#modalBody").empty();
- }
-
- function stopTimers() {
- for (var key in timer_id) {
- if (!{}.hasOwnProperty.call(timer_id, key)) continue;
- Visibility.stop(timer_id[key]);
- }
- }
-
- function disconnect() {
- [graphs, tables].forEach(function (o) {
- Object.keys(o).forEach(function (key) {
- o[key].destroy();
- delete o[key];
- });
- });
-
- stopTimers();
- cleanCredentials();
- ui.connect();
- }
-
- function tabClick(id) {
- var tab_id = id;
- if ($(tab_id).attr("disabled")) return;
- $(tab_id).attr("disabled", true);
-
- stopTimers();
-
- if (tab_id === "#refresh") {
- tab_id = "#" + $(".navbar-nav .active > a").attr("id");
- }
-
- switch (tab_id) {
- case "#status_nav":
- tab_stat.statWidgets(ui, graphs, checked_server);
- timer_id.status = Visibility.every(10000, function () {
- tab_stat.statWidgets(ui, graphs, checked_server);
- });
- break;
- case "#throughput_nav":
- tab_graph.draw(ui, graphs, tables, neighbours, checked_server, selData);
-
- var autoRefresh = {
- hourly: 60000,
- daily: 300000
- };
- timer_id.throughput = Visibility.every(autoRefresh[selData] || 3600000, function () {
- tab_graph.draw(ui, graphs, tables, neighbours, checked_server, selData);
- });
- break;
- case "#configuration_nav":
- tab_config.getActions(ui, checked_server);
- tab_config.getMaps(ui, checked_server);
- break;
- case "#symbols_nav":
- tab_symbols.getSymbols(ui, tables, checked_server);
- break;
- case "#history_nav":
- tab_history.getHistory(ui, tables);
- tab_history.getErrors(ui, tables);
- break;
- case "#disconnect":
- disconnect();
- break;
- default:
- }
-
- setTimeout(function () {
- $(tab_id).removeAttr("disabled");
- $("#refresh").removeAttr("disabled");
- }, 1000);
- }
-
- // @return password
- function getPassword() {
- return sessionStorage.getItem("Password");
- }
-
- // @save credentials
- function saveCredentials(password) {
- sessionStorage.setItem("Password", password);
- }
-
- function displayUI() {
- // In many browsers local storage can only store string.
- // So when we store the boolean true or false, it actually stores the strings "true" or "false".
- ui.read_only = sessionStorage.getItem("read_only") === "true";
- if (ui.read_only) {
- $("#learning_nav").hide();
- $("#resetHistory").attr("disabled", true);
- $("#errors-history").hide();
- } else {
- $("#learning_nav").show();
- $("#resetHistory").removeAttr("disabled", true);
- $("#errors-history").show();
- }
-
- var buttons = $("#navBar .pull-right");
- $("#mainUI").show();
- $("#progress").show();
- $(buttons).show();
- tabClick("#refresh");
- $("#progress").hide();
- }
-
- function alertMessage(alertClass, alertText) {
- var a = $("<div class=\"alert " + alertClass + " alert-dismissible fade in show\">" +
- "<button type=\"button\" class=\"close\" data-dismiss=\"alert\" title=\"Dismiss\">×</button>" +
- "<strong>" + alertText + "</strong>");
- $(".notification-area").append(a);
-
- setTimeout(function () {
- $(a).fadeTo(500, 0).slideUp(500, function () {
- $(this).alert("close");
- });
- }, 5000);
- }
-
- function queryServer(neighbours_status, ind, req_url, o) {
- neighbours_status[ind].checked = false;
- neighbours_status[ind].data = {};
- neighbours_status[ind].status = false;
- var req_params = {
- jsonp: false,
- data: o.data,
- headers: $.extend({Password:getPassword()}, o.headers),
- url: neighbours_status[ind].url + req_url,
- xhr: function () {
- var xhr = $.ajaxSettings.xhr();
- // Download progress
- if (req_url !== "neighbours") {
- xhr.addEventListener("progress", function (e) {
- if (e.lengthComputable) {
- neighbours_status[ind].percentComplete = e.loaded / e.total;
- var percentComplete = neighbours_status.reduce(function (prev, curr) {
- return curr.percentComplete ? curr.percentComplete + prev : prev;
- }, 0);
- NProgress.set(percentComplete / neighbours_status.length);
- }
- }, false);
- }
- return xhr;
- },
- success: function (json) {
- neighbours_status[ind].checked = true;
- neighbours_status[ind].status = true;
- neighbours_status[ind].data = json;
- },
- error: function (jqXHR, textStatus, errorThrown) {
- neighbours_status[ind].checked = true;
- function errorMessage() {
- alertMessage("alert-error", neighbours_status[ind].name + " > " +
- (o.errorMessage ? o.errorMessage : "Request failed") +
- (errorThrown ? ": " + errorThrown : ""));
- }
- if (o.error) {
- o.error(neighbours_status[ind],
- jqXHR, textStatus, errorThrown);
- } else if (o.errorOnceId) {
- var alert_status = o.errorOnceId + neighbours_status[ind].name;
- if (!(alert_status in sessionStorage)) {
- sessionStorage.setItem(alert_status, true);
- errorMessage();
- }
- } else {
- errorMessage();
- }
- },
- complete: function (jqXHR) {
- if (neighbours_status.every(function (elt) { return elt.checked; })) {
- if (neighbours_status.some(function (elt) { return elt.status; })) {
- if (o.success) {
- o.success(neighbours_status, jqXHR);
- } else {
- alertMessage("alert-success", "Request completed");
- }
- } else {
- alertMessage("alert-error", "Request failed");
- }
- NProgress.done();
- }
- },
- statusCode: o.statusCode
- };
- if (o.method) {
- req_params.method = o.method;
- }
- if (o.params) {
- $.each(o.params, function (k, v) {
- req_params[k] = v;
- });
- }
- $.ajax(req_params);
- }
-
- // Public functions
- ui.alertMessage = alertMessage;
- ui.setup = function () {
- $("#selData").change(function () {
- selData = this.value;
- tabClick("#throughput_nav");
- });
- $.ajaxSetup({
- timeout: 20000,
- jsonp: false
- });
-
- $(document).ajaxStart(function () {
- $("#navBar").addClass("loading");
- });
- $(document).ajaxComplete(function () {
- setTimeout(function () {
- $("#navBar").removeClass("loading");
- }, 1000);
- });
-
- $("a[data-toggle=\"tab\"]").on("click", function (e) {
- var tab_id = "#" + $(e.target).attr("id");
- tabClick(tab_id);
- });
-
- $("#selSrv").change(function () {
- checked_server = this.value;
- $("#selSrv [value=\"" + checked_server + "\"]").prop("checked", true);
- tabClick("#" + $("#navBar ul li.active > a").attr("id"));
- });
-
- // Radio buttons
- $(document).on("click", "input:radio[name=\"clusterName\"]", function () {
- if (!this.disabled) {
- checked_server = this.value;
- tabClick("#status_nav");
- }
- });
- tab_config.setup(ui);
- tab_history.setup(ui, tables);
- tab_symbols.setup(ui, tables);
- tab_upload.setup(ui);
- selData = tab_graph.setup();
- };
-
- ui.connect = function () {
- // Query "/stat" to check if user is already logged in or client ip matches "secure_ip"
- $.ajax({
- type: "GET",
- url: "stat",
- async: false,
- success: function () {
- displayUI();
- },
- error: function () {
- var dialog = $("#connectDialog");
- var backdrop = $("#backDrop");
- $("#mainUI").hide();
- $(dialog).show();
- $(backdrop).show();
- $("#connectPassword").focus();
- $("#connectForm").off("submit");
-
- $("#connectForm").on("submit", function (e) {
- e.preventDefault();
- var password = $("#connectPassword").val();
- if (!(/^[\u0020-\u007e]*$/).test(password)) {
- alertMessage("alert-modal alert-error", "Invalid characters in the password");
- $("#connectPassword").focus();
- return;
- }
-
- ui.query("auth", {
- headers: {
- Password: password
- },
- success: function (json) {
- var data = json[0].data;
- $("#connectPassword").val("");
- if (data.auth === "ok") {
- sessionStorage.setItem("read_only", data.read_only);
- saveCredentials(password);
- $(dialog).hide();
- $(backdrop).hide();
- displayUI();
- }
- },
- error: function (jqXHR) {
- ui.alertMessage("alert-modal alert-error", jqXHR.statusText);
- $("#connectPassword").val("");
- $("#connectPassword").focus();
- },
- params: {
- global: false,
- },
- server: "local"
- });
- });
- }
- });
- };
-
- ui.drawPie = function (object, id, data, conf) {
- var obj = object;
- if (obj) {
- obj.updateProp("data.content",
- data.filter(function (elt) {
- return elt.value > 0;
- })
- );
- } else {
- obj = new D3pie(id,
- $.extend({}, {
- header: {
- title: {
- text: "Rspamd filter stats",
- fontSize: 24,
- font: "open sans"
- },
- subtitle: {
- color: "#999999",
- fontSize: 12,
- font: "open sans"
- },
- titleSubtitlePadding: 9
- },
- footer: {
- color: "#999999",
- fontSize: 10,
- font: "open sans",
- location: "bottom-left"
- },
- size: {
- canvasWidth: 600,
- canvasHeight: 400,
- pieInnerRadius: "20%",
- pieOuterRadius: "85%"
- },
- data: {
- // "sortOrder": "value-desc",
- content: data.filter(function (elt) {
- return elt.value > 0;
- })
- },
- labels: {
- outer: {
- hideWhenLessThanPercentage: 1,
- pieDistance: 30
- },
- inner: {
- hideWhenLessThanPercentage: 4
- },
- mainLabel: {
- fontSize: 14
- },
- percentage: {
- color: "#eeeeee",
- fontSize: 14,
- decimalPlaces: 0
- },
- lines: {
- enabled: true
- },
- truncation: {
- enabled: true
- }
- },
- tooltips: {
- enabled: true,
- type: "placeholder",
- string: "{label}: {value} ({percentage}%)"
- },
- effects: {
- pullOutSegmentOnClick: {
- effect: "back",
- speed: 400,
- size: 8
- },
- load: {
- effect: "none"
- }
- },
- misc: {
- gradient: {
- enabled: true,
- percentage: 100
- }
- }
- }, conf));
- }
- return obj;
- };
-
- ui.getPassword = getPassword;
-
- /**
- * @param {string} url - A string containing the URL to which the request is sent
- * @param {Object} [options] - A set of key/value pairs that configure the Ajax request. All settings are optional.
- *
- * @param {Object|string|Array} [options.data] - Data to be sent to the server.
- * @param {Function} [options.error] - A function to be called if the request fails.
- * @param {string} [options.errorMessage] - Text to display in the alert message if the request fails.
- * @param {string} [options.errorOnceId] - A prefix of the alert ID to be added to the session storage. If the
- * parameter is set, the error for each server will be displayed only once per session.
- * @param {Object} [options.headers] - An object of additional header key/value pairs to send along with requests
- * using the XMLHttpRequest transport.
- * @param {string} [options.method] - The HTTP method to use for the request.
- * @param {Object} [options.params] - An object of additional jQuery.ajax() settings key/value pairs.
- * @param {string} [options.server] - A server to which send the request.
- * @param {Function} [options.success] - A function to be called if the request succeeds.
- *
- * @returns {undefined}
- */
- ui.query = function (url, options) {
- // Force options to be an object
- var o = options || {};
- Object.keys(o).forEach(function (option) {
- if (["data", "error", "errorMessage", "errorOnceId", "headers", "method", "params", "server", "statusCode",
- "success"]
- .indexOf(option) < 0) {
- throw new Error("Unknown option: " + option);
- }
- });
-
- var neighbours_status = [{
- name: "local",
- host: "local",
- url: "",
- }];
- o.server = o.server || checked_server;
- if (o.server === "All SERVERS") {
- queryServer(neighbours_status, 0, "neighbours", {
- success: function (json) {
- var data = json[0].data;
- if (jQuery.isEmptyObject(data)) {
- neighbours = {
- local: {
- host: window.location.host,
- url: window.location.href
- }
- };
- } else {
- neighbours = data;
- }
- neighbours_status = [];
- $.each(neighbours, function (ind) {
- neighbours_status.push({
- name: ind,
- host: neighbours[ind].host,
- url: neighbours[ind].url,
- });
- });
- $.each(neighbours_status, function (ind) {
- queryServer(neighbours_status, ind, url, o);
- });
- },
- errorMessage: "Cannot receive neighbours data"
- });
- } else {
- if (o.server !== "local") {
- neighbours_status = [{
- name: o.server,
- host: neighbours[o.server].host,
- url: neighbours[o.server].url,
- }];
- }
- queryServer(neighbours_status, 0, url, o);
- }
- };
-
- return ui;
- });
|