From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 DE2F88A8CB for ; Thu, 20 Oct 2022 21:15:23 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 9EF6D1AB9D for ; Thu, 20 Oct 2022 21:15:23 +0200 (CEST) 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 ; Thu, 20 Oct 2022 21:15:20 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id BA5AD44AEB for ; Thu, 20 Oct 2022 21:15:20 +0200 (CEST) From: Stoiko Ivanov To: pmg-devel@lists.proxmox.com Date: Thu, 20 Oct 2022 21:15:00 +0200 Message-Id: <20221020191500.2414-5-s.ivanov@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221020191500.2414-1-s.ivanov@proxmox.com> References: <20221020191500.2414-1-s.ivanov@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.175 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% 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 Subject: [pmg-devel] [PATCH pmg-gui 4/4] quarantine: move all quarantines to the new controller X-BeenThere: pmg-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Mail Gateway development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Oct 2022 19:15:23 -0000 fixes #1674 (the comment about multiselect for the virus quarantine) fixes #3947 (multiselect for attachment quarantine) Signed-off-by: Stoiko Ivanov --- * best viewed with `-w` js/AttachmentQuarantine.js | 113 +++++++-------- js/SpamQuarantine.js | 290 ++++++++++++------------------------- js/VirusQuarantine.js | 86 +++-------- 3 files changed, 164 insertions(+), 325 deletions(-) diff --git a/js/AttachmentQuarantine.js b/js/AttachmentQuarantine.js index 5e41ada..831ce0a 100644 --- a/js/AttachmentQuarantine.js +++ b/js/AttachmentQuarantine.js @@ -18,87 +18,59 @@ Ext.define('pmg-attachment-list', { idProperty: 'id', }); -Ext.define('PMG.AttachmentQuarantine', { - extend: 'Ext.container.Container', - xtype: 'pmgAttachmentQuarantine', - - border: false, - layout: { type: 'border' }, - - defaults: { border: false }, - - controller: { - - xclass: 'Ext.app.ViewController', - - updatePreview: function(raw, rec) { - var preview = this.lookupReference('preview'); +Ext.define('PMG.AttachmentQuarantineController', { + extend: 'PMG.controller.QuarantineController', + alias: 'controller.attachmentquarantine', + xtype: 'pmgAttachmentQuarantineController', + + onSelectMail: function() { + let me = this; + let list = this.lookupReference('list'); + let selection = list.selModel.getSelection(); + if (selection.length <= 1) { + let rec = selection[0] || {}; + me.lookup('attachmentlist').setID(rec); + } - if (!rec || !rec.data || !rec.data.id) { - preview.update(''); - preview.setDisabled(true); - return; - } + me.callParent(); + }, - let url = `/api2/htmlmail/quarantine/content?id=${rec.data.id}`; - if (raw) { - url += '&raw=1'; - } - preview.setDisabled(false); - preview.update(""); + control: { + 'button[reference=raw]': { + click: 'toggleRaw', }, - - toggleRaw: function(button) { - var me = this; - var list = this.lookupReference('list'); - var rec = list.getSelection()[0] || {}; - me.lookup('mailinfo').setVisible(me.raw); - me.raw = !me.raw; - me.updatePreview(me.raw, rec); + 'pmgQuarantineList': { + selectionChange: 'onSelectMail', }, + }, - btnHandler: function(button, e) { - var list = this.lookupReference('list'); - var selected = list.getSelection(); - if (!selected.length) { - return; - } +}); - var action = button.reference; +Ext.define('PMG.AttachmentQuarantine', { + extend: 'Ext.container.Container', + xtype: 'pmgAttachmentQuarantine', - PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() { - list.getController().load(); - }); - }, + border: false, + layout: { type: 'border' }, - onSelectMail: function() { - let me = this; - let list = me.lookup('list'); - let rec = list.getSelection()[0] || {}; - let mailinfo = me.lookup('mailinfo'); + defaults: { border: false }, - me.updatePreview(me.raw || false, rec); - me.lookup('attachmentlist').setID(rec); - mailinfo.setVisible(!!rec.data && !me.raw); - mailinfo.update(rec.data); + viewModel: { + parent: null, + data: { + mailid: '', }, - - control: { - 'button[reference=raw]': { - click: 'toggleRaw', - }, - 'pmgQuarantineList': { - selectionChange: 'onSelectMail', - }, + formulas: { + downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')), }, - }, - + controller: 'attachmentquarantine', items: [ { title: gettext('Attachment Quarantine'), xtype: 'pmgQuarantineList', emptyText: gettext('No data in database'), + selModel: 'checkboxmodel', emailSelection: false, reference: 'list', region: 'west', @@ -163,6 +135,19 @@ Ext.define('PMG.AttachmentQuarantine', { iconCls: 'fa fa-file-code-o', }, '->', + { + xtype: 'button', + reference: 'download', + text: gettext('Download'), + setDownload: function(id) { + this.el.dom.download = id + ".eml"; + }, + bind: { + href: '{downloadMailURL}', + download: '{mailid}', + }, + iconCls: 'fa fa-download', + }, { reference: 'deliver', text: gettext('Deliver'), diff --git a/js/SpamQuarantine.js b/js/SpamQuarantine.js index efb7fdc..fdacaec 100644 --- a/js/SpamQuarantine.js +++ b/js/SpamQuarantine.js @@ -33,225 +33,123 @@ Ext.define('pmg-spam-list', { idProperty: 'id', }); -Ext.define('PMG.SpamQuarantine', { - extend: 'Ext.container.Container', - xtype: 'pmgSpamQuarantine', - - border: false, - layout: { type: 'border' }, +Ext.define('PMG.SpamQuarantineController', { + extend: 'PMG.controller.QuarantineController', + xtype: 'pmgSpamQuarantineController', + alias: 'controller.spamquarantine', - defaults: { border: false }, + updatePreview: function(raw, rec) { + let me = this; + me.lookupReference('spam').setDisabled(false); - // from mail link - cselect: undefined, + me.callParent(arguments); + }, - viewModel: { - parent: null, - data: { - mailid: '', - }, - formulas: { - downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')), - }, + multiSelect: function(selection) { + let me = this; + let spam = me.lookupReference('spam'); + spam.setDisabled(true); + spam.setPressed(false); + me.lookupReference('spaminfo').setVisible(false); + me.callParent(selection); }, - controller: { - xclass: 'Ext.app.ViewController', + onSelectMail: function() { + let me = this; + let list = me.lookupReference('list'); + let selection = list.selModel.getSelection(); + if (selection.length <= 1) { + let rec = selection[0] || {}; + me.lookupReference('spaminfo').setID(rec); + } + me.callParent(); + }, - updatePreview: function(raw, rec) { - var preview = this.lookupReference('preview'); - if (!rec || !rec.data || !rec.data.id) { - preview.update(''); - preview.setDisabled(true); - return; - } + toggleSpamInfo: function(btn) { + var grid = this.lookupReference('spaminfo'); + grid.setVisible(!grid.isVisible()); + }, - let url = `/api2/htmlmail/quarantine/content?id=${rec.data.id}`; - if (raw) { - url += '&raw=1'; - } - preview.setDisabled(false); - this.lookupReference('raw').setDisabled(false); - this.lookupReference('spam').setDisabled(false); - this.lookupReference('download').setDisabled(false); - preview.update(""); - }, + openContextMenu: function(table, record, tr, index, event) { + event.stopEvent(); + let me = this; + let list = me.lookup('list'); + Ext.create('PMG.menu.SpamContextMenu', { + callback: action => me.doAction(action, list.getSelection()), + }).showAt(event.getXY()); + }, - multiSelect: function(selection) { - var preview = this.lookupReference('preview'); - var raw = this.lookupReference('raw'); - var spam = this.lookupReference('spam'); - var spaminfo = this.lookupReference('spaminfo'); - var mailinfo = this.lookupReference('mailinfo'); - var download = this.lookupReference('download'); + keyPress: function(table, record, item, index, event) { + var me = this; + var list = me.lookup('list'); + var key = event.getKey(); + var action = ''; + switch (key) { + case event.DELETE: + case 127: + action = 'delete'; + break; + case Ext.event.Event.D: + case Ext.event.Event.D + 32: + action = 'deliver'; + break; + case Ext.event.Event.W: + case Ext.event.Event.W + 32: + action = 'whitelist'; + break; + case Ext.event.Event.B: + case Ext.event.Event.B + 32: + action = 'blacklist'; + break; + } - preview.setDisabled(false); - preview.update(`

