Skip to content

Commit 4216de9

Browse files
author
dushimsam
committed
feat(UI): added manage group-users page
Signed-off-by: dushimsam <[email protected]>
1 parent 615a373 commit 4216de9

File tree

11 files changed

+445
-3
lines changed

11 files changed

+445
-3
lines changed

src/Routes.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const UploadDelete = React.lazy(() => import("pages/Organize/Uploads/Delete"));
9292
const GroupCreate = React.lazy(() => import("pages/Admin/Group/Create"));
9393
const DeleteGroup = React.lazy(() => import("pages/Admin/Group/Delete"));
9494
const DeleteUser = React.lazy(() => import("pages/Admin/Users/Delete"));
95+
const ManageGroup = React.lazy(() => import("pages/Admin/Group/Manage"));
9596
const AddUser = React.lazy(() => import("pages/Admin/Users/Add"));
9697
const EditUser = React.lazy(() => import("pages/Admin/Users/Edit"));
9798
const AddLicense = React.lazy(() => import("pages/Admin/License/Create"));
@@ -287,6 +288,11 @@ const Routes = () => {
287288
path={routes.admin.group.create}
288289
component={GroupCreate}
289290
/>
291+
<AdminLayout
292+
exact
293+
path={routes.admin.group.manageGroup}
294+
component={ManageGroup}
295+
/>
290296
<AdminLayout
291297
exact
292298
path={routes.admin.group.delete}

src/api/groups.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@ export const createGroupApi = (name) => {
6464
});
6565
};
6666

67+
// Get all group members
68+
export const getAllGroupMembersApi = (groupId) => {
69+
const url = endpoints.admin.groups.getAllGroupMembers(groupId);
70+
return sendRequest({
71+
url,
72+
method: "GET",
73+
headers: {
74+
Authorization: getToken(),
75+
},
76+
});
77+
};
78+
79+
// Remove Group Member
80+
export const removeGroupMemberApi = (groupId, userId) => {
81+
const url = endpoints.admin.groups.removeGroupMember(groupId, userId);
82+
return sendRequest({
83+
url,
84+
method: "DELETE",
85+
headers: {
86+
Authorization: getToken(),
87+
},
88+
});
89+
};
6790
// Delete a group
6891
export const deleteGroupApi = (id) => {
6992
const url = endpoints.admin.groups.delete(id);
@@ -73,6 +96,21 @@ export const deleteGroupApi = (id) => {
7396
headers: {
7497
Authorization: getToken(),
7598
},
99+
});
100+
};
101+
102+
// Change user permission
103+
export const changeUserPermissionApi = (groupId, userId, permission) => {
104+
const url = endpoints.admin.groups.changeUserPermission(groupId, userId);
105+
return sendRequest({
106+
url,
107+
method: "PUT",
108+
headers: {
109+
Authorization: getToken(),
110+
},
111+
body: {
112+
perm: permission,
113+
},
76114
addGroupName: false,
77115
});
78116
};

src/api/groups.test.js

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515

1616
import sendRequest from "api/sendRequest";
1717
import endpoints from "constants/endpoints";
18-
import { createGroupApi, getAllGroupsApi } from "api/groups";
18+
import {
19+
changeUserPermissionApi,
20+
createGroupApi,
21+
getAllGroupMembersApi,
22+
getAllGroupsApi,
23+
removeGroupMemberApi,
24+
} from "api/groups";
1925
import { getToken } from "shared/authHelper";
2026

