From 1548ee52e7c913bea0542ae6c8cd5e2600a2de65 Mon Sep 17 00:00:00 2001 From: "yuye@microsoft.com" Date: Tue, 25 Jun 2019 17:07:50 +0800 Subject: [PATCH 1/6] Add or remove user from a group. --- src/rest-server/src/config/v2/user.js | 9 ++++ src/rest-server/src/controllers/v2/group.js | 25 ++++++++++ src/rest-server/src/controllers/v2/user.js | 53 +++++++++++++++++++++ src/rest-server/src/routes/v2/group.js | 4 ++ src/rest-server/src/routes/v2/user.js | 6 +++ 5 files changed, 97 insertions(+) diff --git a/src/rest-server/src/config/v2/user.js b/src/rest-server/src/config/v2/user.js index 11094ecb6a..08d831ae64 100644 --- a/src/rest-server/src/config/v2/user.js +++ b/src/rest-server/src/config/v2/user.js @@ -49,6 +49,14 @@ const userAdminPermissionUpdateInputSchema = Joi.object().keys({ admin: Joi.boolean().required(), }); +// define the input schema for the 'add or remove group from grouplist' api +const addOrRemoveGroupInputSchema = Joi.object().keys({ + groupname: Joi.string() + .token() + .required(), +}); + + // define the input schema for the 'create user' api const userCreateInputSchema = Joi.object().keys({ username: Joi.string() @@ -79,4 +87,5 @@ module.exports = { userEmailUpdateInputSchema, userCreateInputSchema, userAdminPermissionUpdateInputSchema, + addOrRemoveGroupInputSchema, }; diff --git a/src/rest-server/src/controllers/v2/group.js b/src/rest-server/src/controllers/v2/group.js index 3042064d47..92c32446c8 100644 --- a/src/rest-server/src/controllers/v2/group.js +++ b/src/rest-server/src/controllers/v2/group.js @@ -18,6 +18,8 @@ // module dependencies const createError = require('@pai/utils/error'); const groupModel = require('@pai/models/v2/group'); +const userModel = require('@pai/models/v2/user'); +const authConfig = require('@pai/config/authn'); const getGroup = async (req, res, next) => { try { @@ -38,6 +40,28 @@ const getAllGroup = async (req, res, next) => { } }; +const getGroupUserList = async (req, res, next) => { + try { + if (!req.user.admin) { + next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allow to do this operation.`)); + } + const groupname = req.params.groupname; + const allUserInfoList = userModel.getAllUser(); + let userlist = []; + for (const userInfo of allUserInfoList) { + if (userInfo.grouplist.includes(groupname)) { + userlist.push({ + username: userInfo.username, + clusterAdmin: userInfo.grouplist.includes(authConfig.groupConfig.adminGroup.groupname), + }); + } + } + return res.status(200).json(userlist); + } catch (error) { + return next(createError.unknown(error)); + } +}; + const createGroup = async (req, res, next) => { try { const groupname = req.body.groupname; @@ -136,6 +160,7 @@ module.exports = { getGroup, getAllGroup, createGroup, + getGroupUserList, updateGroupExtension, updateGroupDescription, updateGroupExternalName, diff --git a/src/rest-server/src/controllers/v2/user.js b/src/rest-server/src/controllers/v2/user.js index 6520f0502d..25bdf4deb8 100644 --- a/src/rest-server/src/controllers/v2/user.js +++ b/src/rest-server/src/controllers/v2/user.js @@ -257,6 +257,57 @@ const updateUserGroupList = async (req, res, next) => { } }; +const addGroupIntoUserGrouplist = async (req, res, next) => { + try { + if (!req.user.admin) { + next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allow to do this operation.`)); + } + const username = req.params.username; + const groupname = req.body.groupname; + let userInfo = await userModel.getUser(username); + if (userInfo.grouplist.includes(authConfig.groupConfig.adminGroup.groupname)) { + return next(createError('Forbidden', 'ForbiddenUserError', 'Admin\'s grouplist cannot be updated.')); + } + if (!userInfo.grouplist.includes(groupname)) { + userInfo.grouplist.push(groupname); + } + userModel.updateUser(username, userInfo); + return res.status(201).json({ + message: `User ${username} is added into group ${groupname}`, + }); + } catch (error) { + if (error.status === 404) { + return next(createError('Not found', 'NoUserError', `User ${req.params.username} not found.`)); + } + return next(createError.unknown(error)); + } +}; + +const removeGroupIntoUserGrouplist = async (req, res, next) => { + try { + if (!req.user.admin) { + next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allow to do this operation.`)); + } + const username = req.params.username; + const groupname = req.body.groupname; + let userInfo = await userModel.getUser(username); + if (userInfo.grouplist.includes(authConfig.groupConfig.adminGroup.groupname)) { + return next(createError('Forbidden', 'ForbiddenUserError', 'Admin\'s grouplist cannot be updated.')); + } + if (userInfo.grouplist.includes(groupname)) { + userInfo.grouplist.splice(userInfo.grouplist.indexOf(groupname), 1); + }userModel.updateUser(username, userInfo); + return res.status(201).json({ + message: `User ${username} is removed from group ${groupname}`, + }); + } catch (error) { + if (error.status === 404) { + return next(createError('Not found', 'NoUserError', `User ${req.params.username} not found.`)); + } + return next(createError.unknown(error)); + } +}; + const updateUserPassword = async (req, res, next) => { try { const username = req.params.username; @@ -396,6 +447,8 @@ module.exports = { updateUserGroupList, updateUserEmail, updateUserAdminPermission, + addGroupIntoUserGrouplist, + removeGroupIntoUserGrouplist, deleteUser, updateUserPassword, createUser, diff --git a/src/rest-server/src/routes/v2/group.js b/src/rest-server/src/routes/v2/group.js index f6ba1ec693..a541775fb1 100644 --- a/src/rest-server/src/routes/v2/group.js +++ b/src/rest-server/src/routes/v2/group.js @@ -52,6 +52,10 @@ router.route('/update/:groupname/externalname') /** put /api/v2/group/update/:groupname/external' */ .put(token.check, param.validate(groupInputSchema.groupExternalNameUpdateInputSchema), groupController.updateGroupExternalName); +router.route('/get/:groupname/userlist') +/** get /api/v2/group/get/:groupname/userlist */ + .get(token.check, groupController.getGroupUserList); + module.exports = router; diff --git a/src/rest-server/src/routes/v2/user.js b/src/rest-server/src/routes/v2/user.js index c108ea93c9..679356582b 100644 --- a/src/rest-server/src/routes/v2/user.js +++ b/src/rest-server/src/routes/v2/user.js @@ -66,6 +66,12 @@ if (authnConfig.authnMethod === 'basic') { router.route('/:username/grouplist') .put(token.check, param.validate(userInputSchema.userGrouplistUpdateInputSchema), userController.updateUserGroupList); + + router.route('/:username/group') + .put(token.check, param.validate(userInputSchema.addOrRemoveGroupInputSchema), userController.addGroupIntoUserGrouplist); + + router.route('/:username/group') + .delete(token.check, param.validate(userInputSchema.addOrRemoveGroupInputSchema), userController.removeGroupIntoUserGrouplist); } router.use('/:username/jobs', jobRouter); From 64e762d5164e257778c6210debf45d3de52c6df1 Mon Sep 17 00:00:00 2001 From: "yuye@microsoft.com" Date: Tue, 25 Jun 2019 17:50:46 +0800 Subject: [PATCH 2/6] Add or remove user from a group. --- src/rest-server/src/controllers/v2/group.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rest-server/src/controllers/v2/group.js b/src/rest-server/src/controllers/v2/group.js index 92c32446c8..de6b1f1e3e 100644 --- a/src/rest-server/src/controllers/v2/group.js +++ b/src/rest-server/src/controllers/v2/group.js @@ -48,6 +48,8 @@ const getGroupUserList = async (req, res, next) => { const groupname = req.params.groupname; const allUserInfoList = userModel.getAllUser(); let userlist = []; + // eslint-disable-next-line no-console + console.log(allUserInfoList); for (const userInfo of allUserInfoList) { if (userInfo.grouplist.includes(groupname)) { userlist.push({ From b32a17157079dcf2d46186ce9cda2b7a942ee116 Mon Sep 17 00:00:00 2001 From: "yuye@microsoft.com" Date: Tue, 25 Jun 2019 18:00:50 +0800 Subject: [PATCH 3/6] Add or remove user from a group. --- src/rest-server/src/controllers/v2/group.js | 2 +- src/rest-server/src/controllers/v2/user.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rest-server/src/controllers/v2/group.js b/src/rest-server/src/controllers/v2/group.js index de6b1f1e3e..6577800295 100644 --- a/src/rest-server/src/controllers/v2/group.js +++ b/src/rest-server/src/controllers/v2/group.js @@ -46,7 +46,7 @@ const getGroupUserList = async (req, res, next) => { next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allow to do this operation.`)); } const groupname = req.params.groupname; - const allUserInfoList = userModel.getAllUser(); + const allUserInfoList = await userModel.getAllUser(); let userlist = []; // eslint-disable-next-line no-console console.log(allUserInfoList); diff --git a/src/rest-server/src/controllers/v2/user.js b/src/rest-server/src/controllers/v2/user.js index 25bdf4deb8..faee68c73b 100644 --- a/src/rest-server/src/controllers/v2/user.js +++ b/src/rest-server/src/controllers/v2/user.js @@ -271,7 +271,7 @@ const addGroupIntoUserGrouplist = async (req, res, next) => { if (!userInfo.grouplist.includes(groupname)) { userInfo.grouplist.push(groupname); } - userModel.updateUser(username, userInfo); + await userModel.updateUser(username, userInfo); return res.status(201).json({ message: `User ${username} is added into group ${groupname}`, }); @@ -296,7 +296,8 @@ const removeGroupIntoUserGrouplist = async (req, res, next) => { } if (userInfo.grouplist.includes(groupname)) { userInfo.grouplist.splice(userInfo.grouplist.indexOf(groupname), 1); - }userModel.updateUser(username, userInfo); + } + await userModel.updateUser(username, userInfo); return res.status(201).json({ message: `User ${username} is removed from group ${groupname}`, }); From db8987e4250242823dc743bfde1a6e5b10d306ac Mon Sep 17 00:00:00 2001 From: "yuye@microsoft.com" Date: Tue, 25 Jun 2019 18:08:09 +0800 Subject: [PATCH 4/6] Add or remove user from a group. --- src/rest-server/src/controllers/v2/group.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rest-server/src/controllers/v2/group.js b/src/rest-server/src/controllers/v2/group.js index 6577800295..75366c843a 100644 --- a/src/rest-server/src/controllers/v2/group.js +++ b/src/rest-server/src/controllers/v2/group.js @@ -48,8 +48,6 @@ const getGroupUserList = async (req, res, next) => { const groupname = req.params.groupname; const allUserInfoList = await userModel.getAllUser(); let userlist = []; - // eslint-disable-next-line no-console - console.log(allUserInfoList); for (const userInfo of allUserInfoList) { if (userInfo.grouplist.includes(groupname)) { userlist.push({ From 1bd5b527c308655b705a8733147b622670281a23 Mon Sep 17 00:00:00 2001 From: "yuye@microsoft.com" Date: Wed, 26 Jun 2019 10:37:47 +0800 Subject: [PATCH 5/6] Add or remove user from a group. --- src/webportal/src/app/home/home/virtual-cluster-list.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webportal/src/app/home/home/virtual-cluster-list.jsx b/src/webportal/src/app/home/home/virtual-cluster-list.jsx index 3342edd717..915070a377 100644 --- a/src/webportal/src/app/home/home/virtual-cluster-list.jsx +++ b/src/webportal/src/app/home/home/virtual-cluster-list.jsx @@ -112,7 +112,7 @@ VirtualClusterItem.propTypes = { }; const VirtualCluster = ({style, userInfo, virtualClusters}) => { - const vcNames = userInfo.virtualCluster.split(',').filter((name) => !isNil(virtualClusters[name])); + const vcNames = userInfo.virtualCluster.filter((name) => !isNil(virtualClusters[name])); const {spacing} = getTheme(); return ( From cf93ac032a667b452267a110cbbb0da4413e6d7f Mon Sep 17 00:00:00 2001 From: "yuye@microsoft.com" Date: Wed, 26 Jun 2019 10:50:34 +0800 Subject: [PATCH 6/6] Add or remove user from a group. --- src/webportal/src/app/vc/vc.component.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/webportal/src/app/vc/vc.component.js b/src/webportal/src/app/vc/vc.component.js index a7a644d938..e634d24228 100644 --- a/src/webportal/src/app/vc/vc.component.js +++ b/src/webportal/src/app/vc/vc.component.js @@ -171,10 +171,12 @@ const addGroup = () => { return false; } $.ajax({ - url: `${webportalConfig.restServerUri}/api/v2/user/create/${vcName}`, + url: `${webportalConfig.restServerUri}/api/v2/group/create`, data: JSON.stringify({ + 'groupname': vcName, 'description': `This group of the same name is created by creating a Virtual Cluster named ${vcName}`, 'externalName': ``, + 'extension': `{"groupType": "vc"}`, }), headers: { Authorization: `Bearer ${token}`,