Skip to content

Commit d7ef2d3

Browse files
committed
Add optional "checkpointWinners" to challenge object
1 parent fabad98 commit d7ef2d3

File tree

4 files changed

+149
-27
lines changed

4 files changed

+149
-27
lines changed

docs/swagger.yaml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2585,6 +2585,25 @@ definitions:
25852585
minimum: 1
25862586
description: the winner placement
25872587
example: 1
2588+
required:
2589+
- userId
2590+
- handle
2591+
- placement
2592+
checkpointWinners:
2593+
type: array
2594+
items:
2595+
properties:
2596+
userId:
2597+
type: integer
2598+
description: The user id
2599+
handle:
2600+
type: string
2601+
description: the user handle
2602+
placement:
2603+
type: integer
2604+
minimum: 1
2605+
description: the checkpoint winner placement
2606+
example: 1
25882607
required:
25892608
- userId
25902609
- handle
@@ -3032,6 +3051,25 @@ definitions:
30323051
- userId
30333052
- handle
30343053
- placement
3054+
checkpointWinners:
3055+
type: array
3056+
items:
3057+
properties:
3058+
userId:
3059+
type: integer
3060+
description: The user id
3061+
handle:
3062+
type: string
3063+
description: the user handle
3064+
placement:
3065+
type: integer
3066+
minimum: 1
3067+
description: the checkpoint winner placement
3068+
example: 1
3069+
required:
3070+
- userId
3071+
- handle
3072+
- placement
30353073
terms:
30363074
type: array
30373075
description: The ids and roleId of the terms of use to add for the challenge
@@ -3229,6 +3267,25 @@ definitions:
32293267
- userId
32303268
- handle
32313269
- placement
3270+
checkpointWinners:
3271+
type: array
3272+
items:
3273+
properties:
3274+
userId:
3275+
type: integer
3276+
description: The user id
3277+
handle:
3278+
type: string
3279+
description: the user handle
3280+
placement:
3281+
type: integer
3282+
minimum: 1
3283+
description: the checkpoint winner placement
3284+
example: 1
3285+
required:
3286+
- userId
3287+
- handle
3288+
- placement
32323289
terms:
32333290
type: array
32343291
description: The ids and roleId of the terms of use to add for the challenge

src/common/challenge-helper.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,11 @@ class ChallengeHelper {
297297
);
298298
}
299299