2127
jest.mock("api/sendRequest");
@@ -56,4 +62,63 @@ describe("groups", () => {
5662
})
5763
);
5864
});
65+
66+
test("removeGroupMemberApi", () => {
67+
const groupId = 2;
68+
const userId = 1;
69+
const url = endpoints.admin.groups.removeGroupMember(groupId, userId);
70+
sendRequest.mockImplementation(() => true);
71+
72+
expect(removeGroupMemberApi(groupId, userId)).toBe(sendRequest({}));
73+
expect(sendRequest).toHaveBeenCalledWith(
74+
expect.objectContaining({
75+
url,
76+
method: "DELETE",
77+
headers: {
78+
Authorization: getToken(),
79+
},
80+
})
81+
);
82+
});
83+
84+
test("getAllGroupMembersApi", () => {
85+
const groupId = 1;
86+
const url = endpoints.admin.groups.getAllGroupMembers(groupId);
87+
sendRequest.mockImplementation(() => true);
88+
89+
expect(getAllGroupMembersApi(groupId)).toBe(sendRequest({}));
90+
expect(sendRequest).toHaveBeenCalledWith(
91+
expect.objectContaining({
92+
url,
93+
method: "GET",
94+
headers: {
95+
Authorization: getToken(),
96+
},
97+
})
98+
);
99+
});
100+
101+
test("changeUserPermissionApi", () => {
102+
const groupId = 1;
103+
const userId = 1;
104+
const permission = 2;
105+
const url = endpoints.admin.groups.changeUserPermission(groupId, userId);
106+
sendRequest.mockImplementation(() => true);
107+
108+
expect(changeUserPermissionApi(groupId, userId, permission)).toBe(
109+
sendRequest({})
110+
);
111+
expect(sendRequest).toHaveBeenCalledWith(
112+
expect.objectContaining({
113+
url,
114+
method: "PUT",
115+
headers: {
116+
Authorization: getToken(),
117+
},
118+
body: {
119+
perm: permission,
120+
},
121+
})
122+
);
123+
});
59124
});
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright (C) 2022 Samuel Dushimimana ([email protected])
3+
4+
SPDX-License-Identifier: GPL-2.0
5+
6+
This program is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU General Public License
8+
version 2 as published by the Free Software Foundation.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License along
15+
with this program; if not, write to the Free Software Foundation, Inc.,
16+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
import React, { useEffect, useState } from "react";
20+
21+
import { InputContainer } from "components/Widgets";
22+
23+
// Required functions for calling APIs
24+
import { changeUserPermission, removeGroupMember } from "services/groups";
25+
26+
import PropTypes from "prop-types";
27+
28+
// Required constants
29+
import { userPermissions } from "constants/constants";
30+
31+
const ChangePermissionContainer = ({
32+
perm,
33+
setShowMessage,
34+
setMessage,
35+
currGroup,
36+
user,
37+
handleFetchGroupMembers,
38+
}) => {
39+
const [selectedPerm, setSelectedPerm] = useState(perm);
40+
41+
useEffect(() => {
42+
setSelectedPerm(perm);
43+
}, [perm]);
44+
45+
const handleSetNewPermission = async (newPerm) => {
46+
setSelectedPerm(newPerm);
47+
// eslint-disable-next-line no-console
48+
try {
49+
let res;
50+
if (parseInt(newPerm, 10) === -1) {
51+
// eslint-disable-next-line no-console
52+
console.log(`HERE ID ${newPerm}`);
53+
res = await removeGroupMember(currGroup, user.id);
54+
} else {
55+
res = await changeUserPermission(currGroup, user.id, newPerm);
56+
}
57+
58+
setShowMessage(true);
59+
setMessage({
60+
type: "success",
61+
text: res.message,
62+
});
63+
64+
handleFetchGroupMembers(currGroup);
65+
} catch (e) {
66+
setMessage({
67+
type: "danger",
68+
text: e.message,
69+
});
70+
} finally {
71+
setTimeout(() => {
72+
setShowMessage(false);
73+
}, [3000]);
74+
}
75+
};
76+
return (
77+
<tr>
78+
<td>{user.name}</td>
79+
<td>
80+
<InputContainer
81+
type="select"
82+
name="name"
83+
options={userPermissions}
84+
id="select-tag"
85+
value={selectedPerm}
86+
property="name"
87+
onChange={(e) => handleSetNewPermission(e.target.value)}
88+
/>
89+
</td>
90+
</tr>
91+
);
92+
};
93+
94+
ChangePermissionContainer.propTypes = {
95+
perm: PropTypes.number,
96+
setMessage: PropTypes.func,
97+
currGroup: PropTypes.number,
98+
user: PropTypes.node,
99+
handleFetchGroupMembers: PropTypes.func,
100+
setShowMessage: PropTypes.func,
101+
};
102+
103+
export default ChangePermissionContainer;

src/components/Header/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ const Header = () => {
258258
</NavDropdown.Item>
259259
<NavDropdown.Item
260260
as={Link}
261-
to={routes.admin.group.delete}
261+
to={routes.admin.group.manageGroup}
262262
>
263-
Delete Group
263+
Manage Group Users
264264
</NavDropdown.Item>
265265
</div>
266266
</DropdownButton>

src/components/Widgets/Input/index.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const InputContainer = ({
2626
id,
2727
className,
2828
onChange,
29+
defaultValue = null,
2930
children,
3031
checked = false,
3132
placeholder = null,
@@ -70,6 +71,7 @@ const InputContainer = ({
7071
className ? `mr-2 form-control ${className}` : `mr-2 form-control`
7172
}
7273
value={value}
74+
defaultValue={defaultValue}
7375
onChange={onChange}
7476
multiple={multiple && multiple}
7577
size={multiple ? "15" : ""}
@@ -125,6 +127,7 @@ InputContainer.propTypes = {
125127
onChange: PropTypes.func,
126128
checked: PropTypes.bool,
127129
disabled: PropTypes.bool,
130+
defaultValue: PropTypes.string,
128131
children: PropTypes.node,
129132
options: PropTypes.arrayOf(
130133
PropTypes.shape({

src/constants/constants.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,3 +356,23 @@ export const agents = {
356356
reso: "REUSE.Software Analysis (forces *Ojo License Analysis*)",
357357
heritage: "Software Heritage Analysis",
358358
};
359+
360+
// eslint-disable-next-line camelcase
361+
export const userPermissions = [
362+
{
363+
id: -1,
364+
name: "None",
365+
},
366+
{
367+
id: 0,
368+
name: "User",
369+
},
370+
{
371+
id: 1,
372+
name: "Admin",
373+
},
374+
{
375+
id: 2,
376+
name: "Advisor",
377+
},
378+
];

src/constants/endpoints.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ const endpoints = {
7878
getAll: () => `${apiUrl}/groups`,
7979
getAllDeletable: () => `${apiUrl}/groups/deletable`,
8080
delete: (groupId) => `${apiUrl}/groups/${groupId}`,
81+
getAllGroupMembers: (groupId) => `${apiUrl}/groups/${groupId}/members`,
82+
changeUserPermission: (groupId, userId) =>
83+
`${apiUrl}/groups/${groupId}/user/${userId}`,
84+
removeGroupMember: (groupId, userId) =>
85+
`${apiUrl}/groups/${groupId}/user/${userId}`,
8186
},
8287
},
8388
license: {

src/constants/routes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const routes = {
6767
group: {
6868
create: "/admin/group/create",
6969
delete: "/admin/group/delete",
70+
manageGroup: "/admin/group/manage",
7071
},
7172
users: {
7273
add: "/admin/users/add",

0 commit comments

Comments
 (0)