[pmg-devel] [PATCH pmg-gui 1/1] add Custom Scores panel to the Spam Detector
Stoiko Ivanov
s.ivanov at proxmox.com
Wed Nov 13 15:13:29 CET 2019
On Fri, 8 Nov 2019 14:29:32 +0100
Dominik Csapak <d.csapak at proxmox.com> wrote:
> 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', '');
small typo: s/changtext/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('changtext', '');
also here
> + },
> + 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,
> + }
> + ],
> +
> +});
More information about the pmg-devel
mailing list