[pmg-devel] [PATCH widget-toolkit 5/7] add ACME account panel

Dominik Csapak d.csapak at proxmox.com
Thu Mar 11 14:51:01 CET 2021


high level question/remark:

would it not be nicer if we set the acmeUrl
in Proxmox.Utils to e.g., /config/acme
and overwrite that in pve ? (like
we do with task descriptions?)

this way the caller does not have to concern
itself with the url and we only set it one time per product

On 3/9/21 3:13 PM, Wolfgang Bumiller wrote:
> 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 <w.bumiller at proxmox.com>
> ---
>   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);
> +	    },
> +	});
> +    },
> +});
> 




More information about the pmg-devel mailing list