@@ -436,6 +436,31 @@ function isDifferentPrizeSets (prizeSets, otherPrizeSets) {
436
436
return false
437
437
}
438
438
439
+ /**
440
+ * Validate the winners array.
441
+ * @param {Array } winners the Winner Array
442
+ */
443
+ function validateWinners ( winners ) {
444
+ for ( const winner of winners ) {
445
+ const diffWinners = _ . differenceWith ( winners , [ winner ] , _ . isEqual )
446
+ if ( diffWinners . length + 1 !== winners . length ) {
447
+ throw new errors . BadRequestError ( `Duplicate member with placement: ${ helper . toString ( winner ) } ` )
448
+ }
449
+
450
+ // find another member with the placement
451
+ const placementExists = _ . find ( diffWinners , function ( w ) { return w . placement === winner . placement } )
452
+ if ( placementExists && ( placementExists . userId !== winner . userId || placementExists . handle !== winner . handle ) ) {
453
+ throw new errors . BadRequestError ( `Only one member can have a placement: ${ winner . placement } ` )
454
+ }
455
+
456
+ // find another placement for a member
457
+ const memberExists = _ . find ( diffWinners , function ( w ) { return w . userId === winner . userId } )
458
+ if ( memberExists && memberExists . placement !== winner . placement ) {
459
+ throw new errors . BadRequestError ( `The same member ${ winner . userId } cannot have multiple placements` )
460
+ }
461
+ }
462
+ }
463
+
439
464
/**
440
465
* Update challenge.
441
466
* @param {Object } currentUser the user who perform operation
@@ -480,10 +505,22 @@ async function update (currentUser, challengeId, data, userToken, isFull) {
480
505
}
481
506
482
507
await validateChallengeData ( data )
508
+ if ( ( challenge . status === constants . challengeStatuses . Completed || challenge . status === constants . challengeStatuses . Canceled ) && data . status && data . status !== challenge . status ) {
509
+ throw new errors . BadRequestError ( `Cannot change ${ challenge . status } challenge status to ${ data . status } status` )
510
+ }
511
+
512
+ if ( data . winners && ( challenge . status !== constants . challengeStatuses . Completed && data . status !== constants . challengeStatuses . Completed ) ) {
513
+ throw new errors . BadRequestError ( `Cannot set winners for challenge with non-completed ${ challenge . status } status` )
514
+ }
515
+
483
516
if ( data . phases ) {
484
517
await helper . validatePhases ( data . phases )
485
518
}
486
519
520
+ if ( data . winners && data . winners . length ) {
521
+ await validateWinners ( data . winners )
522
+ }
523
+
487
524
data . updated = new Date ( )
488
525
data . updatedBy = currentUser . handle || currentUser . sub
489
526
const updateDetails = { }
@@ -526,6 +563,11 @@ async function update (currentUser, challengeId, data, userToken, isFull) {
526
563
_ . intersection ( challenge [ key ] , value ) . length !== value . length ) {
527
564
op = '$PUT'
528
565
}
566
+ } else if ( key === 'winners' ) {
567
+ if ( _ . isUndefined ( challenge [ key ] ) || challenge [ key ] . length !== value . length ||
568
+ _ . intersectionWith ( challenge [ key ] , value , _ . isEqual ) . length !== value . length ) {
569
+ op = '$PUT'
570
+ }
529
571
} else if ( _ . isUndefined ( challenge [ key ] ) || challenge [ key ] !== value ) {
530
572
op = '$PUT'
531
573
}
@@ -649,6 +691,24 @@ async function update (currentUser, challengeId, data, userToken, isFull) {
649
691
// send null to Elasticsearch to clear the field
650
692
data . legacyId = null
651
693
}
694
+ if ( isFull && _ . isUndefined ( data . winners ) && challenge . winners ) {
695
+ if ( ! updateDetails [ '$DELETE' ] ) {
696
+ updateDetails [ '$DELETE' ] = { }
697
+ }
698
+ updateDetails [ '$DELETE' ] . winners = null
699
+ auditLogs . push ( {
700
+ id : uuid ( ) ,
701
+ challengeId,
702
+ fieldName : 'winners' ,
703
+ oldValue : JSON . stringify ( challenge . winners ) ,
704
+ newValue : 'NULL' ,
705
+ created : new Date ( ) ,
706
+ createdBy : currentUser . handle || currentUser . sub
707
+ } )
708
+ delete challenge . winners
709
+ // send null to Elasticsearch to clear the field
710
+ data . winners = null
711
+ }
652
712
653
713
await models . Challenge . update ( { id : challengeId } , updateDetails )
654
714
if ( auditLogs . length > 0 ) {
@@ -727,7 +787,12 @@ fullyUpdateChallenge.schema = {
727
787
status : Joi . string ( ) . valid ( _ . values ( constants . challengeStatuses ) ) . required ( ) ,
728
788
attachmentIds : Joi . array ( ) . items ( Joi . optionalId ( ) ) ,
729
789
groups : Joi . array ( ) . items ( Joi . string ( ) ) , // group names
730
- gitRepoURLs : Joi . array ( ) . items ( Joi . string ( ) . uri ( ) )
790
+ gitRepoURLs : Joi . array ( ) . items ( Joi . string ( ) . uri ( ) ) ,
791
+ winners : Joi . array ( ) . items ( Joi . object ( ) . keys ( {
792
+ userId : Joi . number ( ) . integer ( ) . positive ( ) . required ( ) ,
793
+ handle : Joi . string ( ) . required ( ) ,
794
+ placement : Joi . number ( ) . integer ( ) . positive ( ) . required ( )
795
+ } ) ) . min ( 1 )
731
796
} ) . required ( ) ,
732
797
userToken : Joi . any ( )
733
798
}
@@ -783,7 +848,12 @@ partiallyUpdateChallenge.schema = {
783
848
status : Joi . string ( ) . valid ( _ . values ( constants . challengeStatuses ) ) ,
784
849
attachmentIds : Joi . array ( ) . items ( Joi . optionalId ( ) ) ,
785
850
groups : Joi . array ( ) . items ( Joi . string ( ) ) , // group names
786
- gitRepoURLs : Joi . array ( ) . items ( Joi . string ( ) . uri ( ) )
851
+ gitRepoURLs : Joi . array ( ) . items ( Joi . string ( ) . uri ( ) ) ,
852
+ winners : Joi . array ( ) . items ( Joi . object ( ) . keys ( {
853
+ userId : Joi . number ( ) . integer ( ) . positive ( ) . required ( ) ,
854
+ handle : Joi . string ( ) . required ( ) ,
855
+ placement : Joi . number ( ) . integer ( ) . positive ( ) . required ( )
856
+ } ) ) . min ( 1 )
787
857
} ) . required ( ) ,
788
858
userToken : Joi . any ( )
789
859
}
0 commit comments