From 5df894de2622ad972f10520cfb4d1aaa30d0f941 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 16 Mar 2021 11:24:21 +0100 Subject: [PATCH] add ACME account panel Copied from PVE with URLs now being based on the 'acmeUrl' property which should point to the acme/ root containing /tos, /directories, etc. Signed-off-by: Wolfgang Bumiller --- src/Makefile | 2 + src/panel/ACMEAccount.js | 116 ++++++++++++++++++++++ src/window/ACMEAccount.js | 204 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 322 insertions(+) create mode 100644 src/panel/ACMEAccount.js create mode 100644 src/window/ACMEAccount.js diff --git a/src/Makefile b/src/Makefile index d782e92..00a25c7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -50,6 +50,7 @@ JSSRC= \ panel/RRDChart.js \ panel/GaugeWidget.js \ panel/Certificates.js \ + panel/ACMEAccount.js \ window/Edit.js \ window/PasswordEdit.js \ window/SafeDestroy.js \ @@ -58,6 +59,7 @@ JSSRC= \ window/DiskSmart.js \ window/ZFSDetail.js \ window/Certificates.js \ + window/ACMEAccount.js \ node/APT.js \ node/NetworkEdit.js \ node/NetworkView.js \ diff --git a/src/panel/ACMEAccount.js b/src/panel/ACMEAccount.js new file mode 100644 index 0000000..c7d329e --- /dev/null +++ b/src/panel/ACMEAccount.js @@ -0,0 +1,116 @@ +Ext.define('Proxmox.panel.ACMEAccounts', { + extend: 'Ext.grid.Panel', + xtype: 'pmxACMEAccounts', + + title: gettext('Accounts'), + + acmeUrl: undefined, + + controller: { + xclass: 'Ext.app.ViewController', + + addAccount: function() { + let me = this; + let view = me.getView(); + let defaultExists = view.getStore().findExact('name', 'default') !== -1; + Ext.create('Proxmox.window.ACMEAccountCreate', { + defaultExists, + acmeUrl: view.acmeUrl, + taskDone: function() { + me.reload(); + }, + }).show(); + }, + + viewAccount: function() { + let me = this; + let view = me.getView(); + let selection = view.getSelection(); + if (selection.length < 1) return; + Ext.create('Proxmox.window.ACMEAccountView', { + url: `${view.acmeUrl}/account/${selection[0].data.name}`, + }).show(); + }, + + reload: function() { + let me = this; + let view = me.getView(); + view.getStore().rstore.load(); + }, + + showTaskAndReload: function(options, success, response) { + let me = this; + if (!success) return; + + let upid = response.result.data; + Ext.create('Proxmox.window.TaskProgress', { + upid, + taskDone: function() { + me.reload(); + }, + }).show(); + }, + }, + + minHeight: 150, + emptyText: gettext('No Accounts configured'), + + columns: [ + { + dataIndex: 'name', + text: gettext('Name'), + renderer: Ext.String.htmlEncode, + flex: 1, + }, + ], + + listeners: { + itemdblclick: 'viewAccount', + }, + + store: { + type: 'diff', + autoDestroy: true, + autoDestroyRstore: true, + rstore: { + type: 'update', + storeid: 'proxmox-acme-accounts', + model: 'proxmox-acme-accounts', + autoStart: true, + }, + sorters: 'name', + }, + + initComponent: function() { + let me = this; + + if (!me.acmeUrl) { + throw "no acmeUrl given"; + } + + Ext.apply(me, { + tbar: [ + { + xtype: 'proxmoxButton', + text: gettext('Add'), + selModel: false, + handler: 'addAccount', + }, + { + xtype: 'proxmoxButton', + text: gettext('View'), + handler: 'viewAccount', + disabled: true, + }, + { + xtype: 'proxmoxStdRemoveButton', + baseurl: `${me.acmeUrl}/account`, + callback: 'showTaskAndReload', + }, + ], + }); + + me.callParent(); + me.store.rstore.proxy.setUrl(`/api2/json/${me.acmeUrl}/account`); + }, +}); diff --git a/src/window/ACMEAccount.js b/src/window/ACMEAccount.js new file mode 100644 index 0000000..05278a8 --- /dev/null +++ b/src/window/ACMEAccount.js @@ -0,0 +1,204 @@ +Ext.define('Proxmox.window.ACMEAccountCreate', { + extend: 'Proxmox.window.Edit', + mixins: ['Proxmox.Mixin.CBind'], + xtype: 'pmxACMEAccountCreate', + + acmeUrl: undefined, + + width: 450, + title: gettext('Register Account'), + isCreate: true, + method: 'POST', + submitText: gettext('Register'), + showTaskViewer: true, + defaultExists: false, + + items: [ + { + xtype: 'proxmoxtextfield', + fieldLabel: gettext('Account Name'), + name: 'name', + cbind: { + emptyText: (get) => get('defaultExists') ? '' : 'default', + allowBlank: (get) => !get('defaultExists'), + }, + }, + { + xtype: 'textfield', + name: 'contact', + vtype: 'email', + allowBlank: false, + fieldLabel: gettext('E-Mail'), + }, + { + xtype: 'proxmoxComboGrid', + name: 'directory', + reference: 'directory', + allowBlank: false, + valueField: 'url', + displayField: 'name', + fieldLabel: gettext('ACME Directory'), + store: { + autoLoad: true, + fields: ['name', 'url'], + idProperty: ['name'], + proxy: { type: 'proxmox' }, + sorters: { + property: 'name', + order: 'ASC', + }, + }, + listConfig: { + columns: [ + { + header: gettext('Name'), + dataIndex: 'name', + flex: 1, + }, + { + header: gettext('URL'), + dataIndex: 'url', + flex: 1, + }, + ], + }, + listeners: { + change: function(combogrid, value) { + let me = this; + + if (!value) { + return; + } + + let acmeUrl = me.up('window').acmeUrl; + + let disp = me.up('window').down('#tos_url_display'); + let field = me.up('window').down('#tos_url'); + let checkbox = me.up('window').down('#tos_checkbox'); + + disp.setValue(gettext('Loading')); + field.setValue(undefined); + checkbox.setValue(undefined); + checkbox.setHidden(true); + + Proxmox.Utils.API2Request({ + url: `${acmeUrl}/tos`, + method: 'GET', + params: { + directory: value, + }, + success: function(response, opt) { + field.setValue(response.result.data); + disp.setValue(response.result.data); + checkbox.setHidden(false); + }, + failure: function(response, opt) { + Ext.Msg.alert(gettext('Error'), response.htmlStatus); + }, + }); + }, + }, + }, + { + xtype: 'displayfield', + itemId: 'tos_url_display', + renderer: Proxmox.Utils.render_optional_url, + name: 'tos_url_display', + }, + { + xtype: 'hidden', + itemId: 'tos_url', + name: 'tos_url', + }, + { + xtype: 'proxmoxcheckbox', + itemId: 'tos_checkbox', + boxLabel: gettext('Accept TOS'), + submitValue: false, + validateValue: function(value) { + if (value && this.checked) { + return true; + } + return false; + }, + }, + ], + + initComponent: function() { + let me = this; + + if (!me.acmeUrl) { + throw "no acmeUrl given"; + } + + me.url = `${me.acmeUrl}/account`; + + me.callParent(); + + me.lookup('directory') + .store + .proxy + .setUrl(`/api2/json/${me.acmeUrl}/directories`); + }, +}); + +Ext.define('Proxmox.window.ACMEAccountView', { + extend: 'Proxmox.window.Edit', + xtype: 'pmxACMEAccountView', + + width: 600, + fieldDefaults: { + labelWidth: 140, + }, + + title: gettext('Account'), + + items: [ + { + xtype: 'displayfield', + fieldLabel: gettext('E-Mail'), + name: 'email', + }, + { + xtype: 'displayfield', + fieldLabel: gettext('Created'), + name: 'createdAt', + }, + { + xtype: 'displayfield', + fieldLabel: gettext('Status'), + name: 'status', + }, + { + xtype: 'displayfield', + fieldLabel: gettext('Directory'), + renderer: Proxmox.Utils.render_optional_url, + name: 'directory', + }, + { + xtype: 'displayfield', + fieldLabel: gettext('Terms of Services'), + renderer: Proxmox.Utils.render_optional_url, + name: 'tos', + }, + ], + + initComponent: function() { + var me = this; + + me.callParent(); + + // hide OK/Reset button, because we just want to show data + me.down('toolbar[dock=bottom]').setVisible(false); + + me.load({ + success: function(response) { + var data = response.result.data; + data.email = data.account.contact[0]; + data.createdAt = data.account.createdAt; + data.status = data.account.status; + me.setValues(data); + }, + }); + }, +}); -- 2.39.5