Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfc21e15

Browse files
authored
fix(UI): redirect if user is not permissioned to see workspace (#6786)
* fix(UI): redirect if user is not permissioned to see workspace* fix tests
1 parent08afe3c commitfc21e15

File tree

5 files changed

+125
-60
lines changed

5 files changed

+125
-60
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import{useQuery}from"@tanstack/react-query"
2+
import{checkAuthorization}from"api/api"
3+
4+
exportconstuseReadPagePermissions=(
5+
resource_type:string,
6+
resource_id?:string,
7+
enabled=true,
8+
)=>{
9+
constqueryKey=["readPagePermissions",resource_type,resource_id]
10+
constparams={
11+
checks:{
12+
readPagePermissions:{
13+
object:{
14+
resource_type,
15+
resource_id,
16+
},
17+
action:"read",
18+
},
19+
},
20+
}
21+
22+
returnuseQuery({
23+
queryKey,
24+
queryFn:()=>checkAuthorization(params),
25+
enabled,
26+
})
27+
}

‎site/src/pages/AuditPage/AuditPage.test.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ describe("AuditPage", () => {
4848
constmock=jest.spyOn(CreateDayString,"createDayString")
4949
mock.mockImplementation(()=>"a minute ago")
5050

51+
jest.spyOn(API,"checkAuthorization").mockResolvedValue({
52+
readPagePermissions:true,
53+
})
54+
5155
// Mock the entitlements
5256
server.use(
5357
rest.get("/api/v2/entitlements",(req,res,ctx)=>{

‎site/src/pages/AuditPage/AuditPage.tsx

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@ import { pageTitle } from "util/page"
1111
import{auditMachine}from"xServices/audit/auditXService"
1212
import{PaginationMachineRef}from"xServices/pagination/paginationXService"
1313
import{AuditPageView}from"./AuditPageView"
14+
import{RequirePermission}from"components/RequirePermission/RequirePermission"
15+
import{useReadPagePermissions}from"hooks/useReadPagePermissions"
16+
import{Loader}from"components/Loader/Loader"
1417

1518
constAuditPage:FC=()=>{
19+
// we call the below hook to make sure the user has access to view the page
20+
const{data:permissions,isLoading:isLoadingPermissions}=
21+
useReadPagePermissions("audit_log")
22+
1623
const[searchParams,setSearchParams]=useSearchParams()
1724
constfilter=searchParams.get("filter")??""
1825
const[auditState,auditSend]=useMachine(auditMachine,{
@@ -28,26 +35,34 @@ const AuditPage: FC = () => {
2835

2936
const{ auditLogs, count, apiError}=auditState.context
3037
constpaginationRef=auditState.context.paginationRefasPaginationMachineRef
31-
const{audit_log:isAuditLogVisible}=useFeatureVisibility()
38+
const{audit_log:isAuditLogEnabled}=useFeatureVisibility()
39+
40+
if(!permissions||isLoadingPermissions){
41+
return<Loader/>
42+
}
3243

3344
return(
34-
<>
35-
<Helmet>
36-
<title>{pageTitle("Audit")}</title>
37-
</Helmet>
38-
<AuditPageView
39-
filter={filter}
40-
auditLogs={auditLogs}
41-
count={count}
42-
onFilter={(filter)=>{
43-
auditSend("FILTER",{ filter})
44-
}}
45-
paginationRef={paginationRef}
46-
isNonInitialPage={nonInitialPage(searchParams)}
47-
isAuditLogVisible={isAuditLogVisible}
48-
error={apiError}
49-
/>
50-
</>
45+
<RequirePermission
46+
isFeatureVisible={isAuditLogEnabled&&permissions.readPagePermissions}
47+
>
48+
<>
49+
<Helmet>
50+
<title>{pageTitle("Audit")}</title>
51+
</Helmet>
52+
<AuditPageView
53+
filter={filter}
54+
auditLogs={auditLogs}
55+
count={count}
56+
onFilter={(filter)=>{
57+
auditSend("FILTER",{ filter})
58+
}}
59+
paginationRef={paginationRef}
60+
isNonInitialPage={nonInitialPage(searchParams)}
61+
isAuditLogVisible={isAuditLogEnabled}
62+
error={apiError}
63+
/>
64+
</>
65+
</RequirePermission>
5166
)
5267
}
5368

‎site/src/pages/WorkspacePage/WorkspacePage.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const { t } = i18next
3131

3232
// It renders the workspace page and waits for it be loaded
3333
constrenderWorkspacePage=async()=>{
34+
jest.spyOn(api,"checkAuthorization").mockResolvedValue({
35+
readPagePermissions:true,
36+
})
3437
jest.spyOn(api,"getTemplate").mockResolvedValueOnce(MockTemplate)
3538
jest.spyOn(api,"getTemplateVersionRichParameters").mockResolvedValueOnce([])
3639
renderWithAuth(<WorkspacePage/>,{
@@ -191,6 +194,9 @@ describe("WorkspacePage", () => {
191194
it("updates the parameters when they are missing during update",async()=>{
192195
// Setup mocks
193196
constuser=userEvent.setup()
197+
jest.spyOn(api,"checkAuthorization").mockResolvedValue({
198+
readPagePermissions:true,
199+
})
194200
jest
195201
.spyOn(api,"getWorkspaceByOwnerAndName")
196202
.mockResolvedValueOnce(MockOutdatedWorkspace)

‎site/src/pages/WorkspacePage/WorkspacePage.tsx

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import { Loader } from "components/Loader/Loader"
66
import{FC,useEffect}from"react"
77
import{useParams}from"react-router-dom"
88
import{firstOrItem}from"util/array"
9-
import{quotaMachine}from"xServices/quotas/quotasXService"
109
import{workspaceMachine}from"xServices/workspace/workspaceXService"
1110
import{WorkspaceReadyPage}from"./WorkspaceReadyPage"
11+
import{quotaMachine}from"xServices/quotas/quotasXService"
12+
import{RequirePermission}from"components/RequirePermission/RequirePermission"
13+
import{useReadPagePermissions}from"hooks/useReadPagePermissions"
1214

1315
exportconstWorkspacePage:FC=()=>{
16+
conststyles=useStyles()
1417
const{username:usernameQueryParam,workspace:workspaceQueryParam}=
1518
useParams()
1619
constusername=firstOrItem(usernameQueryParam,null)
@@ -23,9 +26,13 @@ export const WorkspacePage: FC = () => {
2326
getTemplateParametersWarning,
2427
checkPermissionsError,
2528
}=workspaceState.context
29+
30+
// we call the below hook to make sure the user has access to view the page
31+
const{data:permissions,isLoading:isLoadingPermissions}=
32+
useReadPagePermissions("workspace",workspace?.id)
33+
2634
const[quotaState,quotaSend]=useMachine(quotaMachine)
2735
const{ getQuotaError}=quotaState.context
28-
conststyles=useStyles()
2936

3037
/**
3138
* Get workspace, template, and organization on mount and whenever workspaceId changes.
@@ -41,47 +48,53 @@ export const WorkspacePage: FC = () => {
4148
username&&quotaSend({type:"GET_QUOTA", username})
4249
},[username,quotaSend])
4350

51+
if(!permissions||isLoadingPermissions){
52+
return<Loader/>
53+
}
54+
4455
return(
45-
<ChooseOne>
46-
<Condcondition={workspaceState.matches("error")}>
47-
<divclassName={styles.error}>
48-
{Boolean(getWorkspaceError)&&(
49-
<AlertBannerseverity="error"error={getWorkspaceError}/>
50-
)}
51-
{Boolean(getTemplateWarning)&&(
52-
<AlertBannerseverity="error"error={getTemplateWarning}/>
53-
)}
54-
{Boolean(getTemplateParametersWarning)&&(
55-
<AlertBanner
56-
severity="error"
57-
error={getTemplateParametersWarning}
58-
/>
59-
)}
60-
{Boolean(checkPermissionsError)&&(
61-
<AlertBannerseverity="error"error={checkPermissionsError}/>
62-
)}
63-
{Boolean(getQuotaError)&&(
64-
<AlertBannerseverity="error"error={getQuotaError}/>
65-
)}
66-
</div>
67-
</Cond>
68-
<Cond
69-
condition={
70-
Boolean(workspace)&&
71-
workspaceState.matches("ready")&&
72-
quotaState.matches("success")
73-
}
74-
>
75-
<WorkspaceReadyPage
76-
workspaceState={workspaceState}
77-
quotaState={quotaState}
78-
workspaceSend={workspaceSend}
79-
/>
80-
</Cond>
81-
<Cond>
82-
<Loader/>
83-
</Cond>
84-
</ChooseOne>
56+
<RequirePermissionisFeatureVisible={permissions.readPagePermissions}>
57+
<ChooseOne>
58+
<Condcondition={workspaceState.matches("error")}>
59+
<divclassName={styles.error}>
60+
{Boolean(getWorkspaceError)&&(
61+
<AlertBannerseverity="error"error={getWorkspaceError}/>
62+
)}
63+
{Boolean(getTemplateWarning)&&(
64+
<AlertBannerseverity="error"error={getTemplateWarning}/>
65+
)}
66+
{Boolean(getTemplateParametersWarning)&&(
67+
<AlertBanner
68+
severity="error"
69+
error={getTemplateParametersWarning}
70+
/>
71+
)}
72+
{Boolean(checkPermissionsError)&&(
73+
<AlertBannerseverity="error"error={checkPermissionsError}/>
74+
)}
75+
{Boolean(getQuotaError)&&(
76+
<AlertBannerseverity="error"error={getQuotaError}/>
77+
)}
78+
</div>
79+
</Cond>
80+
<Cond
81+
condition={
82+
Boolean(workspace)&&
83+
workspaceState.matches("ready")&&
84+
quotaState.matches("success")
85+
}
86+
>
87+
<WorkspaceReadyPage
88+
workspaceState={workspaceState}
89+
quotaState={quotaState}
90+
workspaceSend={workspaceSend}
91+
/>
92+
</Cond>
93+
<Cond>
94+
<Loader/>
95+
</Cond>
96+
</ChooseOne>
97+
</RequirePermission>
8598
)
8699
}
87100

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp