Skip to content

Commit 814a553

Browse files
authored
Merge pull request #654 from topcoder-platform/dev
feat: add challenge contraints
2 parents f919751 + 0c144a0 commit 814a553

File tree

7 files changed

+85
-29
lines changed

7 files changed

+85
-29
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ workflows:
9090
branches:
9191
only:
9292
- dev
93-
- feature/phase-advance
93+
- PLAT-3368
9494

9595
- "build-qa":
9696
context: org-global

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
"dependencies": {
4343
"@grpc/grpc-js": "^1.8.12",
4444
"@opensearch-project/opensearch": "^2.2.0",
45-
"@topcoder-framework/domain-challenge": "^0.18.0",
46-
"@topcoder-framework/lib-common": "^0.18.0",
45+
"@topcoder-framework/domain-challenge": "^0.22.0",
46+
"@topcoder-framework/lib-common": "^0.22.0",
4747
"aws-sdk": "^2.1145.0",
4848
"axios": "^0.19.0",
4949
"axios-retry": "^3.4.0",

src/common/challenge-helper.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class ChallengeHelper {
9999

100100
// check groups authorization
101101
await helper.ensureAccessibleByGroupsAccess(currentUser, challenge);
102+
103+
if (challenge.constraints) {
104+
await ChallengeHelper.validateChallengeConstraints(challenge.constraints);
105+
}
102106
}
103107

104108
async validateChallengeUpdateRequest(currentUser, challenge, data) {
@@ -196,6 +200,32 @@ class ChallengeHelper {
196200
`Cannot set winners for challenge with non-completed ${challenge.status} status`
197201
);
198202
}
203+
204+
if (data.constraints) {
205+
await ChallengeHelper.validateChallengeConstraints(data.constraints);
206+
}
207+
}
208+
209+
static async validateChallengeConstraints(constraints) {
210+
if (!_.isEmpty(constraints.allowedRegistrants)) {
211+
await ChallengeHelper.validateAllowedRegistrants(constraints.allowedRegistrants);
212+
}
213+
}
214+
215+
static async validateAllowedRegistrants(allowedRegistrants) {
216+
const members = await helper.getMembersByHandles(allowedRegistrants);
217+
const incorrectHandles = _.difference(
218+
allowedRegistrants,
219+
_.map(members, (m) => _.lowerCase(m.handle))
220+
);
221+
if (incorrectHandles.length > 0) {
222+
throw new errors.BadRequestError(
223+
`Cannot create challenge with invalid handle in constraints. [${_.join(
224+
incorrectHandles,
225+
","
226+
)}]`
227+
);
228+
}
199229
}
200230