${gettext('Multiple E-Mails selected')} (${selection.length})

`); - raw.setDisabled(true); - spam.setDisabled(true); - spam.setPressed(false); - spaminfo.setVisible(false); - mailinfo.setVisible(false); - download.setDisabled(true); - }, + if (action !== '') { + me.doAction(action, list.getSelection()); + } + }, - toggleRaw: function(button) { - var me = this; - var list = me.lookupReference('list'); - var rec = list.selModel.getSelection()[0]; - me.lookupReference('mailinfo').setVisible(me.raw); - me.raw = !me.raw; - me.updatePreview(me.raw, rec); - }, + init: function(view) { + this.lookup('list').cselect = view.cselect; + }, - btnHandler: function(button, e) { - var me = this; - var action = button.reference; - var list = this.lookupReference('list'); - var selected = list.getSelection(); - me.doAction(action, selected); + control: { + 'button[reference=raw]': { + click: 'toggleRaw', }, - - doAction: function(action, selected) { - if (!selected.length) { - return; - } - - var list = this.lookupReference('list'); - - if (selected.length > 1) { - let idlist = selected.map(item => item.data.id); - Ext.Msg.confirm( - gettext('Confirm'), - Ext.String.format( - gettext("Action '{0}' for '{1}' items"), - action, selected.length, - ), - async function(button) { - if (button !== 'yes') { - return; - } - - list.mask(gettext('Processing...'), 'x-mask-loading'); - - const sliceSize = 2500, maxInFlight = 2; - let batches = [], batchCount = Math.ceil(selected.length / sliceSize); - for (let i = 0; i * sliceSize < selected.length; i++) { - let sliceStart = i * sliceSize; - let sliceEnd = Math.min(sliceStart + sliceSize, selected.length); - batches.push( - PMG.Async.doQAction( - action, - idlist.slice(sliceStart, sliceEnd), - i + 1, - batchCount, - ), - ); - if (batches.length >= maxInFlight) { - await Promise.allSettled(batches); // eslint-disable-line no-await-in-loop - batches = []; - } - } - await Promise.allSettled(batches); // await possible remaining ones - list.unmask(); - // below can be slow, we could remove directly from the in-memory store, but - // with lots of elements and some failures we could be quite out of sync? - list.getController().load(); - }, - ); - return; - } - - PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() { - let listController = list.getController(); - listController.allowPositionSave = false; - // success -> remove directly to avoid slow store reload for a single-element action - list.getStore().remove(selected[0]); - listController.restoreSavedSelection(); - listController.allowPositionSave = true; - }); + 'button[reference=spam]': { + click: 'toggleSpamInfo', }, - - onSelectMail: function() { - var me = this; - var list = this.lookupReference('list'); - var selection = list.selModel.getSelection(); - if (selection.length > 1) { - me.multiSelect(selection); - return; - } - - var rec = selection[0] || {}; - - me.getViewModel().set('mailid', rec.data ? rec.data.id : ''); - me.updatePreview(me.raw || false, rec); - me.lookupReference('spaminfo').setID(rec); - me.lookupReference('mailinfo').setVisible(!!rec.data && !me.raw); - me.lookupReference('mailinfo').update(rec.data); + 'pmgQuarantineList': { + selectionChange: 'onSelectMail', + itemkeypress: 'keyPress', + rowcontextmenu: 'openContextMenu', }, + }, +}); - toggleSpamInfo: function(btn) { - var grid = this.lookupReference('spaminfo'); - grid.setVisible(!grid.isVisible()); - }, +Ext.define('PMG.SpamQuarantine', { + extend: 'Ext.container.Container', + xtype: 'pmgSpamQuarantine', - openContextMenu: function(table, record, tr, index, event) { - event.stopEvent(); - let me = this; - let list = me.lookup('list'); - Ext.create('PMG.menu.SpamContextMenu', { - callback: action => me.doAction(action, list.getSelection()), - }).showAt(event.getXY()); - }, + border: false, + layout: { type: 'border' }, - keyPress: function(table, record, item, index, event) { - var me = this; - var list = me.lookup('list'); - var key = event.getKey(); - var action = ''; - switch (key) { - case event.DELETE: - case 127: - action = 'delete'; - break; - case Ext.event.Event.D: - case Ext.event.Event.D + 32: - action = 'deliver'; - break; - case Ext.event.Event.W: - case Ext.event.Event.W + 32: - action = 'whitelist'; - break; - case Ext.event.Event.B: - case Ext.event.Event.B + 32: - action = 'blacklist'; - break; - } + defaults: { border: false }, - if (action !== '') { - me.doAction(action, list.getSelection()); - } - }, + // from mail link + cselect: undefined, - init: function(view) { - this.lookup('list').cselect = view.cselect; + viewModel: { + parent: null, + data: { + mailid: '', }, - - control: { - 'button[reference=raw]': { - click: 'toggleRaw', - }, - 'button[reference=spam]': { - click: 'toggleSpamInfo', - }, - 'pmgQuarantineList': { - selectionChange: 'onSelectMail', - itemkeypress: 'keyPress', - rowcontextmenu: 'openContextMenu', - }, + formulas: { + downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')), }, }, + controller: 'spamquarantine', items: [ { diff --git a/js/VirusQuarantine.js b/js/VirusQuarantine.js index 9e9e3b8..3c900f9 100644 --- a/js/VirusQuarantine.js +++ b/js/VirusQuarantine.js @@ -28,80 +28,23 @@ Ext.define('PMG.VirusQuarantine', { defaults: { border: false }, - controller: { - - xclass: 'Ext.app.ViewController', - - updatePreview: function(raw) { - var list = this.lookupReference('list'); - var rec = list.selModel.getSelection()[0]; - var preview = this.lookupReference('preview'); - - if (!rec || !rec.data || !rec.data.id) { - preview.update(''); - preview.setDisabled(true); - return; - } - - let url = `/api2/htmlmail/quarantine/content?id=${rec.data.id}`; - if (raw) { - url += '&raw=1'; - } - preview.setDisabled(false); - preview.update(""); - }, - - toggleRaw: function(button) { - var me = this; - me.lookup('mailinfo').setVisible(me.raw); - me.raw = !me.raw; - me.updatePreview(me.raw); + viewModel: { + parent: null, + data: { + mailid: '', }, - - btnHandler: function(button, e) { - var list = this.lookupReference('list'); - var selected = list.getSelection(); - if (!selected.length) { - return; - } - - var action = button.reference; - - PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() { - list.getController().load(); - }); + formulas: { + downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')), }, - - onSelectMail: function() { - var me = this; - me.updatePreview(me.raw || false); - let mailinfo = me.lookup('mailinfo'); - let list = me.lookup('list'); - let selection = list.getSelection(); - if (selection.length < 1) { - mailinfo.setVisible(false); - return; - } - mailinfo.setVisible(!me.raw); - mailinfo.update(selection[0].data); - }, - - control: { - 'button[reference=raw]': { - click: 'toggleRaw', - }, - 'pmgQuarantineList': { - selectionChange: 'onSelectMail', - }, - }, - }, + controller: 'quarantine', items: [ { title: gettext('Virus Quarantine'), xtype: 'pmgQuarantineList', emptyText: gettext('No data in database'), + selModel: 'checkboxmodel', emailSelection: false, reference: 'list', region: 'west', @@ -172,6 +115,19 @@ Ext.define('PMG.VirusQuarantine', { iconCls: 'fa fa-file-code-o', }, '->', + { + xtype: 'button', + reference: 'download', + text: gettext('Download'), + setDownload: function(id) { + this.el.dom.download = id + ".eml"; + }, + bind: { + href: '{downloadMailURL}', + download: '{mailid}', + }, + iconCls: 'fa fa-download', + }, { reference: 'deliver', text: gettext('Deliver'), -- 2.30.2