public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Alexandre Derumier <aderumier@odiso.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v3 pve-manager 3/4] ui: add vnet permissions panel
Date: Tue,  6 Jun 2023 15:19:26 +0200	[thread overview]
Message-ID: <20230606131927.1667420-10-aderumier@odiso.com> (raw)
In-Reply-To: <20230606131927.1667420-1-aderumier@odiso.com>

Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
 www/manager6/Makefile                |   2 +
 www/manager6/sdn/Browser.js          |  17 +-
 www/manager6/sdn/VnetACLView.js      | 289 +++++++++++++++++++++++++++
 www/manager6/sdn/ZoneContentPanel.js |  41 ++++
 www/manager6/sdn/ZoneContentView.js  |  25 ++-
 5 files changed, 356 insertions(+), 18 deletions(-)
 create mode 100644 www/manager6/sdn/VnetACLView.js
 create mode 100644 www/manager6/sdn/ZoneContentPanel.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 2b577c8e..fb9930af 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -251,10 +251,12 @@ JSSRC= 							\
 	sdn/StatusView.js				\
 	sdn/VnetEdit.js					\
 	sdn/VnetView.js					\
+	sdn/VnetACLView.js					\
 	sdn/VnetPanel.js				\
 	sdn/SubnetEdit.js				\
 	sdn/SubnetView.js				\
 	sdn/ZoneContentView.js				\
+	sdn/ZoneContentPanel.js				\
 	sdn/ZoneView.js					\
 	sdn/OptionsPanel.js				\
 	sdn/controllers/Base.js				\
