Skip to content

Commit d2ff590

Browse files
authored
fix: hide New user button if no permission (#1794)
1 parent e1b0cb0 commit d2ff590

File tree

5 files changed

+52
-7
lines changed

5 files changed

+52
-7
lines changed

site/src/pages/UsersPage/UsersPage.test.tsx

+30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { fireEvent, screen, waitFor, within } from "@testing-library/react"
2+
import { rest } from "msw"
23
import React from "react"
34
import * as API from "../../api/api"
45
import { Role } from "../../api/typesGenerated"
@@ -7,8 +8,11 @@ import { Language as ResetPasswordDialogLanguage } from "../../components/ResetP
78
import { Language as RoleSelectLanguage } from "../../components/RoleSelect/RoleSelect"
89
import { Language as UsersTableLanguage } from "../../components/UsersTable/UsersTable"
910
import { MockAuditorRole, MockUser, MockUser2, render } from "../../testHelpers/renderHelpers"
11+
import { server } from "../../testHelpers/server"
12+
import { permissionsToCheck } from "../../xServices/auth/authXService"
1013
import { Language as usersXServiceLanguage } from "../../xServices/users/usersXService"
1114
import { Language as UsersPageLanguage, UsersPage } from "./UsersPage"
15+
import { Language as UsersViewLanguage } from "./UsersPageView"
1216

1317
const suspendUser = async (setupActionSpies: () => void) => {
1418
// Get the first user in the table
@@ -99,6 +103,32 @@ describe("Users Page", () => {
99103
expect(users.length).toEqual(2)
100104
})
101105

106+
it("shows 'New user' button to an authorized user", () => {
107+
render(<UsersPage />)
108+
const newUserButton = screen.queryByText(UsersViewLanguage.newUserButton)
109+
expect(newUserButton).toBeDefined()
110+
})
111+
112+
it("does not show 'New user' button to unauthorized user", () => {
113+
server.use(
114+
rest.post("/api/v2/users/:userId/authorization", async (req, res, ctx) => {
115+
const permissions = Object.keys(permissionsToCheck)
116+
const response = permissions.reduce((obj, permission) => {
117+
return {
118+
...obj,
119+
[permission]: true,
120+
createUser: false,
121+
}
122+
}, {})
123+
124+
return res(ctx.status(200), ctx.json(response))
125+
}),
126+
)
127+
render(<UsersPage />)
128+
const newUserButton = screen.queryByText(UsersViewLanguage.newUserButton)
129+
expect(newUserButton).toBeNull()
130+
})
131+
102132
describe("suspend user", () => {
103133
describe("when it is success", () => {
104134
it("shows a success message and refresh the page", async () => {

site/src/pages/UsersPage/UsersPage.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const UsersPage: React.FC = () => {
2323
const userToResetPassword = users?.find((u) => u.id === userIdToResetPassword)
2424
const permissions = useSelector(xServices.authXService, selectPermissions)
2525
const canEditUsers = permissions && permissions.updateUsers
26+
const canCreateUser = permissions && permissions.createUser
2627
const { roles } = rolesState.context
2728
// Is loading if
2829
// - permissions are not loaded or
@@ -70,6 +71,7 @@ export const UsersPage: React.FC = () => {
7071
isUpdatingUserRoles={usersState.matches("updatingUserRoles")}
7172
isLoading={isLoading}
7273
canEditUsers={canEditUsers}
74+
canCreateUser={canCreateUser}
7375
/>
7476

7577
<ConfirmDialog

site/src/pages/UsersPage/UsersPageView.stories.tsx

+9-6
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ export default {
1010

1111
const Template: Story<UsersPageViewProps> = (args) => <UsersPageView {...args} />
1212

13-
export const Ready = Template.bind({})
14-
Ready.args = {
13+
export const Admin = Template.bind({})
14+
Admin.args = {
1515
users: [MockUser, MockUser2],
1616
roles: MockSiteRoles,
17+
canCreateUser: true,
18+
canEditUsers: true,
1719
}
20+
21+
export const Member = Template.bind({})
22+
Member.args = { ...Admin.args, canCreateUser: false, canEditUsers: false }
23+
1824
export const Empty = Template.bind({})
19-
Empty.args = {
20-
users: [],
21-
roles: MockSiteRoles,
22-
}
25+
Empty.args = { ...Admin.args, users: [] }

site/src/pages/UsersPage/UsersPageView.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface UsersPageViewProps {
1717
error?: unknown
1818
isUpdatingUserRoles?: boolean
1919
canEditUsers?: boolean
20+
canCreateUser?: boolean
2021
isLoading?: boolean
2122
openUserCreationDialog: () => void
2223
onSuspendUser: (user: TypesGen.User) => void
@@ -34,11 +35,13 @@ export const UsersPageView: React.FC<UsersPageViewProps> = ({
3435
error,
3536
isUpdatingUserRoles,
3637
canEditUsers,
38+
canCreateUser,
3739
isLoading,
3840
}) => {
41+
const newUserAction = canCreateUser ? { text: Language.newUserButton, onClick: openUserCreationDialog } : undefined
3942
return (
4043
<Stack spacing={4}>
41-
<Header title={Language.pageTitle} action={{ text: Language.newUserButton, onClick: openUserCreationDialog }} />
44+
<Header title={Language.pageTitle} action={newUserAction} />
4245
<Margins>
4346
{error ? (
4447
<ErrorSummary error={error} />

site/src/xServices/auth/authXService.ts

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const Language = {
1212
export const checks = {
1313
readAllUsers: "readAllUsers",
1414
updateUsers: "updateUsers",
15+
createUser: "createUser",
1516
createTemplates: "createTemplates",
1617
} as const
1718

@@ -28,6 +29,12 @@ export const permissionsToCheck = {
2829
},
2930
action: "update",
3031
},
32+
[checks.createUser]: {
33+
object: {
34+
resource_type: "user",
35+
},
36+
action: "create",
37+
},
3138
[checks.createTemplates]: {
3239
object: {
3340
resource_type: "template",

0 commit comments

Comments
 (0)