300+
const hasWinnerUpdates =
301+
(Array.isArray(data.winners) && data.winners.length > 0) ||
302+
(Array.isArray(data.checkpointWinners) && data.checkpointWinners.length > 0);
300303
if (
301-
data.winners &&
302-
data.winners.length > 0 &&
304+
hasWinnerUpdates &&
303305
challenge.status !== ChallengeStatusEnum.COMPLETED &&
304306
data.status !== ChallengeStatusEnum.COMPLETED
305307
) {

src/common/prisma-helper.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -244,21 +244,36 @@ function convertChallengeSchemaToPrisma(currentUser, challenge) {
244244
}),
245245
};
246246
}
247-
// winners
247+
const allWinnerEntries = [];
248248
if (!_.isNil(challenge.winners)) {
249+
_.forEach(challenge.winners, (winner) => {
250+
const entry = {
251+
...auditFields,
252+
..._.pick(winner, ["userId", "handle", "placement", "type"]),
253+
};
254+
if (_.isNil(entry.type)) {
255+
entry.type = PrizeSetTypeEnum.PLACEMENT;
256+
} else {
257+
entry.type = entry.type.toUpperCase();
258+
}
259+
allWinnerEntries.push(entry);
260+
});
261+
}
262+
if (!_.isNil(challenge.checkpointWinners)) {
263+
_.forEach(challenge.checkpointWinners, (winner) => {
264+
const entry = {
265+
...auditFields,
266+
..._.pick(winner, ["userId", "handle", "placement", "type"]),
267+
};
268+
entry.type = _.isNil(entry.type)
269+
? PrizeSetTypeEnum.CHECKPOINT
270+
: entry.type.toUpperCase();
271+
allWinnerEntries.push(entry);
272+
});
273+
}
274+
if (allWinnerEntries.length > 0) {
249275
result.winners = {
250-
create: _.map(challenge.winners, (w) => {
251-
const t = {
252-
...auditFields,
253-
..._.pick(w, ["userId", "handle", "placement", "type"]),
254-
};
255-
if (_.isNil(t.type)) {
256-
t.type = PrizeSetTypeEnum.PLACEMENT;
257-
} else {
258-
t.type = t.type.toUpperCase();
259-
}
260-
return t;
261-
}),
276+
create: allWinnerEntries,
262277
};
263278
}
264279
// relations
@@ -357,11 +372,17 @@ function convertModelToResponse(ret) {
357372
// convert attachments
358373
ret.attachments = _.map(ret.attachments, (r) => _.omit(r, constants.auditFields, "challengeId"));
359374
// convert winners
360-
ret.winners = _.map(ret.winners, (w) => {
361-
const winner = _.pick(w, ["userId", "handle", "placement"]);
362-
363-
return winner;
364-
});
375+
const winnersForResponse = ret.winners || [];
376+
const winnerGroups = _.groupBy(winnersForResponse, (w) => w.type);
377+
const placementWinners = winnerGroups[PrizeSetTypeEnum.PLACEMENT] || [];
378+
const checkpointWinners = winnerGroups[PrizeSetTypeEnum.CHECKPOINT] || [];
379+
ret.winners = _.map(placementWinners, (w) => _.pick(w, ["userId", "handle", "placement"]));
380+
delete ret.checkpointWinners;
381+
if (checkpointWinners.length > 0) {
382+
ret.checkpointWinners = _.map(checkpointWinners, (w) =>
383+
_.pick(w, ["userId", "handle", "placement"])
384+
);
385+
}
365386
// convert reviewers
366387
if (ret.reviewers) {
367388
ret.reviewers = _.map(ret.reviewers, (rv) =>

src/services/ChallengeService.js

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,7 @@ async function searchChallenges(currentUser, criteria) {
10981098
result.forEach((challenge) => {
10991099
if (challenge.status !== ChallengeStatusEnum.COMPLETED) {
11001100
_.unset(challenge, "winners");
1101+
_.unset(challenge, "checkpointWinners");
11011102
}
11021103
if (!_hasAdminRole && !_.get(currentUser, "isMachine", false)) {
11031104
_.unset(challenge, "payments");
@@ -1769,6 +1770,7 @@ async function getChallenge(currentUser, id, checkIfExists) {
17691770

17701771
if (challenge.status !== ChallengeStatusEnum.COMPLETED) {
17711772
_.unset(challenge, "winners");
1773+
_.unset(challenge, "checkpointWinners");
17721774
}
17731775

17741776
// TODO: in the long run we wanna do a finer grained filtering of the payments
@@ -1855,6 +1857,27 @@ function isDifferentPrizeSets(prizeSets = [], otherPrizeSets = []) {
18551857
* @param {Array} winners the Winner Array
18561858
* @param {Array} challengeResources the challenge resources
18571859
*/
1860+
function buildCombinedWinnerPayload(data = {}) {
1861+
const combined = [];
1862+
if (Array.isArray(data.winners)) {
1863+
combined.push(
1864+
...data.winners.map((winner) => ({
1865+
...winner,
1866+
type: _.toUpper(winner.type || PrizeSetTypeEnum.PLACEMENT),
1867+
}))
1868+
);
1869+
}
1870+
if (Array.isArray(data.checkpointWinners)) {
1871+
combined.push(
1872+
...data.checkpointWinners.map((winner) => ({
1873+
...winner,
1874+
type: _.toUpper(winner.type || PrizeSetTypeEnum.CHECKPOINT),
1875+
}))
1876+
);
1877+
}
1878+
return combined;
1879+
}
1880+
18581881
async function validateWinners(winners, challengeResources) {
18591882
const registrants = _.filter(challengeResources, (r) => r.roleId === config.SUBMITTER_ROLE_ID);
18601883
for (const prizeType of _.values(PrizeSetTypeEnum)) {
@@ -2381,13 +2404,15 @@ async function updateChallenge(currentUser, challengeId, data, options = {}) {
23812404
}
23822405
}
23832406

2384-
if (data.winners && data.winners.length && data.winners.length > 0) {
2385-
await validateWinners(data.winners, challengeResources);
2386-
if (_.get(challenge, "legacy.pureV5Task", false)) {
2387-
_.each(data.winners, (w) => {
2388-
w.type = PrizeSetTypeEnum.PLACEMENT;
2389-
});
2390-
}
2407+
const combinedWinnerPayload = buildCombinedWinnerPayload(data);
2408+
if (combinedWinnerPayload.length > 0) {
2409+
await validateWinners(combinedWinnerPayload, challengeResources);
2410+
}
2411+
2412+
if (_.get(challenge, "legacy.pureV5Task", false) && !_.isUndefined(data.winners)) {
2413+
_.each(data.winners, (w) => {
2414+
w.type = PrizeSetTypeEnum.PLACEMENT;
2415+
});
23912416
}
23922417

23932418
// Only m2m tokens are allowed to modify the `task.*` information on a challenge
@@ -2876,6 +2901,18 @@ updateChallenge.schema = {
28762901
.unknown(true)
28772902
)
28782903
.optional(),
2904+
checkpointWinners: Joi.array()
2905+
.items(
2906+
Joi.object()
2907+
.keys({
2908+
userId: Joi.number().integer().positive().required(),
2909+
handle: Joi.string().required(),
2910+
placement: Joi.number().integer().positive().required(),
2911+
type: Joi.string().valid(_.values(PrizeSetTypeEnum)),
2912+
})
2913+
.unknown(true)
2914+
)
2915+
.optional(),
28792916
terms: Joi.array().items(
28802917
Joi.object().keys({
28812918
id: Joi.id(),
@@ -3192,6 +3229,11 @@ function sanitizeChallenge(challenge) {
31923229
_.pick(winner, ["userId", "handle", "placement", "type"])
31933230
);
31943231
}
3232+
if (challenge.checkpointWinners) {
3233+
sanitized.checkpointWinners = _.map(challenge.checkpointWinners, (winner) =>
3234+
_.pick(winner, ["userId", "handle", "placement", "type"])
3235+
);
3236+
}
31953237
if (challenge.discussions) {
31963238
sanitized.discussions = _.map(challenge.discussions, (discussion) => ({
31973239
..._.pick(discussion, ["id", "provider", "name", "type", "url", "options"]),

0 commit comments

Comments
 (0)