|
|
@@ -25,6 +25,7 @@ |
|
|
|
define(['jquery', 'footable'], |
|
|
|
function($) { |
|
|
|
var interface = {} |
|
|
|
var ft = {} |
|
|
|
|
|
|
|
function saveSymbols(rspamd, action, id, is_cluster) { |
|
|
|
var inputs = $('#' + id + ' :input[data-role="numerictextbox"]'); |
|
|
@@ -76,16 +77,84 @@ function($) { |
|
|
|
return 1.0 / (Math.pow(10, digits)); |
|
|
|
} |
|
|
|
} |
|
|
|
function process_symbols_data(data) { |
|
|
|
var items = []; |
|
|
|
var lookup = {}; |
|
|
|
var freqs = []; |
|
|
|
var distinct_groups = []; |
|
|
|
|
|
|
|
$.each(data, function (i, group) { |
|
|
|
$.each(group.rules, function (i, item) { |
|
|
|
var max = 20; |
|
|
|
var min = -20; |
|
|
|
if (item.weight > max) { |
|
|
|
max = item.weight * 2; |
|
|
|
} |
|
|
|
item.group = group.group |
|
|
|
if (item.weight < min) { |
|
|
|
min = item.weight * 2; |
|
|
|
} |
|
|
|
var label_class = ''; |
|
|
|
if (item.weight < 0) { |
|
|
|
label_class = 'scorebar-ham'; |
|
|
|
} else { |
|
|
|
label_class = 'scorebar-spam'; |
|
|
|
} |
|
|
|
item.weight = '<input class="form-control input-sm mb-disabled ' + label_class + |
|
|
|
'" data-role="numerictextbox" autocomplete="off" "type="number" class="input" min="' + |
|
|
|
min + '" max="' + |
|
|
|
max + '" step="' + decimalStep(item.weight) + |
|
|
|
'" tabindex="1" value="' + Number(item.weight).toFixed(3) + |
|
|
|
'" 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); |
|
|
|
} |
|
|
|
item.save = '<button type="button" data-save="local" class="btn btn-primary btn-sm mb-disabled">Save</button>' + |
|
|
|
' <button data-save="cluster" type="button" class="btn btn-primary btn-sm mb-disabled">Save in cluster</button>'; |
|
|
|
items.push(item) |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
// For better mean calculations |
|
|
|
var avg_freq = freqs.sort(function(a, b) { |
|
|
|
return Number(a) < Number(b); |
|
|
|
}).reduce(function(f1, acc) { |
|
|
|
return f1 + acc; |
|
|
|
}) / (freqs.length != 0 ? freqs.length : 1.0); |
|
|
|
var mult = 1.0; |
|
|
|
var exp = 0.0; |
|
|
|
|
|
|
|
if (avg_freq > 0.0) { |
|
|
|
while (mult * avg_freq < 1.0) { |
|
|
|
mult *= 10; |
|
|
|
exp ++; |
|
|
|
} |
|
|
|
} |
|
|
|
$.each(items, function (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 |
|
|
|
interface.getSymbols = function(rspamd, tables, checked_server) { |
|
|
|
var symbols = tables.symbols |
|
|
|
if (symbols) { |
|
|
|
symbols.destroy(); |
|
|
|
tables.symbols = undefined; |
|
|
|
$('#symbolsTable').children('tbody').remove(); |
|
|
|
} |
|
|
|
|
|
|
|
var items = []; |
|
|
|
$.ajax({ |
|
|
|
dataType: 'json', |
|
|
|
type: 'GET', |
|
|
@@ -95,151 +164,81 @@ function($) { |
|
|
|
xhr.setRequestHeader('Password', rspamd.getPassword()); |
|
|
|
}, |
|
|
|
success: function (data) { |
|
|
|
var distinct_groups = []; |
|
|
|
var lookup = {}; |
|
|
|
var freqs = []; |
|
|
|
|
|
|
|
$.each(data, function (i, group) { |
|
|
|
$.each(group.rules, function (i, item) { |
|
|
|
var max = 20; |
|
|
|
var min = -20; |
|
|
|
if (item.weight > max) { |
|
|
|
max = item.weight * 2; |
|
|
|
} |
|
|
|
item.group = group.group |
|
|
|
if (item.weight < min) { |
|
|
|
min = item.weight * 2; |
|
|
|
} |
|
|
|
var label_class = ''; |
|
|
|
if (item.weight < 0) { |
|
|
|
label_class = 'scorebar-ham'; |
|
|
|
} else { |
|
|
|
label_class = 'scorebar-spam'; |
|
|
|
} |
|
|
|
item.weight = '<input class="form-control input-sm mb-disabled ' + label_class + |
|
|
|
'" data-role="numerictextbox" autocomplete="off" "type="number" class="input" min="' + |
|
|
|
min + '" max="' + |
|
|
|
max + '" step="' + decimalStep(item.weight) + |
|
|
|
'" tabindex="1" value="' + Number(item.weight).toFixed(3) + |
|
|
|
'" 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); |
|
|
|
} |
|
|
|
item.save = '<button type="button" data-save="local" class="btn btn-primary btn-sm mb-disabled">Save</button>' + |
|
|
|
' <button data-save="cluster" type="button" class="btn btn-primary btn-sm mb-disabled">Save in cluster</button>'; |
|
|
|
items.push(item) |
|
|
|
}); |
|
|
|
}); |
|
|
|
// For better mean calculations |
|
|
|
var avg_freq = freqs.sort(function(a, b) { |
|
|
|
return Number(a) < Number(b); |
|
|
|
}).reduce(function(f1, acc) { |
|
|
|
return f1 + acc; |
|
|
|
}) / (freqs.length != 0 ? freqs.length : 1.0); |
|
|
|
var mult = 1.0; |
|
|
|
var exp = 0.0; |
|
|
|
|
|
|
|
if (avg_freq > 0.0) { |
|
|
|
while (mult * avg_freq < 1.0) { |
|
|
|
mult *= 10; |
|
|
|
exp ++; |
|
|
|
} |
|
|
|
} |
|
|
|
$.each(items, function (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); |
|
|
|
} |
|
|
|
}); |
|
|
|
var items = process_symbols_data(data); |
|
|
|
FooTable.groupFilter = FooTable.Filtering.extend({ |
|
|
|
construct : function(instance) { |
|
|
|
this._super(instance); |
|
|
|
this.groups = distinct_groups; |
|
|
|
this.def = 'Any group'; |
|
|
|
this.$group = null; |
|
|
|
}, |
|
|
|
$create : function() { |
|
|
|
this._super(); |
|
|
|
var self = this, $form_grp = $('<div/>', { |
|
|
|
'class' : 'form-group' |
|
|
|
}).append($('<label/>', { |
|
|
|
'class' : 'sr-only', |
|
|
|
text : 'Group' |
|
|
|
})).prependTo(self.$form); |
|
|
|
construct : function(instance) { |
|
|
|
this._super(instance); |
|
|
|
this.groups = items[1]; |
|
|
|
this.def = 'Any group'; |
|
|
|
this.$group = null; |
|
|
|
}, |
|
|
|
$create : function() { |
|
|
|
this._super(); |
|
|
|
var self = this, $form_grp = $('<div/>', { |
|
|
|
'class' : 'form-group' |
|
|
|
}).append($('<label/>', { |
|
|
|
'class' : 'sr-only', |
|
|
|
text : 'Group' |
|
|
|
})).prependTo(self.$form); |
|
|
|
|
|
|
|
self.$group = $('<select/>', { |
|
|
|
'class' : 'form-control' |
|
|
|
}).on('change', { |
|
|
|
self : self |
|
|
|
}, self._onStatusDropdownChanged).append( |
|
|
|
$('<option/>', { |
|
|
|
text : self.def |
|
|
|
})).appendTo($form_grp); |
|
|
|
self.$group = $('<select/>', { |
|
|
|
'class' : 'form-control' |
|
|
|
}).on('change', { |
|
|
|
self : self |
|
|
|
}, self._onStatusDropdownChanged).append( |
|
|
|
$('<option/>', { |
|
|
|
text : self.def |
|
|
|
})).appendTo($form_grp); |
|
|
|
|
|
|
|
$.each(self.groups, function(i, group) { |
|
|
|
self.$group.append($('<option/>').text(group)); |
|
|
|
}); |
|
|
|
}, |
|
|
|
_onStatusDropdownChanged : function(e) { |
|
|
|
var self = e.data.self, selected = $(this).val(); |
|
|
|
if (selected !== self.def) { |
|
|
|
self.addFilter('group', selected, [ 'group' ]); |
|
|
|
} else { |
|
|
|
self.removeFilter('group'); |
|
|
|
} |
|
|
|
self.filter(); |
|
|
|
}, |
|
|
|
draw : function() { |
|
|
|
this._super(); |
|
|
|
var group = this.find('group'); |
|
|
|
if (group instanceof FooTable.Filter) { |
|
|
|
this.$group.val(group.query.val()); |
|
|
|
} else { |
|
|
|
this.$group.val(this.def); |
|
|
|
} |
|
|
|
} |
|
|
|
$.each(self.groups, function(i, group) { |
|
|
|
self.$group.append($('<option/>').text(group)); |
|
|
|
}); |
|
|
|
}, |
|
|
|
_onStatusDropdownChanged : function(e) { |
|
|
|
var self = e.data.self, selected = $(this).val(); |
|
|
|
if (selected !== self.def) { |
|
|
|
self.addFilter('group', selected, [ 'group' ]); |
|
|
|
} else { |
|
|
|
self.removeFilter('group'); |
|
|
|
} |
|
|
|
self.filter(); |
|
|
|
}, |
|
|
|
draw : function() { |
|
|
|
this._super(); |
|
|
|
var group = this.find('group'); |
|
|
|
if (group instanceof FooTable.Filter) { |
|
|
|
this.$group.val(group.query.val()); |
|
|
|
} else { |
|
|
|
this.$group.val(this.def); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
$('#symbolsTable').footable({ |
|
|
|
"columns": [ |
|
|
|
{"sorted": true,"direction": "ASC", "name":"group","title":"Group","style":{"font-size":"11px"}}, |
|
|
|
{"name":"symbol","title":"Symbol","style":{"font-size":"11px"}}, |
|
|
|
{"name":"description","title":"Description","breakpoints":"xs sm","style":{"font-size":"11px"}}, |
|
|
|
{"name":"weight","title":"Score","style":{"font-size":"11px"}}, |
|
|
|
{"name":"frequency","title":"Frequency","breakpoints":"xs sm","style":{"font-size":"11px"}}, |
|
|
|
{"name":"time","title":"Avg. time","breakpoints":"xs sm","style":{"font-size":"11px"}}, |
|
|
|
{"name":"save","title":"Save","style":{"font-size":"11px"}}, |
|
|
|
], |
|
|
|
"rows": items, |
|
|
|
"paging": { |
|
|
|
"enabled": true, |
|
|
|
"limit": 5, |
|
|
|
"size": 25 |
|
|
|
}, |
|
|
|
"filtering": { |
|
|
|
"enabled": true, |
|
|
|
"position": "left" |
|
|
|
}, |
|
|
|
"sorting": { |
|
|
|
"enabled": true |
|
|
|
}, |
|
|
|
components: { |
|
|
|
filtering: FooTable.groupFilter |
|
|
|
} |
|
|
|
ft.symbols = FooTable.init("#symbolsTable", { |
|
|
|
"columns": [ |
|
|
|
{"sorted": true,"direction": "ASC", "name":"group","title":"Group","style":{"font-size":"11px"}}, |
|
|
|
{"name":"symbol","title":"Symbol","style":{"font-size":"11px"}}, |
|
|
|
{"name":"description","title":"Description","breakpoints":"xs sm","style":{"font-size":"11px"}}, |
|
|
|
{"name":"weight","title":"Score","style":{"font-size":"11px"}}, |
|
|
|
{"name":"frequency","title":"Frequency","breakpoints":"xs sm","style":{"font-size":"11px"}}, |
|
|
|
{"name":"time","title":"Avg. time","breakpoints":"xs sm","style":{"font-size":"11px"}}, |
|
|
|
{"name":"save","title":"Save","style":{"font-size":"11px"}}, |
|
|
|
], |
|
|
|
"rows": items[0], |
|
|
|
"paging": { |
|
|
|
"enabled": true, |
|
|
|
"limit": 5, |
|
|
|
"size": 25 |
|
|
|
}, |
|
|
|
"filtering": { |
|
|
|
"enabled": true, |
|
|
|
"position": "left" |
|
|
|
}, |
|
|
|
"sorting": { |
|
|
|
"enabled": true |
|
|
|
}, |
|
|
|
components: { |
|
|
|
filtering: FooTable.groupFilter |
|
|
|
} |
|
|
|
}, function tableHook() { |
|
|
|
$('#symbolsTable :button').on('click', function() { |
|
|
|
var value = $(this).data('save'); |
|
|
@@ -258,8 +257,24 @@ function($) { |
|
|
|
}; |
|
|
|
|
|
|
|
interface.setup = function(rspamd, tables) { |
|
|
|
$('#updateSymbols').on('click', function () { |
|
|
|
interface.getSymbols(rspamd, tables); |
|
|
|
$('#updateSymbols').on('click', function (e) { |
|
|
|
e.preventDefault(); |
|
|
|
$.ajax({ |
|
|
|
dataType: 'json', |
|
|
|
type: 'GET', |
|
|
|
jsonp: false, |
|
|
|
url: 'symbols', |
|
|
|
beforeSend: function (xhr) { |
|
|
|
xhr.setRequestHeader('Password', rspamd.getPassword()); |
|
|
|
}, |
|
|
|
success: function (data) { |
|
|
|
var items = process_symbols_data(data)[0]; |
|
|
|
ft.symbols.rows.load(items); |
|
|
|
}, |
|
|
|
error: function (data) { |
|
|
|
rspamd.alertMessage('alert-modal alert-error', data.statusText); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|