Skip to content

Commit

Permalink
[feat] apply permission in panel (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
sijav authored May 17, 2024
1 parent 52eef0d commit d9cdf5b
Show file tree
Hide file tree
Showing 55 changed files with 1,438 additions and 1,152 deletions.
30 changes: 18 additions & 12 deletions src/containers/panel/PanelRoutes.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { lazy } from 'react'
import { Navigate, Route, Routes } from 'react-router-dom'
import { panelUI } from 'src/shared/constants'
import { AccountCheckGuard, BenchmarkCheckGuard, SubscriptionCheckGuard } from 'src/shared/layouts/panel-layout'
import { AccountCheckGuard, BenchmarkCheckGuard, PermissionCheckGuard, SubscriptionCheckGuard } from 'src/shared/layouts/panel-layout'

const SecurityPage = lazy(
() =>
Expand All @@ -19,11 +19,11 @@ const SetupCloudPage = lazy(
),
)

const AccountsPage = lazy(
const WorkspaceSettingsAccountsPage = lazy(
() =>
import(
/* webpackChunkName: "accounts" */
'src/pages/panel/accounts/AccountsPage'
'src/pages/panel/workspace-settings-accounts/WorkspaceSettingsAccountsPage'
),
)

Expand Down Expand Up @@ -91,18 +91,24 @@ export function PanelRoutes() {
<Route path="resource-detail/:resourceDetailId" element={<InventoryPage />} />
</Route>
</Route>
<Route path="workspace-settings">
<Route path="accounts" element={<AccountsPage />} />
<Route element={<PermissionCheckGuard permissionToCheck="readSettings" />}>
<Route path="workspace-settings">
<Route path="accounts" element={<WorkspaceSettingsAccountsPage />} />
</Route>
</Route>
</Route>
<Route path="user-settings" element={<UserSettingsPage />} />
<Route path="workspace-settings">
<Route index element={<WorkspaceSettingsPage />} />
<Route path="users" element={<WorkspaceSettingsUsersPage />} />
<Route path="billing-receipts" element={<WorkspaceSettingsBillingPage />} />
<Route path="external-directories" element={<WorkspaceSettingsExternalDirectoryPage />} />
<Route path="accounts">
<Route path="setup-cloud" element={<SetupCloudPage />} />
<Route element={<PermissionCheckGuard permissionToCheck="readSettings" />}>
<Route path="workspace-settings">
<Route index element={<WorkspaceSettingsPage />} />
<Route path="users" element={<WorkspaceSettingsUsersPage />} />
<Route element={<PermissionCheckGuard permissionToCheck="readBilling" />}>
<Route path="billing-receipts" element={<WorkspaceSettingsBillingPage />} />
</Route>
<Route path="external-directories" element={<WorkspaceSettingsExternalDirectoryPage />} />
<Route path="accounts">
<Route path="setup-cloud" element={<SetupCloudPage />} />
</Route>
</Route>
</Route>
<Route path="*" element={<Navigate to={panelUI.homePage} replace />} />
Expand Down
30 changes: 22 additions & 8 deletions src/core/auth/AuthGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { GetWorkspaceResponse } from 'src/shared/types/server'
import { axiosWithAuth, defaultAxiosConfig, setAxiosWithAuth } from 'src/shared/utils/axios'
import { clearAllCookies, isAuthenticated as isCookieAuthenticated } from 'src/shared/utils/cookie'
import { jsonToStr } from 'src/shared/utils/jsonToStr'
import { getAuthData, setAuthData } from 'src/shared/utils/localstorage'
import { getAuthData as getPersistedAuthData, setAuthData as setPersistedAuthData } from 'src/shared/utils/localstorage'
import { TrackJS } from 'trackjs'
import { UserContext, UserContextRealValues } from './UserContext'
import { UserContext, UserContextRealValues, UserContextValue } from './UserContext'
import { getCurrentUserQuery } from './getCurrentUser.query'
import { getPermissions, maxPermissionNumber } from './getPermissions'
import { Permissions, getPermissions, maxPermissionNumber } from './getPermissions'
import { getWorkspacesQuery } from './getWorkspaces.query'
import { logoutMutation } from './logout.mutation'

Expand All @@ -21,7 +21,7 @@ export function AuthGuard({ children }: PropsWithChildren) {
const [auth, setAuth] = useState<UserContextRealValues>(() => {
const isAuthenticated = isCookieAuthenticated()
const selectedWorkspaceId = isAuthenticated
? window.location.hash?.substring(1) || getAuthData()?.selectedWorkspaceId || undefined
? window.location.hash?.substring(1) || getPersistedAuthData()?.selectedWorkspaceId || undefined
: undefined
return {
...defaultAuth,
Expand All @@ -47,9 +47,9 @@ export function AuthGuard({ children }: PropsWithChildren) {
const handleInternalSetAuth = useCallback((value: SetStateAction<UserContextRealValues>) => {
setAuth((prev) => {
const newAuth = typeof value === 'function' ? value(prev) : value
setAuthData({
setPersistedAuthData({
isAuthenticated: newAuth.isAuthenticated,
selectedWorkspaceId: newAuth.selectedWorkspace?.id,
selectedWorkspaceId: newAuth.selectedWorkspace?.id ?? prev.selectedWorkspace?.id,
})
return newAuth
})
Expand Down Expand Up @@ -148,7 +148,7 @@ export function AuthGuard({ children }: PropsWithChildren) {
}
const { message, name, stack = 'unknown' } = error ?? {}
const authorized = isCookieAuthenticated()
const workspaceId = getAuthData()?.selectedWorkspaceId || 'unknown'
const workspaceId = getPersistedAuthData()?.selectedWorkspaceId || 'unknown'
sendToGTM({
event: GTMEventNames.Error,
message: jsonToStr(message),
Expand All @@ -173,7 +173,7 @@ export function AuthGuard({ children }: PropsWithChildren) {
const { response, name, message, cause, status, stack, config, code } = error
const request = error.request as unknown
const authorized = isCookieAuthenticated()
const workspaceId = getAuthData()?.selectedWorkspaceId || 'unknown'
const workspaceId = getPersistedAuthData()?.selectedWorkspaceId || 'unknown'
sendToGTM({
event: GTMEventNames.NetworkError,
api: response?.config.url || 'unknown',
Expand Down Expand Up @@ -211,6 +211,18 @@ export function AuthGuard({ children }: PropsWithChildren) {
}
}, [auth, navigate])

const handleCheckPermission = useCallback(
(permission: Permissions) => {
return auth.selectedWorkspace?.permissions.includes(permission) ?? false
},
[auth.selectedWorkspace?.permissions],
)

const handleCheckPermissions = useCallback(
(...permission: Permissions[]) => permission.map((permission) => handleCheckPermission(permission)),
[handleCheckPermission],
)

return (
<UserContext.Provider
value={{
Expand All @@ -219,6 +231,8 @@ export function AuthGuard({ children }: PropsWithChildren) {
logout: handleLogout,
refreshWorkspaces: handleRefreshWorkspaces,
selectWorkspace: handleSelectWorkspaces,
checkPermission: handleCheckPermission,
checkPermissions: handleCheckPermissions as UserContextValue['checkPermissions'],
}}
>
{children}
Expand Down
4 changes: 4 additions & 0 deletions src/core/auth/UserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export interface UserContextValue extends Partial<UserContextRealValues> {
logout: (noWorkspace?: boolean) => Promise<void>
refreshWorkspaces: () => Promise<GetWorkspacesResponse | undefined>
selectWorkspace: (id: string) => Promise<GetWorkspaceResponse | undefined>
checkPermission: (permission: Permissions) => boolean
checkPermissions: <PermissionsToCheck extends Permissions[]>(
...permission: PermissionsToCheck
) => { [Key in keyof PermissionsToCheck]: boolean }
}

export const UserContext = createContext<UserContextValue | null>(null)
Loading

0 comments on commit d9cdf5b

Please sign in to comment.