Skip to content

Commit 4ee9405

Browse files
authored
Merge pull request #705 from topcoder-platform/dev
feat: points & new timeline template
2 parents 7727daa + 47c1265 commit 4ee9405

File tree

9 files changed

+285
-222
lines changed

9 files changed

+285
-222
lines changed

.circleci/config.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ workflows:
9090
branches:
9191
only:
9292
- dev
93-
- hotfix/budget-update
94-
- CORE-140
93+
- CORE-40
9594

9695
- "build-qa":
9796
context: org-global

app-constants.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ const prizeSetTypes = {
1818
CheckpointPrizes: "checkpoint",
1919
};
2020

21+
const prizeTypes = {
22+
USD: "USD",
23+
POINT: "POINT",
24+
};
25+
2126
const challengeStatuses = {
2227
New: "New",
2328
Draft: "Draft",
@@ -137,6 +142,7 @@ const SelfServiceNotificationSettings = {
137142
module.exports = {
138143
UserRoles,
139144
prizeSetTypes,
145+
prizeTypes,
140146
challengeStatuses,
141147
validChallengeParams,
142148
EVENT_ORIGINATOR,

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@
4242
"dependencies": {
4343
"@grpc/grpc-js": "^1.8.12",
4444
"@opensearch-project/opensearch": "^2.2.0",
45-
"@topcoder-framework/domain-challenge": "^0.24.0",
45+
"@topcoder-framework/domain-challenge": "^0.24.1",
4646
"@topcoder-framework/domain-acl": "^0.24.0",
47-
"@topcoder-framework/lib-common": "^0.24.0",
47+
"@topcoder-framework/lib-common": "^0.24.1",
4848
"aws-sdk": "^2.1145.0",
4949
"axios": "^0.19.0",
5050
"axios-retry": "^3.4.0",

src/common/challenge-helper.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ class ChallengeHelper {
9999
await Promise.all(promises);
100100
}
101101

102+
validatePrizeSetsAndGetPrizeType(prizeSets) {
103+
if (_.isEmpty(prizeSets)) return null;
104+
105+
const firstType = _.get(prizeSets, "[0].prizes[0].type", null);
106+
if (!firstType) return null;
107+
108+
const isConsistent = _.every(prizeSets, (prizeSet) =>
109+
_.every(prizeSet.prizes, (prize) => prize.type === firstType)
110+
);
111+
112+
if (!isConsistent) {
113+
throw new errors.BadRequestError("All prizes must be of the same type");
114+
}
115+
116+
return firstType;
117+
}
118+
102119
/**
103120
* Validate Challenge skills.
104121
* @param {Object} challenge the challenge
@@ -114,7 +131,9 @@ class ChallengeHelper {
114131
if (oldChallenge && oldChallenge.status === constants.challengeStatuses.Completed) {
115132
// Don't allow edit skills for Completed challenges
116133
if (!_.isEqual(ids, _.uniq(_.map(oldChallenge.skills, "id")))) {
117-
throw new errors.BadRequestError("Cannot update skills for challenges with Completed status");
134+
throw new errors.BadRequestError(
135+
"Cannot update skills for challenges with Completed status"
136+
);
118137
}
119138
}
120139

@@ -356,12 +375,14 @@ class ChallengeHelper {
356375
}
357376

358377
if (data.prizeSets != null) {
359-
ChallengeHelper.convertPSValuesToCents(data.prizeSets)
360-
console.log('Converted prizeSets to cents', data.prizeSets)
378+
const type = data.prizeSets[0]?.prizes[0]?.type;
379+
if (type === constants.prizeTypes.USD) {
380+
ChallengeHelper.convertPSValuesToCents(data.prizeSets)
381+
}
382+
361383
data.prizeSetUpdate = {
362384
prizeSets: [...data.prizeSets],
363385
};
364-
console.log('prizeSetUpdate', data.prizeSetUpdate)
365386
delete data.prizeSets;
366387
}
367388

src/common/logger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ logger.logFullError = (err, signature) => {
3535
`${err.name} details: ${JSON.stringify(err.details)} input:${JSON.stringify(err._object)}`
3636
);
3737
} else if (err.isAxiosError) {
38-
logger.error(`${err.message} - ${err.response.data}`);
38+
logger.error(`${err.message} - ${JSON.stringify(err.response.data)}`);
3939
} else if (err.httpStatus) {
4040
logger.error(err.message);
4141
} else if (!_.isUndefined(err.code) && err.details && err.metadata) {

src/phase-management/PhaseAdvancer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ class PhaseAdvancer {
290290

291291
async #areAllSubmissionsReviewed(challengeId) {
292292
console.log(`Getting review count for challenge ${challengeId}`);
293-
return Promise.resolve(false);
293+
return Promise.resolve(true);
294294
}
295295

296296
async #areAllAppealsResolved(challengeId) {

src/phase-management/phase-rules.json

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
{
22
"openRules": {
3+
"Open": [
4+
{
5+
"name": "Open Registration & Submission",
6+
"conditions": {
7+
"all": [
8+
{
9+
"fact": "isPastScheduledStartTime",
10+
"operator": "equal",
11+
"value": true
12+
},
13+
{
14+
"fact": "isOpen",
15+
"operator": "notEqual",
16+
"value": true
17+
},
18+
{
19+
"fact": "isClosed",
20+
"operator": "notEqual",
21+
"value": true
22+
}
23+
]
24+
},
25+
"event": {
26+
"type": "canOpen"
27+
}
28+
}
29+
],
330
"Registration": [
431
{
532
"name": "Registration Open",
@@ -74,11 +101,6 @@
74101
"operator": "notEqual",
75102
"value": true
76103
},
77-
{
78-
"fact": "submissionCount",
79-
"operator": "greaterThanInclusive",
80-
"value": 1
81-
},
82104
{
83105
"fact": "isPredecessorPhaseClosed",
84106
"operator": "equal",
@@ -184,6 +206,33 @@
184206
]
185207
},
186208
"closeRules": {
209+
"Open": [
210+
{
211+
"name": "Close Registration & Submission",
212+
"conditions": {
213+
"all": [
214+
{
215+
"fact": "isOpen",
216+
"operator": "equal",
217+
"value": true
218+
},
219+
{
220+
"fact": "isPastScheduledEndTime",
221+
"operator": "equal",
222+
"value": true
223+
},
224+
{
225+
"fact": "isClosed",
226+
"operator": "notEqual",
227+
"value": true
228+
}
229+
]
230+
},
231+
"event": {
232+
"type": "canClose"
233+
}
234+
}
235+
],
187236
"Registration": [
188237
{
189238
"name": "Registration Close",

src/services/ChallengeService.js

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,6 @@ async function searchChallenges(currentUser, criteria) {
340340
}
341341
boolQuery.push({ range: { "overview.totalPrizes": prizeRangeQuery } });
342342
}
343-
344-
if (criteria.useSchedulingAPI) {
345-
boolQuery.push({
346-
match_phrase: { "legacy.useSchedulingAPI": criteria.useSchedulingAPI },
347-
});
348-
}
349343
if (criteria.selfService) {
350344
boolQuery.push({
351345
match_phrase: { "legacy.selfService": criteria.selfService },
@@ -379,9 +373,21 @@ async function searchChallenges(currentUser, criteria) {
379373
});
380374
}
381375
if (criteria.currentPhaseName) {
382-
boolQuery.push({
383-
match_phrase: { currentPhaseNames: criteria.currentPhaseName },
384-
});
376+
if (criteria.currentPhaseName === "Registration") {
377+
boolQuery.push({
378+
bool: {
379+
should: [
380+
{ match_phrase: { currentPhaseNames: "Registration" } },
381+
{ match_phrase: { currentPhaseNames: "Open" } },
382+
],
383+
minimum_should_match: 1,
384+
},
385+
});
386+
} else {
387+
boolQuery.push({
388+
match_phrase: { currentPhaseNames: criteria.currentPhaseName },
389+
});
390+
}
385391
}
386392
if (criteria.createdDateStart) {
387393
boolQuery.push({ range: { created: { gte: criteria.createdDateStart } } });
@@ -930,7 +936,9 @@ searchChallenges.schema = {
930936
*/
931937
async function createChallenge(currentUser, challenge, userToken) {
932938
await challengeHelper.validateCreateChallengeRequest(currentUser, challenge);
939+
let prizeTypeTmp = challengeHelper.validatePrizeSetsAndGetPrizeType(challenge.prizeSets);
933940

941+
console.log("TYPE", prizeTypeTmp);
934942
if (challenge.legacy.selfService) {
935943
// if self-service, create a new project (what about if projectId is provided in the payload? confirm with business!)
936944
if (!challenge.projectId) {
@@ -1065,9 +1073,17 @@ async function createChallenge(currentUser, challenge, userToken) {
10651073
grpcMetadata.set("userId", currentUser.userId);
10661074
grpcMetadata.set("token", await getM2MToken());
10671075

1068-
convertPrizeSetValuesToCents(challenge.prizeSets);
1076+
const prizeType = challengeHelper.validatePrizeSetsAndGetPrizeType(challenge.prizeSets);
1077+
1078+
if (prizeType === constants.prizeTypes.USD) {
1079+
convertPrizeSetValuesToCents(challenge.prizeSets);
1080+
}
1081+
10691082
const ret = await challengeDomain.create(challenge, grpcMetadata);
1070-
convertPrizeSetValuesToDollars(ret.prizeSets, ret.overview);
1083+
1084+
if (prizeType === constants.prizeTypes.USD) {
1085+
convertPrizeSetValuesToDollars(ret.prizeSets, ret.overview);
1086+
}
10711087

10721088
ret.numOfSubmissions = 0;
10731089
ret.numOfRegistrants = 0;
@@ -1494,7 +1510,11 @@ function validateTask(currentUser, challenge, data, challengeResources) {
14941510
*/
14951511
async function updateChallenge(currentUser, challengeId, data) {
14961512
const challenge = await challengeDomain.lookup(getLookupCriteria("id", challengeId));
1497-
convertPrizeSetValuesToDollars(challenge.prizeSets, challenge.overview);
1513+
const existingPrizeType = challengeHelper.validatePrizeSetsAndGetPrizeType(challenge.prizeSets);
1514+
1515+
if (existingPrizeType === constants.prizeTypes.USD) {
1516+
convertPrizeSetValuesToDollars(challenge.prizeSets, challenge.overview);
1517+
}
14981518

14991519
const projectId = _.get(challenge, "projectId");
15001520

@@ -1618,15 +1638,6 @@ async function updateChallenge(currentUser, challengeId, data) {
16181638
let isChallengeBeingCancelled = false;
16191639
if (data.status) {
16201640
if (data.status === constants.challengeStatuses.Active) {
1621-
if (
1622-
!_.get(challenge, "legacy.pureV5Task") &&
1623-
!_.get(challenge, "legacy.pureV5") &&
1624-
_.isUndefined(_.get(challenge, "legacyId"))
1625-
) {
1626-
throw new errors.BadRequestError(
1627-
"You cannot activate the challenge as it has not been created on legacy yet. Please try again later or contact support."
1628-
);
1629-
}
16301641
// if activating a challenge, the challenge must have a billing account id
16311642
if (
16321643
(!billingAccountId || billingAccountId === null) &&
@@ -1799,6 +1810,11 @@ async function updateChallenge(currentUser, challengeId, data) {
17991810

18001811
if (data.winners && data.winners.length && data.winners.length > 0) {
18011812
await validateWinners(data.winners, challengeResources);
1813+
if (_.get(challenge, "legacy.pureV5Task", false)) {
1814+
_.each(data.winners, (w) => {
1815+
w.type = constants.prizeSetTypes.ChallengePrizes;
1816+
});
1817+
}
18021818
}
18031819

18041820
// Only m2m tokens are allowed to modify the `task.*` information on a challenge
@@ -1891,25 +1907,28 @@ async function updateChallenge(currentUser, challengeId, data) {
18911907
}
18921908
}
18931909

1894-
try {
1895-
const updateInput = sanitizeRepeatedFieldsInUpdateRequest(_.omit(data, ["cancelReason"]));
1896-
if (!_.isEmpty(updateInput)) {
1897-
const grpcMetadata = new GrpcMetadata();
1910+
const updateInput = sanitizeRepeatedFieldsInUpdateRequest(_.omit(data, ["cancelReason"]));
1911+
if (!_.isEmpty(updateInput)) {
1912+
const grpcMetadata = new GrpcMetadata();
18981913

1899-
grpcMetadata.set("handle", currentUser.handle);
1900-
grpcMetadata.set("userId", currentUser.userId);
1901-
grpcMetadata.set("token", await getM2MToken());
1914+
grpcMetadata.set("handle", currentUser.handle);
1915+
grpcMetadata.set("userId", currentUser.userId);
1916+
grpcMetadata.set("token", await getM2MToken());
19021917

1903-
await challengeDomain.update(
1904-
{
1905-
filterCriteria: getScanCriteria({ id: challengeId }),
1906-
updateInput,
1907-
},
1908-
grpcMetadata
1918+
const newPrizeType = challengeHelper.validatePrizeSetsAndGetPrizeType(updateInput.prizeSets);
1919+
if (newPrizeType != null && existingPrizeType != null && newPrizeType !== existingPrizeType) {
1920+
throw new errors.BadRequestError(
1921+
`Cannot change prize type from ${existingPrizeType} to ${newPrizeType}`
19091922
);
19101923
}
1911-
} catch (e) {
1912-
throw e;
1924+
1925+
await challengeDomain.update(
1926+
{
1927+
filterCriteria: getScanCriteria({ id: challengeId }),
1928+
updateInput,
1929+
},
1930+
grpcMetadata
1931+
);
19131932
}
19141933

19151934
const updatedChallenge = await challengeDomain.lookup(getLookupCriteria("id", challengeId));
@@ -2119,9 +2138,7 @@ updateChallenge.schema = {
21192138
userId: Joi.number().integer().positive().required(),
21202139
handle: Joi.string().required(),
21212140
placement: Joi.number().integer().positive().required(),
2122-
type: Joi.string()
2123-
.valid(_.values(constants.prizeSetTypes))
2124-
.default(constants.prizeSetTypes.ChallengePrizes),
2141+
type: Joi.string().valid(_.values(constants.prizeSetTypes)),
21252142
})
21262143
.unknown(true)
21272144
)
@@ -2423,7 +2440,11 @@ advancePhase.schema = {
24232440
};
24242441

24252442
async function indexChallengeAndPostToKafka(updatedChallenge, track, type) {
2426-
convertPrizeSetValuesToDollars(updatedChallenge.prizeSets, updatedChallenge.overview);
2443+
const prizeType = challengeHelper.validatePrizeSetsAndGetPrizeType(updatedChallenge.prizeSets);
2444+
2445+
if (prizeType === constants.prizeTypes.USD) {
2446+
convertPrizeSetValuesToDollars(updatedChallenge.prizeSets, updatedChallenge.overview);
2447+
}
24272448

24282449
if (track == null || type == null) {
24292450
const trackAndTypeData = await challengeHelper.validateAndGetChallengeTypeAndTrack({

0 commit comments

Comments
 (0)