From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <d.csapak@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 52AA0947E2
 for <pmg-devel@lists.proxmox.com>; Thu, 22 Feb 2024 10:14:52 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 35C9F4BA6
 for <pmg-devel@lists.proxmox.com>; Thu, 22 Feb 2024 10:14:22 +0100 (CET)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [94.136.29.106])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS
 for <pmg-devel@lists.proxmox.com>; Thu, 22 Feb 2024 10:14:21 +0100 (CET)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 40BC6447C4
 for <pmg-devel@lists.proxmox.com>; Thu, 22 Feb 2024 10:14:21 +0100 (CET)
From: Dominik Csapak <d.csapak@proxmox.com>
To: pmg-devel@lists.proxmox.com
Date: Thu, 22 Feb 2024 10:14:19 +0100
Message-Id: <20240222091420.2732402-3-d.csapak@proxmox.com>
X-Mailer: git-send-email 2.30.2
In-Reply-To: <20240222091420.2732402-1-d.csapak@proxmox.com>
References: <20240222091420.2732402-1-d.csapak@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.019 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 DMARC_MISSING             0.1 Missing DMARC policy
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 T_SCC_BODY_TEXT_LINE    -0.01 -
 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See
 http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more
 information. [defines.mk]
Subject: [pmg-devel] [PATCH pmg-gui v3 2/3] rules/objects: add mode selector
 dropdown
X-BeenThere: pmg-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Mail Gateway development discussion
 <pmg-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pmg-devel>, 
 <mailto:pmg-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pmg-devel/>
List-Post: <mailto:pmg-devel@lists.proxmox.com>
List-Help: <mailto:pmg-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pmg-devel>, 
 <mailto:pmg-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Thu, 22 Feb 2024 09:14:52 -0000

for objects and object types in rules. We add a simple dropdown for the
'and' and 'invert' flags, to be somewhat consistent with the
notification matchers from pve and to make the wording more clear than
simple and/invert.

For What matches add a special warning hint, since that behaves a bit
special because of the mail parts.

When the mode changes for an object group, we reload the list of
objects since that holds the info about the attributes, so to avoid
having to keep track in the gui which field changed on the group,
we simply reload the list with the current information.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 js/Makefile                    |  1 +
 js/ObjectGroup.js              | 68 +++++++++++++++++++++++++++++++++-
 js/ObjectGroupConfiguration.js |  2 +
 js/RuleInfo.js                 | 42 +++++++++++++++++++++
 js/form/MatchModeSelector.js   | 11 ++++++
 5 files changed, 122 insertions(+), 2 deletions(-)
 create mode 100644 js/form/MatchModeSelector.js

diff --git a/js/Makefile b/js/Makefile
index 5f57e0d..2fb7d19 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -3,6 +3,7 @@ include ../defines.mk
 JSSRC=							\
 	Utils.js					\
 	form/FilterField.js				\
+	form/MatchModeSelector.js			\
 	FilterProxy.js					\
 	LoginView.js					\
 	RoleSelector.js					\