diff --git a/www/manager6/sdn/Browser.js b/www/manager6/sdn/Browser.js
index 09b0c4fe..3dc5a5ad 100644
--- a/www/manager6/sdn/Browser.js
+++ b/www/manager6/sdn/Browser.js
@@ -25,14 +25,15 @@ Ext.define('PVE.sdn.Browser', {
 
 	const caps = Ext.state.Manager.get('GuiCap');
 
-	if (caps.sdn['SDN.Audit']) {
-	    me.items.push({
-		xtype: 'pveSDNZoneContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content',
-	    });
-	}
+	me.items.push({
+	    nodename: nodename,
+	    zone: sdnId,
+	    xtype: 'pveSDNZoneContentPanel',
+	    title: gettext('Content'),
+	    iconCls: 'fa fa-th',
+	    itemId: 'content',
+	});
+
 	if (caps.sdn['Permissions.Modify']) {
 	    me.items.push({
 		xtype: 'pveACLView',
diff --git a/www/manager6/sdn/VnetACLView.js b/www/manager6/sdn/VnetACLView.js
new file mode 100644
index 00000000..af10d954
--- /dev/null
+++ b/www/manager6/sdn/VnetACLView.js
@@ -0,0 +1,289 @@
+Ext.define('PVE.sdn.VnetACLAdd', {
+    extend: 'Proxmox.window.Edit',
+    alias: ['widget.pveSDNVnetACLAdd'],
+
+    url: '/access/acl',
+    method: 'PUT',
+    isAdd: true,
+    isCreate: true,
+
+    width: 400,
+    initComponent: function() {
+        let me = this;
+
+	let items = [
+	    {
+		xtype: 'hiddenfield',
+		name: 'path',
+		value: me.path,
+		allowBlank: false,
+		fieldLabel: gettext('Path'),
+	    },
+	];
+
+	if (me.aclType === 'group') {
+	    me.subject = gettext("Group Permission");
+	    items.push({
+		xtype: 'pveGroupSelector',
+		name: 'groups',
+		fieldLabel: gettext('Group'),
+	    });
+	} else if (me.aclType === 'user') {
+	    me.subject = gettext("User Permission");
+	    items.push({
+		xtype: 'pmxUserSelector',
+		name: 'users',
+		fieldLabel: gettext('User'),
+	    });
+	} else if (me.aclType === 'token') {
+	    me.subject = gettext("API Token Permission");
+	    items.push({
+		xtype: 'pveTokenSelector',
+		name: 'tokens',
+		fieldLabel: gettext('API Token'),
+	    });
+	} else {
+	    throw "unknown ACL type";
+	}
+
+	items.push({
+	    xtype: 'pmxRoleSelector',
+	    name: 'roles',
+	    value: 'NoAccess',
+	    fieldLabel: gettext('Role'),
+	});
+
+	items.push({
+	    xtype: 'proxmoxintegerfield',
+	    name: 'vlan',
+	    minValue: 1,
+	    maxValue: 4096,
+            allowBlank: true,
+	    fieldLabel: 'Vlan',
+	    emptyText: gettext('All'),
+	});
+
+	let ipanel = Ext.create('Proxmox.panel.InputPanel', {
+	    items: items,
+	    onlineHelp: 'pveum_permission_management',
+	    onGetValues: function(values) {
+		if (values.vlan) {
+		    values.path = values.path + "/" + values.vlan;
+		    delete values.vlan;
+		}
+		return values;
+	    },
+	});
+
+	Ext.apply(me, {
+	    items: [ipanel],
+	});
+
+	me.callParent();
+    },
+});
+
+Ext.define('PVE.sdn.VnetACLView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveSDNVnetACLView'],
+
+    onlineHelp: 'chapter_user_management',
+
+    stateful: true,
+    stateId: 'grid-acls',
+
+    // use fixed path
+    path: undefined,
+
+    setPath: function(path) {
+        let me = this;
+
+        me.path = path;
+
+        if (path === undefined) {
+	    me.down('#groupmenu').setDisabled(true);
+	    me.down('#usermenu').setDisabled(true);
+	    me.down('#tokenmenu').setDisabled(true);
+        } else {
+	    me.down('#groupmenu').setDisabled(false);
+	    me.down('#usermenu').setDisabled(false);
+	    me.down('#tokenmenu').setDisabled(false);
+            me.store.load();
+        }
+    },
+    initComponent: function() {
+	let me = this;
+
+	let store = Ext.create('Ext.data.Store', {
+	    model: 'pve-acl',
+	    proxy: {
+                type: 'proxmox',
+		url: "/api2/json/access/acl",
+	    },
+	    sorters: {
+		property: 'path',
+		direction: 'ASC',
+	    },
+	});
+
+	store.addFilter(Ext.create('Ext.util.Filter', {
+	    filterFn: item => item.data.path.replace(/(\/sdn\/zones\/(.*)\/(.*))\/[0-9]*$/, '$1') === me.path,
+	}));
+
+	let render_ugid = function(ugid, metaData, record) {
+	    if (record.data.type === 'group') {
+		return '@' + ugid;
+	    }
+
+	    return Ext.String.htmlEncode(ugid);
+	};
+
+	let render_vlan = function(path, metaData, record) {
+	    let vlan = 'any';
+	    const match = path.match(/(\/sdn\/zones\/)(.*)\/(.*)\/([0-9]*)$/);
+	    if (match) {
+		vlan = match[4];
+	    }
+
+	    return Ext.String.htmlEncode(vlan);
+	};
+
+	let columns = [
+	    {
+		header: gettext('User') + '/' + gettext('Group') + '/' + gettext('API Token'),
+		flex: 1,
+		sortable: true,
+		renderer: render_ugid,
+		dataIndex: 'ugid',
+	    },
+	    {
+		header: gettext('Role'),
+		flex: 1,
+		sortable: true,
+		dataIndex: 'roleid',
+	    },
+	    {
+		header: gettext('Vlan'),
+		flex: 1,
+		sortable: true,
+		renderer: render_vlan,
+		dataIndex: 'path',
+	    },
+	];
+
+
+	let sm = Ext.create('Ext.selection.RowModel', {});
+
+	let remove_btn = new Proxmox.button.Button({
+	    text: gettext('Remove'),
+	    disabled: true,
+	    selModel: sm,
+	    confirmMsg: gettext('Are you sure you want to remove this entry'),
+	    handler: function(btn, event, rec) {
+		var params = {
+		    'delete': 1,
+		    path: rec.data.path,
+		    roles: rec.data.roleid,
+		};
+		if (rec.data.type === 'group') {
+		    params.groups = rec.data.ugid;
+		} else if (rec.data.type === 'user') {
+		    params.users = rec.data.ugid;
+		} else if (rec.data.type === 'token') {
+		    params.tokens = rec.data.ugid;
+		} else {
+		    throw 'unknown data type';
+		}
+
+		Proxmox.Utils.API2Request({
+		    url: '/access/acl',
+		    params: params,
+		    method: 'PUT',
+		    waitMsgTarget: me,
+		    callback: () => store.load(),
+		    failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
+		});
+	    },
+	});
+
+	Proxmox.Utils.monStoreErrors(me, store);
+
+	Ext.apply(me, {
+	    store: store,
+	    selModel: sm,
+	    tbar: [
+		{
+		    text: gettext('Add'),
+		    menu: {
+			xtype: 'menu',
+			items: [
+			    {
+				text: gettext('Group Permission'),
+				disabled: !me.path,
+				itemId: 'groupmenu',
+				iconCls: 'fa fa-fw fa-group',
+				handler: function() {
+				    var win = Ext.create('PVE.sdn.VnetACLAdd', {
+					aclType: 'group',
+					path: me.path,
+				    });
+				    win.on('destroy', () => store.load());
+				    win.show();
+				},
+			    },
+			    {
+				text: gettext('User Permission'),
+				disabled: !me.path,
+				itemId: 'usermenu',
+				iconCls: 'fa fa-fw fa-user',
+				handler: function() {
+				    var win = Ext.create('PVE.sdn.VnetACLAdd', {
+					aclType: 'user',
+					path: me.path,
+				    });
+				    win.on('destroy', () => store.load());
+				    win.show();
+				},
+			    },
+			    {
+				text: gettext('API Token Permission'),
+				disabled: !me.path,
+				itemId: 'tokenmenu',
+				iconCls: 'fa fa-fw fa-user-o',
+				handler: function() {
+				    let win = Ext.create('PVE.sdn.VnetACLAdd', {
+					aclType: 'token',
+					path: me.path,
+				    });
+				    win.on('destroy', () => store.load());
+				    win.show();
+				},
+			    },
+			],
+		    },
+		},
+		remove_btn,
+	    ],
+	    viewConfig: {
+		trackOver: false,
+	    },
+	    columns: columns,
+	    listeners: {
+	    },
+	});
+
+	me.callParent();
+    },
+}, function() {
+    Ext.define('pve-acl-vnet', {
+	extend: 'Ext.data.Model',
+	fields: [
+	    'path', 'type', 'ugid', 'roleid',
+	    {
+		name: 'propagate',
+		type: 'boolean',
+	    },
+	],
+    });
+});
diff --git a/www/manager6/sdn/ZoneContentPanel.js b/www/manager6/sdn/ZoneContentPanel.js
new file mode 100644
index 00000000..5bb081bb
--- /dev/null
+++ b/www/manager6/sdn/ZoneContentPanel.js
@@ -0,0 +1,41 @@
+Ext.define('PVE.sdn.ZoneContentPanel', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveSDNZoneContentPanel',
+
+    title: 'Vnet',
+
+    onlineHelp: 'pvesdn_config_vnet',
+
+    initComponent: function() {
+	var me = this;
+
+	var permissions_panel = Ext.createWidget('pveSDNVnetACLView', {
+	    title: gettext('Vnet Permissions'),
+	    region: 'center',
+	    border: false,
+	});
+
+	var vnetview_panel = Ext.createWidget('pveSDNZoneContentView', {
+	    title: 'Vnets',
+	    region: 'west',
+	    permissions_panel: permissions_panel,
+	    nodename: me.nodename,
+	    zone: me.zone,
+	    width: '50%',
+	    border: false,
+	    split: true,
+	});
+
+	Ext.apply(me, {
+	    layout: 'border',
+	    items: [vnetview_panel, permissions_panel],
+	    listeners: {
+		show: function() {
+		    permissions_panel.fireEvent('show', permissions_panel);
+		},
+	    },
+	});
+
+	me.callParent();
+    },
+});
diff --git a/www/manager6/sdn/ZoneContentView.js b/www/manager6/sdn/ZoneContentView.js
index 1ea65450..4bc92718 100644
--- a/www/manager6/sdn/ZoneContentView.js
+++ b/www/manager6/sdn/ZoneContentView.js
@@ -17,17 +17,15 @@ Ext.define('PVE.sdn.ZoneContentView', {
     initComponent: function() {
 	var me = this;
 
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
+	if (!me.nodename) {
 	    throw "no node name specified";
 	}
 
-	var zone = me.pveSelNode.data.sdn;
-	if (!zone) {
+	if (!me.zone) {
 	    throw "no zone ID specified";
 	}
 
-	var baseurl = "/nodes/" + nodename + "/sdn/zones/" + zone + "/content";
+	var baseurl = "/nodes/" + me.nodename + "/sdn/zones/" + me.zone + "/content";
 	var store = Ext.create('Ext.data.Store', {
 	    model: 'pve-sdnzone-content',
 	    groupField: 'content',
@@ -48,7 +46,6 @@ Ext.define('PVE.sdn.ZoneContentView', {
 	};
 
 	Proxmox.Utils.monStoreErrors(me, store);
-
 	Ext.apply(me, {
 	    store: store,
 	    selModel: sm,
@@ -79,11 +76,19 @@ Ext.define('PVE.sdn.ZoneContentView', {
 		    dataIndex: 'statusmsg',
 		},
 	    ],
-	    listeners: {
-		activate: reload,
-	    },
+            listeners: {
+                activate: reload,
+                show: reload,
+                select: function(_sm, rec) {
+                    let path = `/sdn/zones/${me.zone}/${rec.data.vnet}`;
+                    me.permissions_panel.setPath(path);
+                },
+                deselect: function() {
+                    me.permissions_panel.setPath(undefined);
+                },
+            },
 	});
-
+	store.load();
 	me.callParent();
     },
 }, function() {
-- 
2.30.2




  parent reply	other threads:[~2023-06-06 13:20 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-06 13:19 [pve-devel] [PATCH-SERIE pve-access-control/pve-manager/pve-guest-common/qemu-server/pve-network] check permissions on local bridge Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH v2 pve-access-control 1/3] access control: add /sdn/zones/<zone>/<vnet>/<vlan> path Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH v3 qemu-server 1/1] api2: add check_bridge_access for create/update/clone vm Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH v3 pve-manager 1/4] api2: network: check permissions for local bridges Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH pve-network 1/1] get_local_vnets: fix permission path && perm Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH pve-guest-common 1/1] helpers : add check_vnet_access Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH v3 pve-manager 2/4] api2: cluster: ressources: add "localnetwork" zone Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH v2 pve-access-control 2/3] rpcenvironnment: add check_sdn_bridge Alexandre Derumier
2023-06-06 13:19 ` [pve-devel] [PATCH v2 pve-access-control 3/3] add new SDN.use privilege in PVESDNUser role Alexandre Derumier
2023-06-06 13:19 ` Alexandre Derumier [this message]
2023-06-06 13:19 ` [pve-devel] [PATCH v3 pve-manager 4/4] ui: add permissions management for "localnetwork" zone Alexandre Derumier
2023-06-07 12:03 [pve-devel] [PATCH-SERIE pve-access-control/pve-manager/pve-guest-common/qemu-server/pve-network] check permissions on local bridge Alexandre Derumier
2023-06-07 12:03 ` [pve-devel] [PATCH v3 pve-manager 3/4] ui: add vnet permissions panel Alexandre Derumier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230606131927.1667420-10-aderumier@odiso.com \
    --to=aderumier@odiso.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal