[pmg-devel] [PATCH pmg-gui 1/1] add Custom Scores panel to the Spam Detector

Dominik Csapak d.csapak at proxmox.com
Fri Nov 8 14:29:32 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>
---
 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..a65fcdf
--- /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('changtext', '');
+		},
+		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('changtext', '');
+		},
+		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