diff --git a/site/src/hooks/useReadPagePermissions.ts b/site/src/hooks/useReadPagePermissions.ts new file mode 100644 index 0000000000000..b1b199cda214a --- /dev/null +++ b/site/src/hooks/useReadPagePermissions.ts @@ -0,0 +1,27 @@ +import { useQuery } from "@tanstack/react-query" +import { checkAuthorization } from "api/api" + +export const useReadPagePermissions = ( + resource_type: string, + resource_id?: string, + enabled = true, +) => { + const queryKey = ["readPagePermissions", resource_type, resource_id] + const params = { + checks: { + readPagePermissions: { + object: { + resource_type, + resource_id, + }, + action: "read", + }, + }, + } + + return useQuery({ + queryKey, + queryFn: () => checkAuthorization(params), + enabled, + }) +} diff --git a/site/src/pages/AuditPage/AuditPage.test.tsx b/site/src/pages/AuditPage/AuditPage.test.tsx index 3305243739e47..5883a0bfd1b8f 100644 --- a/site/src/pages/AuditPage/AuditPage.test.tsx +++ b/site/src/pages/AuditPage/AuditPage.test.tsx @@ -48,6 +48,10 @@ describe("AuditPage", () => { const mock = jest.spyOn(CreateDayString, "createDayString") mock.mockImplementation(() => "a minute ago") + jest.spyOn(API, "checkAuthorization").mockResolvedValue({ + readPagePermissions: true, + }) + // Mock the entitlements server.use( rest.get("/api/v2/entitlements", (req, res, ctx) => { diff --git a/site/src/pages/AuditPage/AuditPage.tsx b/site/src/pages/AuditPage/AuditPage.tsx index d06808cb630ca..b8c22addb4ec1 100644 --- a/site/src/pages/AuditPage/AuditPage.tsx +++ b/site/src/pages/AuditPage/AuditPage.tsx @@ -11,8 +11,15 @@ import { pageTitle } from "util/page" import { auditMachine } from "xServices/audit/auditXService" import { PaginationMachineRef } from "xServices/pagination/paginationXService" import { AuditPageView } from "./AuditPageView" +import { RequirePermission } from "components/RequirePermission/RequirePermission" +import { useReadPagePermissions } from "hooks/useReadPagePermissions" +import { Loader } from "components/Loader/Loader" const AuditPage: FC = () => { + // we call the below hook to make sure the user has access to view the page + const { data: permissions, isLoading: isLoadingPermissions } = + useReadPagePermissions("audit_log") + const [searchParams, setSearchParams] = useSearchParams() const filter = searchParams.get("filter") ?? "" const [auditState, auditSend] = useMachine(auditMachine, { @@ -28,26 +35,34 @@ const AuditPage: FC = () => { const { auditLogs, count, apiError } = auditState.context const paginationRef = auditState.context.paginationRef as PaginationMachineRef - const { audit_log: isAuditLogVisible } = useFeatureVisibility() + const { audit_log: isAuditLogEnabled } = useFeatureVisibility() + + if (!permissions || isLoadingPermissions) { + return + } return ( - <> - - {pageTitle("Audit")} - - { - auditSend("FILTER", { filter }) - }} - paginationRef={paginationRef} - isNonInitialPage={nonInitialPage(searchParams)} - isAuditLogVisible={isAuditLogVisible} - error={apiError} - /> - + + <> + + {pageTitle("Audit")} + + { + auditSend("FILTER", { filter }) + }} + paginationRef={paginationRef} + isNonInitialPage={nonInitialPage(searchParams)} + isAuditLogVisible={isAuditLogEnabled} + error={apiError} + /> + + ) } diff --git a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx index dbb2408be7cd6..4c6f7eba2bc57 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx @@ -31,6 +31,9 @@ const { t } = i18next // It renders the workspace page and waits for it be loaded const renderWorkspacePage = async () => { + jest.spyOn(api, "checkAuthorization").mockResolvedValue({ + readPagePermissions: true, + }) jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate) jest.spyOn(api, "getTemplateVersionRichParameters").mockResolvedValueOnce([]) renderWithAuth(, { @@ -191,6 +194,9 @@ describe("WorkspacePage", () => { it("updates the parameters when they are missing during update", async () => { // Setup mocks const user = userEvent.setup() + jest.spyOn(api, "checkAuthorization").mockResolvedValue({ + readPagePermissions: true, + }) jest .spyOn(api, "getWorkspaceByOwnerAndName") .mockResolvedValueOnce(MockOutdatedWorkspace) diff --git a/site/src/pages/WorkspacePage/WorkspacePage.tsx b/site/src/pages/WorkspacePage/WorkspacePage.tsx index c805e33c02cef..1352233bfe597 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.tsx @@ -6,11 +6,14 @@ import { Loader } from "components/Loader/Loader" import { FC, useEffect } from "react" import { useParams } from "react-router-dom" import { firstOrItem } from "util/array" -import { quotaMachine } from "xServices/quotas/quotasXService" import { workspaceMachine } from "xServices/workspace/workspaceXService" import { WorkspaceReadyPage } from "./WorkspaceReadyPage" +import { quotaMachine } from "xServices/quotas/quotasXService" +import { RequirePermission } from "components/RequirePermission/RequirePermission" +import { useReadPagePermissions } from "hooks/useReadPagePermissions" export const WorkspacePage: FC = () => { + const styles = useStyles() const { username: usernameQueryParam, workspace: workspaceQueryParam } = useParams() const username = firstOrItem(usernameQueryParam, null) @@ -23,9 +26,13 @@ export const WorkspacePage: FC = () => { getTemplateParametersWarning, checkPermissionsError, } = workspaceState.context + + // we call the below hook to make sure the user has access to view the page + const { data: permissions, isLoading: isLoadingPermissions } = + useReadPagePermissions("workspace", workspace?.id) + const [quotaState, quotaSend] = useMachine(quotaMachine) const { getQuotaError } = quotaState.context - const styles = useStyles() /** * Get workspace, template, and organization on mount and whenever workspaceId changes. @@ -41,47 +48,53 @@ export const WorkspacePage: FC = () => { username && quotaSend({ type: "GET_QUOTA", username }) }, [username, quotaSend]) + if (!permissions || isLoadingPermissions) { + return + } + return ( - - -
- {Boolean(getWorkspaceError) && ( - - )} - {Boolean(getTemplateWarning) && ( - - )} - {Boolean(getTemplateParametersWarning) && ( - - )} - {Boolean(checkPermissionsError) && ( - - )} - {Boolean(getQuotaError) && ( - - )} -
-
- - - - - - -
+ + + +
+ {Boolean(getWorkspaceError) && ( + + )} + {Boolean(getTemplateWarning) && ( + + )} + {Boolean(getTemplateParametersWarning) && ( + + )} + {Boolean(checkPermissionsError) && ( + + )} + {Boolean(getQuotaError) && ( + + )} +
+
+ + + + + + +
+
) }