Skip to content

Commit 0223926

Browse files
authored
Merge pull request #1317 from topcoder-platform/system-admin-fixes
System admin fixes
2 parents 85db582 + 85e124e commit 0223926

File tree

12 files changed

+279
-14
lines changed

12 files changed

+279
-14
lines changed

src/apps/admin/src/challenge-management/ManageSubmissionPage/ManageSubmissionPage.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
useManageBusEventProps,
1919
useManageChallengeSubmissions,
2020
useManageChallengeSubmissionsProps,
21+
useManageSubmissionReprocess,
22+
useManageSubmissionReprocessProps,
2123
} from '../../lib/hooks'
2224
import {
2325
ActionLoading,
@@ -26,7 +28,7 @@ import {
2628
TableLoading,
2729
TableNoRecord,
2830
} from '../../lib'
29-
import { checkIsMM } from '../../lib/utils'
31+
import { checkIsMM, getSubmissionReprocessTopic } from '../../lib/utils'
3032

3133
import styles from './ManageSubmissionPage.module.scss'
3234

@@ -46,6 +48,10 @@ export const ManageSubmissionPage: FC<Props> = (props: Props) => {
4648
challengeInfo,
4749
}: useFetchChallengeProps = useFetchChallenge(challengeId)
4850
const isMM = useMemo(() => checkIsMM(challengeInfo), [challengeInfo])
51+
const submissionReprocessTopic = useMemo(
52+
() => getSubmissionReprocessTopic(challengeInfo),
53+
[challengeInfo],
54+
)
4955

5056
const {
5157
isLoading: isLoadingSubmission,
@@ -71,6 +77,12 @@ export const ManageSubmissionPage: FC<Props> = (props: Props) => {
7177
isLoadingBool: isDoingAvScanBool,
7278
doPostBusEvent: doPostBusEventAvScan,
7379
}: useManageAVScanProps = useManageAVScan()
80+
const {
81+
isLoading: isReprocessingSubmission,
82+
isLoadingBool: isReprocessingSubmissionBool,
83+
doReprocessSubmission,
84+
}: useManageSubmissionReprocessProps
85+
= useManageSubmissionReprocess(submissionReprocessTopic)
7486

7587
const isLoading = isLoadingSubmission || isLoadingChallenge
7688

@@ -111,13 +123,21 @@ export const ManageSubmissionPage: FC<Props> = (props: Props) => {
111123
showSubmissionHistory={showSubmissionHistory}
112124
setShowSubmissionHistory={setShowSubmissionHistory}
113125
isMM={isMM}
126+
isReprocessingSubmission={
127+
isReprocessingSubmission
128+
}
129+
doReprocessSubmission={doReprocessSubmission}
130+
canReprocessSubmission={Boolean(
131+
submissionReprocessTopic,
132+
)}
114133
/>
115134

116135
{(isDoingAvScanBool
117136
|| isDownloadingSubmissionBool
118137
|| isRemovingSubmissionBool
119138
|| isRunningTestBool
120-
|| isRemovingReviewSummationsBool) && (
139+
|| isRemovingReviewSummationsBool
140+
|| isReprocessingSubmissionBool) && (
121141
<ActionLoading />
122142
)}
123143
</div>

src/apps/admin/src/config/busEvent.config.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
RequestBusAPI,
1010
RequestBusAPIAVScan,
1111
RequestBusAPIAVScanPayload,
12+
RequestBusAPIReprocess,
13+
SubmissionReprocessPayload,
1214
} from '../lib/models'
1315

1416
/**
@@ -49,3 +51,26 @@ export const CREATE_BUS_EVENT_AV_RESCAN = (
4951
.toISOString(),
5052
topic: EnvironmentConfig.ADMIN.AVSCAN_TOPIC,
5153
})
54+
55+
export const SUBMISSION_REPROCESS_TOPICS = {
56+
FIRST2FINISH: 'first2finish.submission.received',
57+
TOPGEAR_TASK: 'topgear.submission.received',
58+
}
59+
60+
/**
61+
* Create data for submission reprocess bus event
62+
* @param topic kafka topic
63+
* @param payload submission data
64+
* @returns data for bus event
65+
*/
66+
export const CREATE_BUS_EVENT_REPROCESS_SUBMISSION = (
67+
topic: string,
68+
payload: SubmissionReprocessPayload,
69+
): RequestBusAPIReprocess => ({
70+
'mime-type': 'application/json',
71+
originator: 'review-api-v6',
72+
payload,
73+
timestamp: new Date()
74+
.toISOString(),
75+
topic,
76+
})

src/apps/admin/src/lib/components/SubmissionTable/SubmissionTable.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ interface Props {
7070
downloadSubmission: (submissionId: string) => void
7171
isDoingAvScan: IsRemovingType
7272
doPostBusEventAvScan: (submission: Submission) => void
73+
isReprocessingSubmission: IsRemovingType
74+
doReprocessSubmission: (submission: Submission) => void
75+
canReprocessSubmission?: boolean
7376
}
7477

7578
export const SubmissionTable: FC<Props> = (props: Props) => {
@@ -277,6 +280,15 @@ export const SubmissionTable: FC<Props> = (props: Props) => {
277280
doPostBusEventAvScan={function doPostBusEventAvScan() {
278281
props.doPostBusEventAvScan(data)
279282
}}
283+
canReprocessSubmission={
284+
props.canReprocessSubmission
285+
}
286+
isReprocessingSubmission={
287+
props.isReprocessingSubmission
288+
}
289+
doReprocessSubmission={function doReprocessSubmission() {
290+
props.doReprocessSubmission(data)
291+
}}
280292
isDownloading={props.isDownloading}
281293
downloadSubmission={function downloadSubmission() {
282294
props.downloadSubmission(data.id)
@@ -306,6 +318,9 @@ export const SubmissionTable: FC<Props> = (props: Props) => {
306318
props.downloadSubmission,
307319
props.isDoingAvScan,
308320
props.doPostBusEventAvScan,
321+
props.isReprocessingSubmission,
322+
props.doReprocessSubmission,
323+
props.canReprocessSubmission,
309324
],
310325
)
311326

src/apps/admin/src/lib/components/SubmissionTable/SubmissionTableActionsNonMM.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ interface Props {
1515
downloadSubmission: () => void
1616
isDoingAvScan: IsRemovingType
1717
doPostBusEventAvScan: () => void
18+
canReprocessSubmission?: boolean
19+
isReprocessingSubmission: IsRemovingType
20+
doReprocessSubmission: () => void
1821
}
1922

2023
export const SubmissionTableActionsNonMM: FC<Props> = (props: Props) => (
@@ -39,6 +42,17 @@ export const SubmissionTableActionsNonMM: FC<Props> = (props: Props) => (
3942
AV Rescan
4043
</Button>
4144
)}
45+
{props.canReprocessSubmission && (
46+
<Button
47+
onClick={function onClick() {
48+
props.doReprocessSubmission()
49+
}}
50+
primary
51+
disabled={props.isReprocessingSubmission[props.data.id]}
52+
>
53+
Reprocess submission
54+
</Button>
55+
)}
4256
</div>
4357
)
4458

src/apps/admin/src/lib/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ export * from './useAutoScrollTopWhenInit'
3636
export * from './useFetchChallenge'
3737
export * from './useDownloadSubmission'
3838
export * from './useManageAVScan'
39+
export * from './useManageSubmissionReprocess'
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Manage submission reprocess event
3+
*/
4+
import { useCallback, useMemo, useState } from 'react'
5+
import { toast } from 'react-toastify'
6+
import _ from 'lodash'
7+
8+
import {
9+
CREATE_BUS_EVENT_REPROCESS_SUBMISSION,
10+
} from '../../config/busEvent.config'
11+
import { createSubmissionReprocessPayload, reqToBusAPI } from '../services'
12+
import { handleError } from '../utils'
13+
import { IsRemovingType, Submission } from '../models'
14+
15+
export interface useManageSubmissionReprocessProps {
16+
isLoading: IsRemovingType
17+
isLoadingBool: boolean
18+
doReprocessSubmission: (submission: Submission) => Promise<void>
19+
}
20+
21+
/**
22+
* Manage submission reprocess
23+
*/
24+
export function useManageSubmissionReprocess(
25+
topic?: string,
26+
): useManageSubmissionReprocessProps {
27+
const [isLoading, setIsLoading] = useState<IsRemovingType>({})
28+
const isLoadingBool = useMemo(
29+
() => _.some(isLoading, value => value === true),
30+
[isLoading],
31+
)
32+
33+
const doReprocessSubmission = useCallback(
34+
async (submission: Submission) => {
35+
if (!topic) {
36+
toast.error(
37+
'Submission reprocess is only available for specific challenge types.',
38+
{
39+
toastId: 'Reprocess submission',
40+
},
41+
)
42+
return
43+
}
44+
45+
setIsLoading(previous => ({
46+
...previous,
47+
[submission.id]: true,
48+
}))
49+
50+
try {
51+
const payload
52+
= await createSubmissionReprocessPayload(submission)
53+
const data = CREATE_BUS_EVENT_REPROCESS_SUBMISSION(
54+
topic,
55+
payload,
56+
)
57+
await reqToBusAPI(data)
58+
toast.success('Reprocess submission request sent', {
59+
toastId: 'Reprocess submission',
60+
})
61+
} catch (error) {
62+
handleError(error as Error)
63+
} finally {
64+
setIsLoading(previous => ({
65+
...previous,
66+
[submission.id]: false,
67+
}))
68+
}
69+
},
70+
[topic],
71+
)
72+
73+
return {
74+
doReprocessSubmission,
75+
isLoading,
76+
isLoadingBool,
77+
}
78+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { RequestBusAPI } from './RequestBusAPI.model'
22
import { RequestBusAPIAVScan } from './RequestBusAPIAVScan.model'
3+
import { RequestBusAPIReprocess } from './RequestBusAPIReprocess.model'
34

45
/**
56
* Common type for bus api request
67
*/
7-
export type CommonRequestBusAPI = RequestBusAPI | RequestBusAPIAVScan
8+
export type CommonRequestBusAPI = RequestBusAPI
9+
| RequestBusAPIAVScan
10+
| RequestBusAPIReprocess
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Request to reprocess submission bus api
3+
*/
4+
export interface SubmissionReprocessPayload {
5+
submissionId: string
6+
challengeId: string
7+
submissionUrl: string
8+
memberHandle: string
9+
memberId: string
10+
submittedDate: string
11+
}
12+
13+
export interface RequestBusAPIReprocess {
14+
topic: string
15+
originator: string
16+
timestamp: string
17+
'mime-type': string
18+
payload: SubmissionReprocessPayload
19+
}

src/apps/admin/src/lib/models/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export * from './RoleMemberInfo.model'
3535
export * from './Submission.model'
3636
export * from './RequestBusAPI.model'
3737
export * from './RequestBusAPIAVScan.model'
38+
export * from './RequestBusAPIReprocess.model'
3839
export * from './MemberSubmission.model'
3940
export * from './SubmissionReviewSummation.model'
4041
export * from './SSOUserLogin.model'

src/apps/admin/src/lib/services/submissions.service.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
MemberSubmission,
1111
RequestBusAPIAVScanPayload,
1212
Submission,
13+
SubmissionReprocessPayload,
1314
ValidateS3URIResult,
1415
} from '../models'
1516
import { validateS3URI } from '../utils'
@@ -139,3 +140,62 @@ export const createAvScanSubmissionPayload = async (
139140
url,
140141
}
141142
}
143+
144+
/**
145+
* Create submission reprocess payload
146+
* @param submissionInfo submission info
147+
* @returns resolves to the reprocess payload
148+
*/
149+
export const createSubmissionReprocessPayload = async (
150+
submissionInfo: Submission,
151+
): Promise<SubmissionReprocessPayload> => {
152+
const submissionId = submissionInfo.id
153+
const challengeId = submissionInfo.challengeId
154+
const submissionUrl = submissionInfo.url
155+
const memberId = submissionInfo.memberId
156+
const memberHandle = submissionInfo.submitterHandle ?? submissionInfo.createdBy
157+
const submittedDateValue = submissionInfo.submittedDate
158+
159+
if (!submissionId) {
160+
throw new Error('Submission id is not valid')
161+
}
162+
163+
const normalizedChallengeId = challengeId
164+
? challengeId.toString()
165+
: ''
166+
if (!normalizedChallengeId) {
167+
throw new Error('Challenge id is not valid')
168+
}
169+
170+
if (!submissionUrl) {
171+
throw new Error('Submission url is not valid')
172+
}
173+
174+
const normalizedMemberId = memberId ? memberId.toString() : ''
175+
if (!normalizedMemberId) {
176+
throw new Error('Member id is not valid')
177+
}
178+
179+
if (!memberHandle) {
180+
throw new Error('Member handle is not valid')
181+
}
182+
183+
const submittedDate = submittedDateValue
184+
? new Date(submittedDateValue)
185+
: undefined
186+
const submittedDateIso = submittedDate && !Number.isNaN(submittedDate.valueOf())
187+
? submittedDate.toISOString()
188+
: ''
189+
if (!submittedDateIso) {
190+
throw new Error('Submitted date is not valid')
191+
}
192+
193+
return {
194+
challengeId: normalizedChallengeId,
195+
memberHandle,
196+
memberId: normalizedMemberId,
197+
submissionId,
198+
submissionUrl,
199+
submittedDate: submittedDateIso,
200+
}
201+
}

0 commit comments

Comments
 (0)