@@ -55,6 +55,43 @@ function parsePrizes(issue) {
55
55
return true ;
56
56
}
57
57
58
+ /**
59
+ * Check challenge data and challenge resources
60
+ * @param {Object } event the event
61
+ * @param {Object } challenge the challenge
62
+ * @param {Object } challengeResources the challenge resources
63
+ * @returns {boolean } true if the challenge and challenge resources is valid; or false otherwise
64
+ * @private
65
+ */
66
+ function checkChallenge ( event , challenge , challengeResources ) {
67
+ // check prize
68
+ const validPrize = _ . isEqual ( challenge . prize . sort ( ) , event . dbIssue . prizes . sort ( ) ) ;
69
+
70
+ // check copilot
71
+ const copilot = _ . find ( challengeResources , { role : 'Copilot' } ) ;
72
+ const validCopilot = copilot ? copilot . properties . Handle === event . copilot . topcoderUsername : false ;
73
+
74
+ // check assignee
75
+ const assignee = _ . find ( challengeResources , { role : 'Submitter' } ) ;
76
+ const validAssignee = assignee ? assignee . properties . Handle === event . assigneeMember . topcoderUsername : false ;
77
+
78
+ // check status
79
+ const validStatus = challenge . currentStatus . toLowerCase ( ) === 'active' ;
80
+
81
+ return validPrize && validCopilot && validAssignee && validStatus ;
82
+ }
83
+
84
+ /**
85
+ * Check the error object contains some error messages
86
+ * @param {Object } err the error object
87
+ * @param {Array } validErrorMessages the valid error messages
88
+ * @returns {boolean } true if the error contains some valid error messages; or false otherwise
89
+ * @private
90
+ */
91
+ function checkErrorMessages ( err , validErrorMessages ) {
92
+ return _ . some ( validErrorMessages , ( errorMessage ) => err . message && err . message . includes ( errorMessage ) ) ;
93
+ }
94
+
58
95
/**
59
96
* handles the event gracefully when there is error processing the event
60
97
* @param {Object } event the event
@@ -69,6 +106,16 @@ async function handleEventGracefully(event, issue, err) {
69
106
logger . debug ( 'Scheduling event for next retry' ) ;
70
107
const newEvent = { ...event } ;
71
108
newEvent . retryCount += 1 ;
109
+
110
+ const validErrorMessages = [ 'Failed to create challenge.' , 'Failed to activate challenge.' ] ;
111
+
112
+ if ( newEvent . event === 'issue.closed' && checkErrorMessages ( err , validErrorMessages ) ) {
113
+ const challenge = await topcoderApiHelper . getChallengeById ( newEvent . dbIssue . challengeId ) ;
114
+ const challengeResources = await topcoderApiHelper . getResourcesFromChallenge ( newEvent . dbIssue . challengeId ) ;
115
+
116
+ newEvent . challengeValid = checkChallenge ( newEvent , challenge , challengeResources ) ;
117
+ }
118
+
72
119
delete newEvent . copilot ;
73
120
setTimeout ( async ( ) => {
74
121
const kafka = require ( '../utils/kafka' ) ; // eslint-disable-line
@@ -325,6 +372,8 @@ async function handleIssueClose(event, issue) {
325
372
let dbIssue ;
326
373
try {
327
374
dbIssue = await ensureChallengeExists ( event , issue ) ;
375
+ event . dbIssue = dbIssue ;
376
+
328
377
if ( ! event . paymentSuccessful ) {
329
378
let closeChallenge = false ;
330
379
// if issue is closed without Fix accepted label
@@ -339,7 +388,6 @@ async function handleIssueClose(event, issue) {
339
388
closeChallenge = true ;
340
389
}
341
390
342
-
343
391
// if issue is closed without assignee then do nothing
344
392
if ( ! event . data . assignee . id ) {
345
393
logger . debug ( `This issue ${ issue . number } doesn't have assignee so ignoring this event.` ) ;
@@ -354,6 +402,7 @@ async function handleIssueClose(event, issue) {
354
402
355
403
logger . debug ( `Looking up TC handle of git user: ${ event . data . assignee . id } ` ) ;
356
404
const assigneeMember = await userService . getTCUserName ( event . provider , event . data . assignee . id ) ;
405
+ event . assigneeMember = assigneeMember
357
406
358
407
// no mapping is found for current assignee remove assign, re-open issue and make comment
359
408
// to assignee to login with Topcoder X
@@ -398,7 +447,10 @@ async function handleIssueClose(event, issue) {
398
447
await topcoderApiHelper . assignUserAsRegistrant ( winnerId , dbIssue . challengeId ) ;
399
448
400
449
// activate challenge
401
- await topcoderApiHelper . activateChallenge ( dbIssue . challengeId ) ;
450
+ if ( ! event . challengeValid ) {
451
+ await topcoderApiHelper . activateChallenge ( dbIssue . challengeId ) ;
452
+ }
453
+
402
454
if ( closeChallenge ) {
403
455
logger . debug ( `The associated challenge ${ dbIssue . challengeId } is scheduled for cancel` ) ;
404
456
setTimeout ( async ( ) => {
@@ -413,7 +465,7 @@ async function handleIssueClose(event, issue) {
413
465
}
414
466
} catch ( e ) {
415
467
event . paymentSuccessful = event . paymentSuccessful === true ; // if once paid shouldn't be false
416
- await handleEventGracefully ( event , issue , e , event . paymentSuccessful ) ;
468
+ await handleEventGracefully ( event , issue , e ) ;
417
469
return ;
418
470
}
419
471
try {
@@ -425,7 +477,7 @@ async function handleIssueClose(event, issue) {
425
477
await dbIssue . save ( ) ;
426
478
await gitHelper . markIssueAsPaid ( event , issue . number , dbIssue . challengeId ) ;
427
479
} catch ( e ) {
428
- await handleEventGracefully ( event , issue , e , event . paymentSuccessful ) ;
480
+ await handleEventGracefully ( event , issue , e ) ;
429
481
return ;
430
482
}
431
483
}
@@ -657,7 +709,10 @@ process.schema = Joi.object().keys({
657
709
labels : Joi . array ( ) . items ( Joi . string ( ) )
658
710
} ) . required ( ) ,
659
711
retryCount : Joi . number ( ) . integer ( ) . default ( 0 ) . optional ( ) ,
660
- paymentSuccessful : Joi . boolean ( ) . default ( false ) . optional ( )
712
+ paymentSuccessful : Joi . boolean ( ) . default ( false ) . optional ( ) ,
713
+ challengeValid : Joi . boolean ( ) . default ( false ) . optional ( ) ,
714
+ dbIssue : Joi . object ( ) . optional ( ) ,
715
+ assigneeMember : Joi . object ( ) . optional ( ) ,
661
716
} ) ;
662
717
663
718
0 commit comments