diff --git a/js/ObjectGroup.js b/js/ObjectGroup.js
index 387fd54..214e641 100644
--- a/js/ObjectGroup.js
+++ b/js/ObjectGroup.js
@@ -10,6 +10,7 @@ Ext.define('PMG.ObjectGroup', {
     showDirection: false, // only important for SMTP Whitelist
 
     ogdata: undefined,
+    objectClass: undefined,
 
     emptyText: gettext('Please select an object.'),
 
@@ -32,10 +33,15 @@ Ext.define('PMG.ObjectGroup', {
     setObjectInfo: function(ogdata) {
 	let me = this;
 
+	let mode = ogdata?.invert ? 'not' : '';
+	mode += ogdata?.and ? 'all' : 'any';
+
 	me.ogdata = ogdata;
 
 	if (me.ogdata === undefined) {
 	    me.down('#oginfo').update(me.emptyText);
+	    me.down('#modeBox').setHidden(true);
+	    me.down('#whatWarning').setHidden(true);
 	} else {
 	    let html = '<b>' + Ext.String.htmlEncode(me.ogdata.name) + '</b>';
 	    html += "<br><br>";
@@ -43,6 +49,12 @@ Ext.define('PMG.ObjectGroup', {
 
 	    me.down('#oginfo').update(html);
 	    me.down('#ogdata').setHidden(false);
+	    let modeSelector = me.down('#modeSelector');
+	    modeSelector.suspendEvents();
+	    me.down('#modeSelector').setValue(mode);
+	    modeSelector.resumeEvents();
+	    me.down('#modeBox').setHidden(false);
+	    me.down('#whatWarning').setHidden(me.objectClass !== 'what' || mode === 'any');
 	}
     },
 
@@ -216,13 +228,51 @@ Ext.define('PMG.ObjectGroup', {
 	me.dockedItems.push({
 	    dock: 'top',
 	    border: 1,
-	    layout: 'anchor',
+	    layout: 'hbox',
 	    hidden: !!me.hideGroupInfo,
 	    itemId: 'ogdata',
 	    items: [
+		{
+		    xtype: 'container',
+		    itemId: 'modeBox',
+		    hidden: true,
+		    width: 220,
+		    padding: 10,
+		    layout: {
+			type: 'vbox',
+			align: 'stretch',
+		    },
+		    items: [
+			{
+			    xtype: 'box',
+			    html: `<b>${gettext("Match if")}</b>`,
+			},
+			{
+			    xtype: 'pmgMatchModeSelector',
+			    itemId: 'modeSelector',
+			    padding: '10 0 0 0',
+			    listeners: {
+				change: function(_field, value) {
+				    let invert = value.startsWith('not') ? 1 : 0;
+				    let and = value.endsWith('all') ? 1 : 0;
+
+				    Proxmox.Utils.API2Request({
+					url: `${me.baseurl}/config`,
+					method: 'PUT',
+					params: {
+					    and,
+					    invert,
+					},
+					success: () => me.fireEvent('modeUpdate', me),
+				    });
+				},
+			    },
+			},
+		    ],
+		},
 		{
 		    xtype: 'component',
-		    anchor: '100%',
+		    flex: 1,
 		    itemId: 'oginfo',
 		    style: { 'white-space': 'pre' },
 		    padding: 10,
@@ -241,6 +291,20 @@ Ext.define('PMG.ObjectGroup', {
 	    ],
 	});
 
+	me.dockedItems.push({
+	    dock: 'top',
+	    border: 1,
+	    hidden: true,
+	    itemId: 'whatWarning',
+	    bodyPadding: 5,
+	    items: {
+		xtype: 'displayfield',
+		margin: 0,
+		value: gettext("Caution: 'What Objects' match each mail part separately, so be careful with any option besides 'Any matches'."),
+		userCls: 'pmx-hint',
+	    },
+	});
+
 	Proxmox.Utils.monStoreErrors(me, me.store, true);
 
 	Ext.apply(me, {
diff --git a/js/ObjectGroupConfiguration.js b/js/ObjectGroupConfiguration.js
index 1d72851..eb80032 100644
--- a/js/ObjectGroupConfiguration.js
+++ b/js/ObjectGroupConfiguration.js
@@ -30,6 +30,7 @@ Ext.define('PMG.ObjectGroupConfiguration', {
 
 	var right = Ext.create('PMG.ObjectGroup', {
 	    otype_list: me.otype_list,
+	    objectClass: me.ogclass,
 	    border: false,
 	    region: 'center',
 	    listeners: {
@@ -40,6 +41,7 @@ Ext.define('PMG.ObjectGroupConfiguration', {
 			left.run_editor();
 		    }
 		},
+		modeUpdate: () => left.reload(),
 	    },
 	});
 
diff --git a/js/RuleInfo.js b/js/RuleInfo.js
index 404c437..12c9dcb 100644
--- a/js/RuleInfo.js
+++ b/js/RuleInfo.js
@@ -120,6 +120,8 @@ Ext.define('PMG.RuleInfo', {
 			name: oc,
 			oclass: oc,
 			type: true,
+			invert: ruledata[`${oc}-invert`],
+			and: ruledata[`${oc}-and`],
 			leaf: false,
 			expanded: true,
 			expandable: false,
@@ -162,6 +164,23 @@ Ext.define('PMG.RuleInfo', {
 	    return true;
 	},
 
+	updateMode: function(field, value) {
+	    let me = this;
+	    let vm = me.getViewModel();
+	    let oclass = field.getWidgetRecord().data.oclass;
+
+	    let params = {};
+	    params[`${oclass}-invert`] = value.startsWith('not') ? 1 : 0;
+	    params[`${oclass}-and`] = value.endsWith('all') ? 1 : 0;
+
+	    Proxmox.Utils.API2Request({
+		url: `${vm.get('baseurl')}/config`,
+		method: 'PUT',
+		params,
+		success: () => me.reload(),
+	    });
+	},
+
 	control: {
 	    'treepanel[reference=usedobjects]': {
 		drop: 'addDrop',
@@ -169,6 +188,9 @@ Ext.define('PMG.RuleInfo', {
 	    'tabpanel[reference=availobjects] > grid': {
 		drop: 'removeDrop',
 	    },
+	    'pmgMatchModeSelector': {
+		change: 'updateMode',
+	    },
 	},
     },
 
@@ -312,6 +334,26 @@ Ext.define('PMG.RuleInfo', {
 		    },
 		    flex: 1,
 		},
+		{
+		    header: gettext('Match if'),
+		    xtype: 'widgetcolumn',
+		    width: 200,
+		    widget: {
+			xtype: 'pmgMatchModeSelector',
+		    },
+		    onWidgetAttach: function(col, widget, rec) {
+			if (rec.data.type && rec.data.oclass !== 'action') {
+			    let mode = rec.data.invert ? 'not' : '';
+			    mode += rec.data.and ? 'all' : 'any';
+			    widget.suspendEvents();
+			    widget.setValue(mode);
+			    widget.resumeEvents();
+			    widget.setHidden(false);
+			} else {
+			    widget.setHidden(true);
+			}
+		    },
+		},
 		{
 		    text: '',
 		    xtype: 'actioncolumn',
diff --git a/js/form/MatchModeSelector.js b/js/form/MatchModeSelector.js
new file mode 100644
index 0000000..07f6e59
--- /dev/null
+++ b/js/form/MatchModeSelector.js
@@ -0,0 +1,11 @@
+Ext.define('PMG.MatchModeSelector', {
+    extend: 'Proxmox.form.KVComboBox',
+    alias: 'widget.pmgMatchModeSelector',
+
+    comboItems: [
+	['all', gettext('All match')],
+	['any', gettext('Any matches')],
+	['notall', gettext('At least one does not match')],
+	['notany', gettext('None matches')],
+    ],
+});
-- 
2.30.2