summaryrefslogtreecommitdiffstats
path: root/interface/js/app/symbols.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 21:30:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 21:30:40 +0000
commit133a45c109da5310add55824db21af5239951f93 (patch)
treeba6ac4c0a950a0dda56451944315d66409923918 /interface/js/app/symbols.js
parentInitial commit. (diff)
downloadrspamd-upstream.tar.xz
rspamd-upstream.zip
Adding upstream version 3.8.1.upstream/3.8.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'interface/js/app/symbols.js')
-rw-r--r--interface/js/app/symbols.js260
1 files changed, 260 insertions, 0 deletions
diff --git a/interface/js/app/symbols.js b/interface/js/app/symbols.js
new file mode 100644
index 0000000..1e3fb5d
--- /dev/null
+++ b/interface/js/app/symbols.js
@@ -0,0 +1,260 @@
+/*
+ The MIT License (MIT)
+
+ Copyright (C) 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 FooTable */
+
+define(["jquery", "app/common", "footable"],
+ ($, common) => {
+ "use strict";
+ const ui = {};
+ let altered = {};
+
+ function clear_altered() {
+ $("#save-alert").addClass("d-none");
+ altered = {};
+ }
+
+ function saveSymbols(server) {
+ $("#save-alert button").attr("disabled", true);
+
+ const values = [];
+ Object.entries(altered).forEach(([key, value]) => values.push({name: key, value: value}));
+
+ common.query("./savesymbols", {
+ success: function () {
+ clear_altered();
+ common.alertMessage("alert-modal alert-success", "Symbols successfully saved");
+ },
+ complete: () => $("#save-alert button").removeAttr("disabled", true),
+ errorMessage: "Save symbols error",
+ method: "POST",
+ params: {
+ data: JSON.stringify(values),
+ dataType: "json",
+ },
+ server: server
+ });
+ }
+
+ function process_symbols_data(data) {
+ const items = [];
+ const lookup = {};
+ const freqs = [];
+ const distinct_groups = [];
+
+ data.forEach((group) => {
+ group.rules.forEach((item) => {
+ const formatter = new Intl.NumberFormat("en", {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 6,
+ useGrouping: false
+ });
+ item.group = group.group;
+ let label_class = "";
+ if (item.weight < 0) {
+ label_class = "scorebar-ham";
+ } else if (item.weight > 0) {
+ label_class = "scorebar-spam";
+ }
+ item.weight = '<input class="form-control input-sm mb-disabled scorebar ' + label_class +
+ '" autocomplete="off" type="number" step="0.01" tabindex="1" ' +
+ 'value="' + formatter.format(item.weight) + '" id="_sym_' + item.symbol + '"></input>';
+ if (!item.time) {
+ item.time = 0;
+ }
+ item.time = Number(item.time).toFixed(2) + "s";
+ if (!item.frequency) {
+ item.frequency = 0;
+ }
+ freqs.push(item.frequency);
+ item.frequency = Number(item.frequency).toFixed(2);
+ if (!(item.group in lookup)) {
+ lookup[item.group] = 1;
+ distinct_groups.push(item.group);
+ }
+ items.push(item);
+ });
+ });
+
+ // For better mean calculations
+ const avg_freq = freqs
+ .sort((a, b) => Number(a) < Number(b))
+ .reduce((f1, acc) => f1 + acc) / (freqs.length !== 0 ? freqs.length : 1.0);
+ let mult = 1.0;
+ let exp = 0.0;
+
+ if (avg_freq > 0.0) {
+ while (mult * avg_freq < 1.0) {
+ mult *= 10;
+ exp++;
+ }
+ }
+ $.each(items, (i, item) => {
+ item.frequency = Number(item.frequency) * mult;
+
+ if (exp > 0) {
+ item.frequency = item.frequency.toFixed(2) + "e-" + exp;
+ } else {
+ item.frequency = item.frequency.toFixed(2);
+ }
+ });
+ return [items, distinct_groups];
+ }
+ // @get symbols into modal form
+ ui.getSymbols = function (checked_server) {
+ clear_altered();
+ common.query("symbols", {
+ success: function (json) {
+ const [{data}] = json;
+ const items = process_symbols_data(data);
+
+ /* eslint-disable consistent-this, no-underscore-dangle, one-var-declaration-per-line */
+ FooTable.groupFilter = FooTable.Filtering.extend({
+ construct: function (instance) {
+ this._super(instance);
+ [,this.groups] = items;
+ this.def = "Any group";
+ this.$group = null;
+ },
+ $create: function () {
+ this._super();
+ const self = this;
+ const $form_grp = $("<div/>", {
+ class: "form-group"
+ }).append($("<label/>", {
+ class: "sr-only",
+ text: "Group"
+ })).prependTo(self.$form);
+
+ self.$group = $("<select/>", {
+ class: "form-select"
+ }).on("change", {
+ self: self
+ }, self._onStatusDropdownChanged).append(
+ $("<option/>", {
+ text: self.def
+ })).appendTo($form_grp);
+
+ $.each(self.groups, (i, group) => {
+ self.$group.append($("<option/>").text(group));
+ });
+ },
+ _onStatusDropdownChanged: function (e) {
+ const {self} = e.data;
+ const selected = $(this).val();
+ if (selected !== self.def) {
+ self.addFilter("group", selected, ["group"]);
+ } else {
+ self.removeFilter("group");
+ }
+ self.filter();
+ },
+ draw: function () {
+ this._super();
+ const group = this.find("group");
+ if (group instanceof FooTable.Filter) {
+ this.$group.val(group.query.val());
+ } else {
+ this.$group.val(this.def);
+ }
+ }
+ });
+ /* eslint-enable consistent-this, no-underscore-dangle, one-var-declaration-per-line */
+
+ common.tables.symbols = FooTable.init("#symbolsTable", {
+ columns: [
+ {sorted: true, direction: "ASC", name: "group", title: "Group"},
+ {name: "symbol", title: "Symbol"},
+ {name: "description", title: "Description", breakpoints: "xs sm"},
+ {name: "weight", title: "Score"},
+ {name: "frequency",
+ title: "Frequency",
+ breakpoints: "xs sm",
+ sortValue: function (value) { return Number(value).toFixed(2); }},
+ {name: "time", title: "Avg. time", breakpoints: "xs sm"},
+ ],
+ rows: items[0],
+ paging: {
+ enabled: true,
+ limit: 5,
+ size: 25
+ },
+ filtering: {
+ enabled: true,
+ position: "left",
+ connectors: false
+ },
+ sorting: {
+ enabled: true
+ },
+ components: {
+ filtering: FooTable.groupFilter
+ },
+ on: {
+ "ready.ft.table": function () {
+ if (common.read_only) {
+ $(".mb-disabled").attr("disabled", true);
+ }
+ }
+ }
+ });
+ },
+ server: (checked_server === "All SERVERS") ? "local" : checked_server
+ });
+ };
+
+
+ $("#updateSymbols").on("click", (e) => {
+ e.preventDefault();
+ clear_altered();
+ const checked_server = common.getSelector("selSrv");
+ common.query("symbols", {
+ success: function (data) {
+ const [items] = process_symbols_data(data[0].data);
+ common.tables.symbols.rows.load(items);
+ },
+ server: (checked_server === "All SERVERS") ? "local" : checked_server
+ });
+ });
+
+ $("#symbolsTable")
+ .on("input", ".scorebar", ({target}) => {
+ const t = $(target);
+ t.removeClass("scorebar-ham scorebar-spam");
+ if (target.value < 0) {
+ t.addClass("scorebar-ham");
+ } else if (target.value > 0) {
+ t.addClass("scorebar-spam");
+ }
+ })
+ .on("change", ".scorebar", ({target}) => {
+ altered[$(target).attr("id").substring(5)] = parseFloat(target.value);
+ $("#save-alert").removeClass("d-none");
+ });
+
+ $("#save-alert button")
+ .on("click", ({target}) => saveSymbols($(target).data("save")));
+
+ return ui;
+ });