201231
sanitizeRepeatedFieldsInUpdateRequest(data) {

src/common/helper.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ async function capturePayment(paymentId) {
358358
const url = `${config.CUSTOMER_PAYMENTS_URL}/${paymentId}/charge`;
359359
logger.info(`Calling: ${url} to capture payment`);
360360
const res = await axios.patch(url, {}, { headers: { Authorization: `Bearer ${token}` } });
361-
logger.debug(`Payment API Response: ${JSON.stringify(res.data, null, 2)}`);
361+
logger.debug(`Payment API Response: ${JSON.stringify(res.data)}`);
362362
if (res.data.status !== "succeeded") {
363363
throw new Error(`Failed to charge payment. Current status: ${res.data.status}`);
364364
}
@@ -1080,6 +1080,22 @@ async function getMemberByHandle(handle) {
10801080
return res.data || {};
10811081
}
10821082

1083+
/**
1084+
* Get members by handles
1085+
* @param {Array<String>} handles the user handle
1086+
* @returns {Object}
1087+
*/
1088+
async function getMembersByHandles(handles) {
1089+
const token = await m2mHelper.getM2MToken();
1090+
const res = await axios.get(
1091+
`${config.MEMBERS_API_URL}/?fields=handle&handlesLower=["${_.join(handles, '","')}"]`,
1092+
{
1093+
headers: { Authorization: `Bearer ${token}` },
1094+
}
1095+
);
1096+
return res.data;
1097+
}
1098+
10831099
/**
10841100
* Send self service notification
10851101
* @param {String} type the notification type
@@ -1199,6 +1215,7 @@ module.exports = {
11991215
cancelPayment,
12001216
sendSelfServiceNotification,
12011217
getMemberByHandle,
1218+
getMembersByHandles,
12021219
submitZendeskRequest,
12031220
updateSelfServiceProjectInfo,
12041221
getFromInternalCache,

src/phase-management/PhaseAdvancer.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ class PhaseAdvancer {
212212
this.#updateSubsequentPhases(phases, phase, -delta);
213213
}
214214

215-
console.log(`Updated phases: ${JSON.stringify(phases, null, 2)}`);
215+
console.log(`Updated phases: ${JSON.stringify(phases)}`);
216216
}
217217

218218
async #close(challengeId, phases, phase) {
@@ -229,7 +229,7 @@ class PhaseAdvancer {
229229
this.#updateSubsequentPhases(phases, phase, -delta);
230230
}
231231

232-
console.log(`Updated phases: ${JSON.stringify(phases, null, 2)}`);
232+
console.log(`Updated phases: ${JSON.stringify(phases)}`);
233233
}
234234

235235
#insertPhaseIfRequired(phases, phase, facts) {
@@ -326,9 +326,7 @@ class PhaseAdvancer {
326326
async #hasActiveUnreviewedSubmissions(challengeId, phaseSpecificFacts, phases) {
327327
console.log(
328328
`Checking if there are active unreviewed submissions for challenge ${challengeId} using phaseSpecificFacts: ${JSON.stringify(
329-
phaseSpecificFacts,
330-
null,
331-
2
329+
phaseSpecificFacts
332330
)}`
333331
);
334332

src/services/ChallengeService.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,11 @@ createChallenge.schema = {
11651165
tags: Joi.array().items(Joi.string()), // tag names
11661166
projectId: Joi.number().integer().positive(),
11671167
legacyId: Joi.number().integer().positive(),
1168+
constraints: Joi.object()
1169+
.keys({
1170+
allowedRegistrants: Joi.array().items(Joi.string().trim().lowercase()).optional(),
1171+
})
1172+
.optional(),
11681173
startDate: Joi.date().iso(),
11691174
status: Joi.string().valid([
11701175
constants.challengeStatuses.Active,
@@ -1991,6 +1996,11 @@ updateChallenge.schema = {
19911996
tags: Joi.array().items(Joi.string().required()).min(1), // tag names
19921997
projectId: Joi.number().integer().positive(),
19931998
legacyId: Joi.number().integer().positive(),
1999+
constraints: Joi.object()
2000+
.keys({
2001+
allowedRegistrants: Joi.array().items(Joi.string().trim().lowercase()).optional(),
2002+
})
2003+
.optional(),
19942004
status: Joi.string().valid(_.values(constants.challengeStatuses)),
19952005
attachments: Joi.array().items(
19962006
Joi.object().keys({
@@ -2078,6 +2088,7 @@ function sanitizeChallenge(challenge) {
20782088
"task",
20792089
"groups",
20802090
"cancelReason",
2091+
"constraints",
20812092
]);
20822093
if (!_.isUndefined(sanitized.name)) {
20832094
sanitized.name = xss(sanitized.name);

yarn.lock

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -255,35 +255,35 @@
255255
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
256256
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
257257

258-
"@topcoder-framework/client-relational@^0.18.0":
259-
version "0.18.0"
260-
resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com/npm/topcoder-framework/@topcoder-framework/client-relational/-/client-relational-0.18.0.tgz#20175617c3ac281797d7717a157159076b2578fb"
261-
integrity sha512-JwcKcuT6w/3ydd27+doi9dVWHtuJClXOwajVOfXfHPGFhsgswfoFZ+k4kfc2kC/fioDJ1IPKdFRTeVCxycljnA==
258+
"@topcoder-framework/client-relational@^0.22.0":
259+
version "0.22.0"
260+
resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com/npm/topcoder-framework/@topcoder-framework/client-relational/-/client-relational-0.22.0.tgz#0e096758ffd8c9d0eb986b2f9328ed247930abfe"
261+
integrity sha512-We0sb8pdxOZfzX8WzKxczhXl16jmZ6cN/eBgDv5jR8qpVoXhLTa2iaTLqiRYUWi9ZvHCN6vmNQ607w0IU/iRFQ==
262262
dependencies:
263263
"@grpc/grpc-js" "^1.8.0"
264-
"@topcoder-framework/lib-common" "^0.18.0"
265-
topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.56-beta-1"
264+
"@topcoder-framework/lib-common" "^0.22.0"
265+
topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.58-beta-1"
266266
tslib "^2.4.1"
267267

268-
"@topcoder-framework/domain-challenge@^0.18.0":
269-
version "0.18.0"
270-
resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com/npm/topcoder-framework/@topcoder-framework/domain-challenge/-/domain-challenge-0.18.0.tgz#505d24e14a0354c900c2d55f92335bf9c5aa8d8c"
271-
integrity sha512-+jPNhU+ZqcTjuPBCYc2mLLTUiKVg1WTUZbaySL09iYoEQpnfhpCf/t3Z/5cnC2WuLlaHp5lR7xQP5+Iz/Hl+6g==
268+
"@topcoder-framework/domain-challenge@^0.22.0":
269+
version "0.22.0"
270+
resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com/npm/topcoder-framework/@topcoder-framework/domain-challenge/-/domain-challenge-0.22.0.tgz#bcb7f7a602e424d9932fd0693935aa5f1f2439a4"
271+
integrity sha512-PT2Zts56QKtntSJQxjH8slRjrYISuUGCZdYmyQcy+ak0nQL0COhQ0puqJ6mfIA9Ml3Ggi8Vmk/G9Ti12h1YNDg==
272272
dependencies:
273273
"@grpc/grpc-js" "^1.8.0"
274-
"@topcoder-framework/client-relational" "^0.18.0"
275-
"@topcoder-framework/lib-common" "^0.18.0"
276-
topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.56-beta-1"
274+
"@topcoder-framework/client-relational" "^0.22.0"
275+
"@topcoder-framework/lib-common" "^0.22.0"
276+
topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.58-beta-1"
277277
tslib "^2.4.1"
278278

279-
"@topcoder-framework/lib-common@^0.18.0":
280-
version "0.18.0"
281-
resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com/npm/topcoder-framework/@topcoder-framework/lib-common/-/lib-common-0.18.0.tgz#ad06f5effbebcb67472cd0c51434ae4415fd9ba1"
282-
integrity sha512-961jxIjgQcSlMfhQCM9bi8A4yjQV88hzAhOM/SO5k40WhnsmiazWwb4+P9asoBie86Z2TpYn1cnP0hNt1IQ3DA==
279+
"@topcoder-framework/lib-common@^0.22.0":
280+
version "0.22.0"
281+
resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com/npm/topcoder-framework/@topcoder-framework/lib-common/-/lib-common-0.22.0.tgz#bd3428b0199410a5151326d1d9731c404c255fb5"
282+
integrity sha512-sHdOAyCGcNaDT9esc9Q3sNaqvVAwHPv6NCTlTAt5O9dcSpdz2AyEur8mS5WccFclKhF5ZB9BM1bbWxO8i9WXGQ==
283283
dependencies:
284284
"@grpc/grpc-js" "^1.8.0"
285285
rimraf "^3.0.2"
286-
topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.56-beta-1"
286+
topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.58-beta-1"
287287
tslib "^2.4.1"
288288

289289
"@types/body-parser@*":
@@ -3999,9 +3999,9 @@ topcoder-bus-api-wrapper@topcoder-platform/tc-bus-api-wrapper.git:
39993999
superagent "^3.8.3"
40004000
tc-core-library-js appirio-tech/tc-core-library-js.git#v2.6.4
40014001

4002-
"topcoder-interface@github:topcoder-platform/plat-interface-definition#v0.0.56-beta-1":
4002+
"topcoder-interface@github:topcoder-platform/plat-interface-definition#v0.0.58-beta-1":
40034003
version "1.0.0"
4004-
resolved "https://codeload.github.com/topcoder-platform/plat-interface-definition/tar.gz/7d743db08b113964d5cd3d52644963af7dde5ba4"
4004+
resolved "https://codeload.github.com/topcoder-platform/plat-interface-definition/tar.gz/474bcfa1d01f0f2d0a2658de21aa835f4c824c44"
40054005

40064006
topo@3.x.x:
40074007
version "3.0.3"

0 commit comments

Comments
 (0)