Skip to content

Commit d088964

Browse files
authored
Merge pull request #1364 from topcoder-platform/pm-2662_1
fix(PM-2662): hide other submitters submissions if challenge is configured to hide it
2 parents 985e16a + 195226c commit d088964

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

src/apps/review/src/lib/components/ChallengeDetailsContent/TabContentSubmissions.tsx

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ import {
2525
BackendSubmission,
2626
ChallengeDetailContextModel,
2727
convertBackendSubmissionToSubmissionInfo,
28+
ReviewAppContextModel,
2829
SubmissionInfo,
2930
} from '../../models'
3031
import { TableNoRecord } from '../TableNoRecord'
3132
import { TableWrapper } from '../TableWrapper'
3233
import { SubmissionHistoryModal } from '../SubmissionHistoryModal'
3334
import { useSubmissionDownloadAccess } from '../../hooks/useSubmissionDownloadAccess'
3435
import type { UseSubmissionDownloadAccessResult } from '../../hooks/useSubmissionDownloadAccess'
35-
import { ChallengeDetailContext } from '../../contexts'
36+
import { ChallengeDetailContext, ReviewAppContext } from '../../contexts'
3637
import {
3738
challengeHasSubmissionLimit,
3839
getSubmissionHistoryKey,
@@ -42,6 +43,7 @@ import {
4243
import type { SubmissionHistoryPartition } from '../../utils'
4344
import { TABLE_DATE_FORMAT } from '../../../config/index.config'
4445
import { CollapsibleAiReviewsRow } from '../CollapsibleAiReviewsRow'
46+
import { useRolePermissions, UseRolePermissionsResult } from '../../hooks'
4547

4648
import styles from './TabContentSubmissions.module.scss'
4749

@@ -67,9 +69,36 @@ export const TabContentSubmissions: FC<Props> = props => {
6769
isSubmissionDownloadRestrictedForMember,
6870
getRestrictionMessageForMember,
6971
}: UseSubmissionDownloadAccessResult = useSubmissionDownloadAccess()
72+
const { loginUserInfo }: ReviewAppContextModel = useContext(ReviewAppContext)
73+
const { canViewAllSubmissions }: UseRolePermissionsResult = useRolePermissions()
7074

7175
const { challengeInfo }: ChallengeDetailContextModel = useContext(ChallengeDetailContext)
7276

77+
const isCompletedDesignChallenge = useMemo(() => {
78+
if (!challengeInfo) return false
79+
const type = challengeInfo.track.name ? String(challengeInfo.track.name)
80+
.toLowerCase() : ''
81+
const status = challengeInfo.status ? String(challengeInfo.status)
82+
.toLowerCase() : ''
83+
return type === 'design' && (
84+
status === 'completed'
85+
)
86+
}, [challengeInfo])
87+
88+
const isSubmissionsViewable = useMemo(() => {
89+
if (!challengeInfo?.metadata?.length) return false
90+
return challengeInfo.metadata.some(m => m.name === 'submissionsViewable' && String(m.value)
91+
.toLowerCase() === 'true')
92+
}, [challengeInfo])
93+
94+
const canViewSubmissions = useMemo(() => {
95+
if (isCompletedDesignChallenge) {
96+
return canViewAllSubmissions || isSubmissionsViewable
97+
}
98+
99+
return true
100+
}, [isCompletedDesignChallenge, isSubmissionsViewable, canViewAllSubmissions])
101+
73102
const submissionMetaById = useMemo(
74103
() => {
75104
const map = new Map<string, BackendSubmission>()
@@ -205,19 +234,32 @@ export const TabContentSubmissions: FC<Props> = props => {
205234

206235
const filteredSubmissions = useMemo<BackendSubmission[]>(
207236
() => {
237+
238+
const filterFunc = (submissions: BackendSubmission[]): BackendSubmission[] => submissions
239+
.filter(submission => {
240+
if (!canViewSubmissions) {
241+
return String(submission.memberId) === String(loginUserInfo?.userId)
242+
}
243+
244+
return true
245+
})
246+
const filteredByUserId = filterFunc(latestBackendSubmissions)
247+
const filteredByUserIdSubmissions = filterFunc(props.submissions)
208248
if (restrictToLatest && hasLatestFlag) {
209249
return latestBackendSubmissions.length
210-
? latestBackendSubmissions
211-
: props.submissions
250+
? filteredByUserId
251+
: filteredByUserIdSubmissions
212252
}
213253

214-
return props.submissions
254+
return filteredByUserIdSubmissions
215255
},
216256
[
217257
latestBackendSubmissions,
218258
props.submissions,
219259
restrictToLatest,
220260
hasLatestFlag,
261+
canViewSubmissions,
262+
loginUserInfo?.userId,
221263
],
222264
)
223265

src/apps/review/src/lib/hooks/useRole.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface useRoleProps {
2424
hasReviewerRole: boolean
2525
hasApproverRole: boolean
2626
hasPostMortemReviewerRole: boolean
27+
hasManagerRole: boolean
2728
checkpointScreenerResourceIds: Set<string>
2829
checkpointReviewerResourceIds: Set<string>
2930
copilotReviewerResourceIds: Set<string>
@@ -119,6 +120,18 @@ const useRole = (): useRoleProps => {
119120
[myResources],
120121
)
121122

123+
const pmResourceIds = useMemo<Set<string>>(
124+
() => new Set(
125+
(myResources ?? [])
126+
.filter(resource => {
127+
const roleName = resource.roleName?.toLowerCase() ?? ''
128+
return roleName.includes('manager')
129+
})
130+
.map(resource => resource.id),
131+
),
132+
[myResources],
133+
)
134+
122135
const screenerResourceIds = useMemo<Set<string>>(
123136
() => new Set(
124137
(myResources ?? [])
@@ -201,6 +214,11 @@ const useRole = (): useRoleProps => {
201214
[screenerResourceIds],
202215
)
203216

217+
const hasManagerRole = useMemo(
218+
() => pmResourceIds.size > 0,
219+
[pmResourceIds],
220+
)
221+
204222
const hasReviewerRole = useMemo(
205223
() => reviewerResourceIds.size > 0,
206224
[reviewerResourceIds],
@@ -235,6 +253,7 @@ const useRole = (): useRoleProps => {
235253
hasApproverRole,
236254
hasCheckpointReviewerRole,
237255
hasCheckpointScreenerRole,
256+
hasManagerRole,
238257
hasPostMortemReviewerRole,
239258
hasReviewerRole,
240259
hasScreenerRole,

src/apps/review/src/lib/hooks/useRolePermissions.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ import { useRole } from './useRole'
1818
export interface UseRolePermissionsResult {
1919
actionChallengeRole: ChallengeRole
2020
canManageCompletedReviews: boolean
21+
canViewAllSubmissions: boolean
2122
hasCopilotRole: boolean
2223
hasReviewerRole: boolean
2324
hasSubmitterRole: boolean
2425
isAdmin: boolean
26+
isProjectManager: boolean
2527
isCopilotWithReviewerAssignments: boolean
2628
ownedMemberIds: Set<string>
2729
}
@@ -38,6 +40,9 @@ export function useRolePermissions(): UseRolePermissionsResult {
3840
const {
3941
actionChallengeRole,
4042
hasReviewerRole,
43+
hasApproverRole,
44+
hasScreenerRole,
45+
hasManagerRole,
4146
isCopilotWithReviewerAssignments,
4247
}: useRoleProps = useRole()
4348

@@ -56,6 +61,18 @@ export function useRolePermissions(): UseRolePermissionsResult {
5661
[normalizedRoles],
5762
)
5863

64+
const isProjectManager = useMemo<boolean>(
65+
() => (loginUserInfo?.roles?.some(
66+
role => typeof role === 'string'
67+
&& role.toLowerCase() === UserRole.projectManager,
68+
) ?? false)
69+
|| normalizedRoles.some(role => role.includes('project manager')),
70+
[
71+
loginUserInfo?.roles,
72+
normalizedRoles,
73+
],
74+
)
75+
5976
const isAdmin = useMemo<boolean>(
6077
() => (loginUserInfo?.roles?.some(
6178
role => typeof role === 'string'
@@ -82,14 +99,29 @@ export function useRolePermissions(): UseRolePermissionsResult {
8299
[hasCopilotRole, isAdmin],
83100
)
84101

102+
const canViewAllSubmissions = useMemo<boolean>(
103+
() => (
104+
isAdmin
105+
|| hasCopilotRole
106+
|| hasReviewerRole
107+
|| hasManagerRole
108+
|| hasScreenerRole
109+
|| hasApproverRole
110+
|| isProjectManager
111+
),
112+
[hasCopilotRole, isAdmin, isProjectManager, hasReviewerRole, hasManagerRole, hasScreenerRole, hasApproverRole],
113+
)
114+
85115
return {
86116
actionChallengeRole,
87117
canManageCompletedReviews,
118+
canViewAllSubmissions,
88119
hasCopilotRole,
89120
hasReviewerRole,
90121
hasSubmitterRole,
91122
isAdmin,
92123
isCopilotWithReviewerAssignments,
124+
isProjectManager,
93125
ownedMemberIds,
94126
}
95127
}

0 commit comments

Comments
 (0)