Skip to content

feat: Add permissions for links #1407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update navbar to be displayed only if the user has permissions for it
  • Loading branch information
BrunoQuaresma committed May 13, 2022
commit d0ff321e07a7aaebdb07220b9ddd1c3d543d9e87
9 changes: 7 additions & 2 deletions site/src/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { useActor } from "@xstate/react"
import { useActor, useSelector } from "@xstate/react"
import React, { useContext } from "react"
import { selectPermissions } from "../../xServices/auth/authSelectors"
import { XServiceContext } from "../../xServices/StateContext"
import { NavbarView } from "../NavbarView/NavbarView"

export const Navbar: React.FC = () => {
const xServices = useContext(XServiceContext)
const [authState, authSend] = useActor(xServices.authXService)
const { me } = authState.context
const permissions = useSelector(xServices.authXService, selectPermissions)
// When we have more options in the admin dropdown we may want to check this
// for more permissions
const displayAdminDropdown = !!permissions?.readAllUsers
const onSignOut = () => authSend("SIGN_OUT")

return <NavbarView user={me} onSignOut={onSignOut} />
return <NavbarView user={me} onSignOut={onSignOut} displayAdminDropdown={displayAdminDropdown} />
}
22 changes: 20 additions & 2 deletions site/src/components/NavbarView/NavbarView.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,33 @@ const Template: Story<NavbarViewProps> = (args: NavbarViewProps) => <NavbarView

export const ForAdmin = Template.bind({})
ForAdmin.args = {
user: { id: "1", username: "Administrator", email: "admin@coder.com", created_at: "dawn" },
user: {
id: "1",
username: "Administrator",
email: "admin@coder.com",
created_at: "dawn",
status: "active",
organization_ids: [],
roles: [],
},
displayAdminDropdown: true,
onSignOut: () => {
return Promise.resolve()
},
}

export const ForMember = Template.bind({})
ForMember.args = {
user: { id: "1", username: "CathyCoder", email: "cathy@coder.com", created_at: "dawn" },
user: {
id: "1",
username: "CathyCoder",
email: "cathy@coder.com",
created_at: "dawn",
status: "active",
organization_ids: [],
roles: [],
},
displayAdminDropdown: false,
onSignOut: () => {
return Promise.resolve()
},
Expand Down
5 changes: 3 additions & 2 deletions site/src/components/NavbarView/NavbarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { UserDropdown } from "../UserDropdown/UsersDropdown"
export interface NavbarViewProps {
user?: TypesGen.User
onSignOut: () => void
displayAdminDropdown: boolean
}

export const NavbarView: React.FC<NavbarViewProps> = ({ user, onSignOut }) => {
export const NavbarView: React.FC<NavbarViewProps> = ({ user, onSignOut, displayAdminDropdown }) => {
const styles = useStyles()
return (
<nav className={styles.root}>
Expand All @@ -31,7 +32,7 @@ export const NavbarView: React.FC<NavbarViewProps> = ({ user, onSignOut }) => {
</ListItem>
</List>
<div className={styles.fullWidth} />
{user && user.email === "admin@coder.com" && <AdminDropdown />}
{displayAdminDropdown && <AdminDropdown />}
<div className={styles.fixed}>{user && <UserDropdown user={user} onSignOut={onSignOut} />}</div>
</nav>
)
Expand Down
8 changes: 7 additions & 1 deletion site/src/xServices/auth/authSelectors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { State } from "xstate"
import { AuthContext, AuthEvent } from "./authXService"

export const selectOrgId = (state: State<AuthContext, AuthEvent>): string | undefined => {
type AuthState = State<AuthContext, AuthEvent>

export const selectOrgId = (state: AuthState): string | undefined => {
return state.context.me?.organization_ids[0]
}

export const selectPermissions = (state: AuthState): AuthContext["permissions"] => {
return state.context.permissions
}
12 changes: 8 additions & 4 deletions site/src/xServices/auth/authXService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ export const Language = {
successProfileUpdate: "Updated preferences.",
}

const permissionsToCheck: Record<string, TypesGen.UserPermissionCheck> = {
const permissionsToCheck = {
readAllUsers: {
object: {
resource_type: "user",
},
action: "read",
},
}
} as const

type Permissions = Record<keyof typeof permissionsToCheck, boolean>

export interface AuthContext {
getUserError?: Error | unknown
Expand All @@ -23,7 +25,7 @@ export interface AuthContext {
updateProfileError?: Error | unknown
me?: TypesGen.User
methods?: TypesGen.AuthMethods
permissions?: TypesGen.UserPermissionCheckResponse
permissions?: Permissions
checkPermissionsError?: Error | unknown
}

Expand Down Expand Up @@ -286,7 +288,9 @@ export const authMachine =
updateProfileError: (_) => undefined,
}),
assignPermissions: assign({
permissions: (_, event) => event.data,
// Setting event.data as Permissions to be more stricted. So we know
// what permissions we asked for.
permissions: (_, event) => event.data as Permissions,
}),
assignGetPermissionsError: assign({
checkPermissionsError: (_, event) => event.data,
Expand Down