[pmg-devel] [PATCH pmg-gui v2 1/1] add Custom Scores panel to the Spam Detector
Dominik Csapak
d.csapak at proxmox.com
Thu Nov 14 12:18:55 CET 2019
with this panel, users can manually override a rule score for
SpamAssassin rules. This can be useful sometimes, e.g. if
a certain rule always triggers in a certain environment which
is considered spam by the SpamAssassin rules
after adding/editing a rule, we show diff, similar to the network
panel, and offer a button to apply those changes (and restart
pmg-smtp-filter). the changes can also be reverted
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
changes from v1:
* fix 'changtext' typo
js/Makefile | 1 +
js/SpamDetectorConfiguration.js | 7 +-
js/SpamDetectorCustom.js | 308 ++++++++++++++++++++++++++++++++
3 files changed, 315 insertions(+), 1 deletion(-)
create mode 100644 js/SpamDetectorCustom.js
diff --git a/js/Makefile b/js/Makefile
index 762b43d..e0ac026 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -54,6 +54,7 @@ JSSRC= \
SpamQuarantineOptions.js \
SpamDetectorStatus.js \
SpamDetectorConfiguration.js \
+ SpamDetectorCustom.js \
VirusDetectorOptions.js \
VirusQuarantineOptions.js \
VirusQuarantine.js \
diff --git a/js/SpamDetectorConfiguration.js b/js/SpamDetectorConfiguration.js
index f10c8dc..2c0d755 100644
--- a/js/SpamDetectorConfiguration.js
+++ b/js/SpamDetectorConfiguration.js
@@ -23,7 +23,12 @@ Ext.define('PMG.SpamDetectorConfiguration', {
title: gettext('Status'),
itemId: 'status',
xtype: 'pmgSpamDetectorStatus'
- }
+ },
+ {
+ title: gettext('Custom Scores'),
+ itemId: 'scores',
+ xtype: 'pmgSpamDetectorCustomScores'
+ },
]
});
diff --git a/js/SpamDetectorCustom.js b/js/SpamDetectorCustom.js
new file mode 100644
index 0000000..34cd95d
--- /dev/null
+++ b/js/SpamDetectorCustom.js
@@ -0,0 +1,308 @@
+Ext.define('pmg-sa-custom', {
+ extend: 'Ext.data.Model',
+ fields: [ 'name', 'score', 'comment', 'digest' ],
+ idProperty: 'name'
+});
+
+Ext.define('PMG.SpamDetectorCustomScores', {
+ extend: 'Ext.panel.Panel',
+ xtype: 'pmgSpamDetectorCustomScores',
+
+ layout: 'border',
+
+ viewModel: {
+ data: {
+ applied: true,
+ changetext: '',
+ digest: null,
+ },
+ },
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+
+ reload: function() {
+ var me = this;
+ var vm = this.getViewModel();
+ var grid = me.lookup('grid');
+
+ Proxmox.Utils.API2Request({
+ url: '/config/customscores',
+ failure: function(response, opts) {
+ grid.getStore().loadData({});
+ Proxmox.Utils.setErrorMask(grid, response.htmlStatus);
+ vm.set('digest', null);
+ vm.set('applied', true);
+ vm.set('changetext', '');
+ },
+ success: function(response, opts) {
+ let data = response.result.data;
+ let digestel = data.pop(); // last element is digest
+ let changes = response.result.changes;
+ grid.getStore().loadData(data);
+
+ vm.set('digest', digestel.digest);
+ vm.set('applied', !changes);
+ vm.set('changetext', `<pre>${changes || ''}</pre>`);
+ }
+ });
+ },
+
+ revert: function() {
+ var me = this;
+ var vm = this.getViewModel();
+
+ Proxmox.Utils.API2Request({
+ url: '/config/customscores',
+ method: 'DELETE',
+ param: {
+ digest: vm.get('digest'),
+ },
+ failure: function(response, opts) {
+ grid.getStore().loadData({});
+ Proxmox.Utils.setErrorMask(grid, response.htmlStatus);
+ vm.set('digest', null);
+ vm.set('applied', true);
+ vm.set('changetext', '');
+ },
+ success: () => { me.reload(); },
+ });
+ },
+
+ restart: function() {
+ var me = this;
+ var vm = this.getViewModel();
+
+ var win = Ext.createWidget('proxmoxWindowEdit', {
+ method: 'PUT',
+ url: "/api2/extjs/config/customscores",
+ isCreate: true,
+ submitText: gettext('Apply'),
+ showProgress: true,
+ taskDone: () => { me.reload(); },
+
+ title: gettext("Apply Custom Scores"),
+
+ items: [
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'restart-daemon',
+ fieldLabel: gettext('Restart pmg-smtp-filter'),
+ labelWidth: 150,
+ checked: true,
+ },
+ {
+ xtype: 'hiddenfield',
+ name: 'digest',
+ value: vm.get('digest'),
+ }
+ ]
+ }).show();
+ },
+
+ create_custom: function() {
+ var me = this;
+ var vm = this.getViewModel();
+
+ var win = Ext.createWidget('proxmoxWindowEdit', {
+ method: 'POST',
+ url: "/api2/extjs/config/customscores",
+ isCreate: true,
+ subject: gettext("Custom Rule Score"),
+ items: [
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'name',
+ allowBlank: false,
+ fieldLabel: gettext('Name')
+ },
+ {
+ xtype: 'numberfield',
+ name: 'score',
+ allowBlank: false,
+ fieldLabel: gettext('Score')
+ },
+
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'comment',
+ fieldLabel: gettext("Comment")
+ },
+ {
+ xtype: 'hiddenfield',
+ name: 'digest',
+ value: vm.get('digest'),
+ }
+ ]
+ });
+
+ win.on('destroy', me.reload, me);
+ win.show();
+ },
+
+ run_editor: function() {
+ var me = this;
+ var vm = this.getViewModel();
+ var grid = me.lookup('grid');
+ var rec = grid.getSelection()[0];
+ if (!rec) {
+ return;
+ }
+
+ var win = Ext.createWidget('proxmoxWindowEdit', {
+ url: "/api2/extjs/config/customscores/" + rec.data.name,
+ method: 'PUT',
+ subject: gettext("Custom Rule Score"),
+ items: [
+ {
+ xtype: 'displayfield',
+ name: 'name',
+ fieldLabel: gettext('Name')
+ },
+ {
+ xtype: 'numberfield',
+ name: 'score',
+ allowBlank: false,
+ fieldLabel: gettext('Score')
+ },
+
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'comment',
+ fieldLabel: gettext("Comment")
+ },
+ {
+ xtype: 'hiddenfield',
+ name: 'digest',
+ value: vm.get('digest'),
+ }
+ ]
+ });
+
+ win.load();
+ win.on('destroy', me.reload, me);
+ win.show();
+ },
+ },
+
+ listeners: {
+ activate: 'reload',
+ },
+
+ defaults: {
+ border: 0,
+ },
+
+ items: [
+ {
+ xtype: 'gridpanel',
+ region: 'center',
+ reference: 'grid',
+
+ store: {
+ model: 'pmg-sa-custom',
+ proxy: {
+ type: 'proxmox',
+ url: "/api2/json/config/customscores"
+ },
+ sorters: {
+ property: 'name',
+ }
+ },
+
+ tbar: [
+ {
+ xtype: 'proxmoxButton',
+ text: gettext('Edit'),
+ disabled: true,
+ handler: 'run_editor'
+ },
+ {
+ text: gettext('Create'),
+ handler: 'create_custom',
+ },
+ {
+ xtype: 'proxmoxStdRemoveButton',
+ getUrl: function(rec) {
+ let digest = this.up('grid').digest;
+ let url = `/config/customscores/${rec.getId()}`;
+ if (digest) {
+ url += `?digest=${digest}`
+ }
+ return url;
+ },
+ callback: 'reload',
+ },
+ ' ',
+ {
+ text: gettext('Revert'),
+ reference: 'revert_btn',
+ handler: 'revert',
+ disabled: true,
+ bind: {
+ disabled: '{applied}',
+ },
+ },
+ '-',
+ {
+ text: gettext('Apply Custom Scores'),
+ reference: 'restart_btn',
+ disabled: true,
+ bind: {
+ disabled: '{applied}',
+ },
+ handler: 'restart',
+ }
+ ],
+
+ viewConfig: {
+ trackOver: false
+ },
+
+ columns: [
+ {
+ header: gettext('Name'),
+ width: 200,
+ sortable: true,
+ dataIndex: 'name'
+ },
+ {
+ header: gettext('Score'),
+ width: 200,
+ sortable: true,
+ dataIndex: 'score'
+ },
+ {
+ header: gettext('Comment'),
+ sortable: false,
+ renderer: Ext.String.htmlEncode,
+ dataIndex: 'comment',
+ flex: 1
+ }
+ ],
+
+ listeners: {
+ itemdblclick: 'run_editor',
+ }
+ },
+ {
+ xtype: 'panel',
+ bodyPadding: 5,
+ region: 'south',
+ autoScroll: true,
+ flex: 0.5,
+ hidden: true,
+ bind: {
+ hidden: '{applied}',
+ html: '{changetext}'
+ },
+ reference: 'changes',
+ tbar: [
+ gettext('Pending changes') + ' (' +
+ gettext('Please restart pmg-smtp-filter to activate changes') + ')'
+ ],
+ split: true,
+ }
+ ],
+
+});
--
2.20.1
More information about the pmg-devel
mailing list