Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 06e6e07

Browse files
authored
Merge pull request #60 from anonymousjaggu/challenge-changes
changes of challenge
2 parents 6d45e36 + a46540e commit 06e6e07

File tree

6 files changed

+88
-49
lines changed

6 files changed

+88
-49
lines changed

config/default.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ module.exports = {
7777
WEBSITE_SECURE: process.env.WEBSITE_SECURE || 'https://topcoderx.topcoder-dev.com',
7878

7979
ROLE_ID_COPILOT: process.env.ROLE_ID_COPILOT || 'cfe12b3f-2a24-4639-9d8b-ec86726f76bd',
80-
ROLE_ID_SUBMITTER: process.env.ROLE_ID_SUBMITTER || '732339e7-8e30-49d7-9198-cccf9451e221',
80+
ROLE_ID_SUBMITTER: process.env.ROLE_ID_SUBMITTER || '0bc7e20e-cf08-4051-b6e5-421d69e492ac',
8181
TYPE_ID_FIRST2FINISH: process.env.TYPE_ID_FIRST2FINISH || '927abff4-7af9-4145-8ba1-577c16e64e2e',
82-
DEFAULT_TIMELINE_TEMPLATE_ID: process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '7ebf1c69-f62f-4d3a-bdfb-fe9ddb56861c',
83-
DEFAULT_TRACK_ID : process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '9b6fc876-f4d9-4ccb-9dfd-419247628825'
82+
DEFAULT_TIMELINE_TEMPLATE_ID: process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '6969125a-a12f-4b89-8de6-e66b0056f36b',
83+
DEFAULT_TRACK_ID: process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '9b6fc876-f4d9-4ccb-9dfd-419247628825'
8484
};

constants.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,22 @@ const CHALLENGE_STATUS = {
3131

3232
const SERVICE_ERROR_STATUS = 500;
3333

34+
// issue status
35+
const ISSUE_STATUS = {
36+
CHALLENGE_CANCELLED: 'challenge_cancelled',
37+
CHALLENGE_CREATION_PENDING: 'challenge_creation_pending',
38+
CHALLENGE_CREATION_SUCCESSFUL: 'challenge_creation_successful',
39+
CHALLENGE_CREATION_FAILED: 'challenge_creation_failed',
40+
CHALLENGE_CREATION_RETRIED: 'challenge_creation_retried',
41+
CHALLENGE_PAYMENT_SUCCESSFUL: 'challenge_payment_successful',
42+
CHALLENGE_PAYMENT_PENDING: 'challenge_payment_pending',
43+
CHALLENGE_PAYMENT_FAILED: 'challenge_payment_failed'
44+
};
45+
3446
module.exports = {
3547
USER_ROLES,
3648
USER_TYPES,
3749
SERVICE_ERROR_STATUS,
38-
CHALLENGE_STATUS
50+
CHALLENGE_STATUS,
51+
ISSUE_STATUS
3952
};

services/CopilotPaymentService.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ function updateChallengeDetails(payments) {
6363
*/
6464
async function getExistingChallengeIdIfExists(event, dbPayment) {
6565
// check if there is existing active challenge associated with this project
66-
let existingPayments = await dbHelper.scan(models.CopilotPayment, {
66+
const existingPayments = await dbHelper.scan(models.CopilotPayment, {
6767
project: {eq: dbPayment.project},
6868
username: {eq: event.project.copilot},
6969
closed: {eq: 'false'}
7070
});
7171

72-
const payment = _.find(existingPayments, x => x.challengeUUID);
73-
72+
const payment = _.find(existingPayments, (x) => x.challengeUUID);
73+
7474
// if no existing challenge found then it will be created by processor
7575
if (payment) {
7676
// update db payment
@@ -286,7 +286,7 @@ async function handlePaymentUpdates(event) {
286286
},
287287
ExpressionAttributeValues: filterValues
288288
});
289-
289+
290290
if (dbPayments) {
291291
const challengeIds = _(dbPayments).map('challengeUUID').uniq().filter(_.isString)
292292
.value();

services/GithubService.js

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ async function _removeAssignees(github, owner, repo, number, assignees) {
8686
* @returns {string} username if found
8787
*/
8888
async function _getUsernameById(github, id) {
89-
const user = await github.users.getById({ id });
89+
const user = await github.users.getById({id});
9090
return user ? user.data.login : null;
9191
}
9292

@@ -98,11 +98,11 @@ async function _getUsernameById(github, id) {
9898
* @param {string} title new title
9999
*/
100100
async function updateIssue(copilot, repoFullName, number, title) {
101-
Joi.attempt({ copilot, repoFullName, number, title }, updateIssue.schema);
101+
Joi.attempt({copilot, repoFullName, number, title}, updateIssue.schema);
102102
const github = await _authenticate(copilot.accessToken);
103-
const { owner, repo } = _parseRepoUrl(repoFullName);
103+
const {owner, repo} = _parseRepoUrl(repoFullName);
104104
try {
105-
await github.issues.edit({ owner, repo, number, title });
105+
await github.issues.edit({owner, repo, number, title});
106106
} catch (err) {
107107
throw errors.convertGitHubError(err, 'Error occurred during updating issue.');
108108
}
@@ -124,17 +124,17 @@ updateIssue.schema = {
124124
* @param {string} user the user login of assignee
125125
*/
126126
async function assignUser(copilot, repoFullName, number, user) {
127-
Joi.attempt({ copilot, repoFullName, number, user }, assignUser.schema);
127+
Joi.attempt({copilot, repoFullName, number, user}, assignUser.schema);
128128
const github = await _authenticate(copilot.accessToken);
129-
const { owner, repo } = _parseRepoUrl(repoFullName);
129+
const {owner, repo} = _parseRepoUrl(repoFullName);
130130
try {
131-
const issue = await github.issues.get({ owner, repo, number });
131+
const issue = await github.issues.get({owner, repo, number});
132132

133133
const oldAssignees = _(issue.data.assignees).map('login').without(user).value();
134134
if (oldAssignees && oldAssignees.length > 0) {
135135
await _removeAssignees(github, owner, repo, number, oldAssignees);
136136
}
137-
await github.issues.addAssigneesToIssue({ owner, repo, number, assignees: [user] });
137+
await github.issues.addAssigneesToIssue({owner, repo, number, assignees: [user]});
138138
} catch (err) {
139139
throw errors.convertGitHubError(err, 'Error occurred during assigning issue user.');
140140
}
@@ -156,10 +156,10 @@ assignUser.schema = {
156156
* @param {string} user the user login of assignee
157157
*/
158158
async function removeAssign(copilot, repoFullName, number, user) {
159-
Joi.attempt({ copilot, repoFullName, number, user }, removeAssign.schema);
159+
Joi.attempt({copilot, repoFullName, number, user}, removeAssign.schema);
160160

161161
const github = await _authenticate(copilot.accessToken);
162-
const { owner, repo } = _parseRepoUrl(repoFullName);
162+
const {owner, repo} = _parseRepoUrl(repoFullName);
163163
await _removeAssignees(github, owner, repo, number, [user]);
164164
logger.debug(`Github user ${user} is unassigned from issue number ${number}`);
165165
}
@@ -174,12 +174,12 @@ removeAssign.schema = assignUser.schema;
174174
* @param {string} body the comment body text
175175
*/
176176
async function createComment(copilot, repoFullName, number, body) {
177-
Joi.attempt({ copilot, repoFullName, number, body }, createComment.schema);
177+
Joi.attempt({copilot, repoFullName, number, body}, createComment.schema);
178178
const github = await _authenticate(copilot.accessToken);
179-
const { owner, repo } = _parseRepoUrl(repoFullName);
179+
const {owner, repo} = _parseRepoUrl(repoFullName);
180180
try {
181181
body = helper.prepareAutomatedComment(body, copilot);
182-
await github.issues.createComment({ owner, repo, number, body });
182+
await github.issues.createComment({owner, repo, number, body});
183183
} catch (err) {
184184
throw errors.convertGitHubError(err, 'Error occurred during creating comment on issue.');
185185
}
@@ -200,7 +200,7 @@ createComment.schema = {
200200
* @returns {string} the username if found else null
201201
*/
202202
async function getUsernameById(copilot, userId) {
203-
Joi.attempt({ copilot, userId }, getUsernameById.schema);
203+
Joi.attempt({copilot, userId}, getUsernameById.schema);
204204
const github = await _authenticate(copilot.accessToken);
205205
const login = await _getUsernameById(github, userId);
206206
return login;
@@ -218,9 +218,9 @@ getUsernameById.schema = {
218218
* @returns {Number} the user id if found else null
219219
*/
220220
async function getUserIdByLogin(copilot, login) {
221-
Joi.attempt({ copilot, login }, getUserIdByLogin.schema);
221+
Joi.attempt({copilot, login}, getUserIdByLogin.schema);
222222
const github = await _authenticate(copilot.accessToken);
223-
const user = await github.users.getForUser({ username: login });
223+
const user = await github.users.getForUser({username: login});
224224
return user.data ? user.data.id : null;
225225
}
226226

@@ -243,11 +243,11 @@ getUserIdByLogin.schema = {
243243
async function markIssueAsPaid(copilot, repoFullName, number, challengeUUID, existLabels, winner, createCopilotPayments) { // eslint-disable-line max-params
244244
Joi.attempt({copilot, repoFullName, number, challengeUUID, existLabels, winner, createCopilotPayments}, markIssueAsPaid.schema);
245245
const github = await _authenticate(copilot.accessToken);
246-
const { owner, repo } = _parseRepoUrl(repoFullName);
246+
const {owner, repo} = _parseRepoUrl(repoFullName);
247247
const labels = _(existLabels).filter((i) => i !== config.FIX_ACCEPTED_ISSUE_LABEL)
248248
.push(config.FIX_ACCEPTED_ISSUE_LABEL, config.PAID_ISSUE_LABEL).value();
249249
try {
250-
await github.issues.edit({ owner, repo, number, labels });
250+
await github.issues.edit({owner, repo, number, labels});
251251
let commentMessage = '';
252252
commentMessage += `Payment task has been updated: ${config.TC_URL}/challenges/${challengeUUID}\n`;
253253
commentMessage += '*Payments Complete*\n';
@@ -283,11 +283,11 @@ markIssueAsPaid.schema = {
283283
* @param {string} state new state
284284
*/
285285
async function changeState(copilot, repoFullName, number, state) {
286-
Joi.attempt({ copilot, repoFullName, number, state }, changeState.schema);
286+
Joi.attempt({copilot, repoFullName, number, state}, changeState.schema);
287287
const github = await _authenticate(copilot.accessToken);
288-
const { owner, repo } = _parseRepoUrl(repoFullName);
288+
const {owner, repo} = _parseRepoUrl(repoFullName);
289289
try {
290-
await github.issues.edit({ owner, repo, number, state });
290+
await github.issues.edit({owner, repo, number, state});
291291
} catch (err) {
292292
throw errors.convertGitHubError(err, 'Error occurred during updating status of issue.');
293293
}
@@ -309,11 +309,11 @@ changeState.schema = {
309309
* @param {Number} labels the challenge id
310310
*/
311311
async function addLabels(copilot, repoFullName, number, labels) {
312-
Joi.attempt({ copilot, repoFullName, number, labels }, addLabels.schema);
312+
Joi.attempt({copilot, repoFullName, number, labels}, addLabels.schema);
313313
const github = await _authenticate(copilot.accessToken);
314-
const { owner, repo } = _parseRepoUrl(repoFullName);
314+
const {owner, repo} = _parseRepoUrl(repoFullName);
315315
try {
316-
await github.issues.edit({ owner, repo, number, labels });
316+
await github.issues.edit({owner, repo, number, labels});
317317
} catch (err) {
318318
throw errors.convertGitHubError(err, 'Error occurred during adding label in issue.');
319319
}

services/IssueService.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,27 @@ async function ensureChallengeExists(event, issue, create = true) {
7777
logger.debugWithContext(`DB Issue number: ${issue.number}`, event, issue);
7878
logger.debugWithContext(`DB Issue provider: ${issue.provider}`, event, issue);
7979
logger.debugWithContext(`DB Issue repository: ${issue.repositoryId}`, event, issue);
80-
if (dbIssue && dbIssue.status === 'challenge_creation_pending') {
80+
81+
if (dbIssue && dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_CREATION_PENDING) {
8182
logger.debugWithContext('dbIssue is PENDING', event, issue);
8283
throw errors.internalDependencyError(`Challenge for the updated issue ${issue.number} is creating, rescheduling this event`);
8384
}
84-
if (dbIssue && dbIssue.status === 'challenge_creation_failed') {
85+
const hasOpenForPickupLabel = _(issue.labels).includes(config.OPEN_FOR_PICKUP_ISSUE_LABEL);
86+
if (dbIssue && dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_CREATION_FAILED && hasOpenForPickupLabel) {
8587
// remove issue from db
8688
await dbHelper.removeIssue(models.Issue, issue.repositoryId, issue.number, issue.provider);
8789
dbIssue = null;
8890
}
91+
if (dbIssue && dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_CANCELLED) {
92+
dbIssue = null;
93+
}
8994

9095
if (!dbIssue && create) {
9196
logger.debugWithContext('dbIssue is NULL, process to create new record and challenge', event, issue);
9297

9398
await handleIssueCreate(event, issue, true);
9499
dbIssue = await dbHelper.queryOneIssue(models.Issue, issue.repositoryId, issue.number, issue.provider);
95-
logger.debugWithContext(`dbIssue is CREATED ${dbIssue ? 'Succesfully' : 'Failed'}`, event, issue);
100+
logger.debugWithContext(`dbIssue is CREATED ${dbIssue ? 'Successfully' : 'Failed'}`, event, issue);
96101
}
97102
return dbIssue;
98103
}
@@ -384,26 +389,39 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
384389
event.dbIssue = dbIssue;
385390

386391
// if the issue has payment success or payment pending status, we'll ignore this process.
387-
if (dbIssue && dbIssue.status === 'challenge_payment_successful') {
392+
if (dbIssue && dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_PAYMENT_SUCCESSFUL) {
388393
logger.debugWithContext('Ignoring close issue processing. The issue has challenge_payment_successful.', event, issue);
389394
return;
390395
}
391-
if (dbIssue && dbIssue.status === 'challenge_payment_pending') {
396+
if (dbIssue && dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_PAYMENT_PENDING) {
392397
logger.debugWithContext('Ignoring close issue processing. The issue has challenge_payment_pending.', event, issue);
393398
return;
394399
}
395400

396401
if (!event.paymentSuccessful) {
397402
let closeChallenge = false;
398-
// if issue is closed without Fix accepted label
399-
if (!_.includes(event.data.issue.labels, config.FIX_ACCEPTED_ISSUE_LABEL) || _.includes(event.data.issue.labels, config.CANCELED_ISSUE_LABEL)) {
403+
// if issue is closed without Fix accepted and cancel label
404+
if (!_.includes(event.data.issue.labels, config.FIX_ACCEPTED_ISSUE_LABEL) && !_.includes(event.data.issue.labels, config.CANCELED_ISSUE_LABEL)) {
400405
logger.debugWithContext(`This issue ${issue.number} is closed without fix accepted label.`, event, issue);
401406
let comment = 'This ticket was not processed for payment. If you would like to process it for payment,';
402407
comment += ' please reopen it, add the ```' + config.FIX_ACCEPTED_ISSUE_LABEL + '``` label, and then close it again';// eslint-disable-line
403408
await gitHelper.createComment(event, issue.number, comment);
404409
closeChallenge = true;
405410
}
406411

412+
// if issue is close with cancelled label
413+
if (_.includes(event.data.issue.labels, config.CANCELED_ISSUE_LABEL)) {
414+
const comment = `Challenge ${dbIssue.challengeUUID} has been cancelled`;
415+
await topcoderApiHelper.cancelPrivateContent(dbIssue.challengeUUID);
416+
await gitHelper.createComment(event, issue.number, comment);
417+
// update the issue status to payment pending to prevent double processing.
418+
await dbHelper.update(models.Issue, dbIssue.id, {
419+
status: constants.ISSUE_STATUS.CHALLENGE_CANCELLED,
420+
updatedAt: new Date()
421+
});
422+
closeChallenge = true;
423+
}
424+
407425
if (issue.prizes[0] === 0) {
408426
closeChallenge = true;
409427
}
@@ -437,7 +455,7 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
437455

438456
// update the issue status to payment pending to prevent double processing.
439457
await dbHelper.update(models.Issue, dbIssue.id, {
440-
status: 'challenge_payment_pending',
458+
status: constants.ISSUE_STATUS.CHALLENGE_PAYMENT_PENDING,
441459
updatedAt: new Date()
442460
});
443461

@@ -503,7 +521,7 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
503521
// update the issue status to payment failed
504522
if (!event.paymentSuccessful && dbIssue && dbIssue.id) {
505523
await dbHelper.update(models.Issue, dbIssue.id, {
506-
status: 'challenge_payment_failed',
524+
status: constants.ISSUE_STATUS.CHALLENGE_PAYMENT_FAILED,
507525
updatedAt: new Date()
508526
});
509527
}
@@ -520,7 +538,7 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
520538
.value();
521539
dbIssue = await dbHelper.update(models.Issue, dbIssue.id, {
522540
labels,
523-
status: 'challenge_payment_successful',
541+
status: constants.ISSUE_STATUS.CHALLENGE_PAYMENT_SUCCESSFUL,
524542
updatedAt: new Date()
525543
});
526544
await gitHelper.markIssueAsPaid(event, issue.number, dbIssue.challengeUUID, labels, event.assigneeMember.topcoderUsername,
@@ -552,7 +570,7 @@ async function handleIssueCreate(event, issue, forceAssign = false) {
552570
// Check if duplicated
553571
let dbIssue = await dbHelper.queryOneIssue(models.Issue, issue.repositoryId, issue.number, issue.provider);
554572

555-
if (dbIssue) {
573+
if (dbIssue && dbIssue.status !== constants.ISSUE_STATUS.CHALLENGE_CANCELLED) {
556574
throw new Error(
557575
`Issue ${issue.number} is already in ${dbIssue.status}`);
558576
}
@@ -573,9 +591,17 @@ async function handleIssueCreate(event, issue, forceAssign = false) {
573591
// create issue with challenge creation pending
574592
const issueObject = _.assign({}, _.omit(issue, 'assignee'), {
575593
id: helper.generateIdentifier(),
576-
status: 'challenge_creation_pending'
594+
status: constants.ISSUE_STATUS.CHALLENGE_CREATION_PENDING
577595
});
578-
dbIssue = await dbHelper.create(models.Issue, issueObject);
596+
597+
if (!dbIssue) {
598+
dbIssue = await dbHelper.create(models.Issue, issueObject);
599+
} else if (dbIssue && dbIssue.status !== 'challenge_cancelled') {
600+
await dbHelper.update(models.Issue, dbIssue.id, {
601+
status: constants.ISSUE_STATUS.CHALLENGE_CREATION_PENDING,
602+
updatedAt: new Date()
603+
});
604+
}
579605

580606
const projectId = project.tcDirectId;
581607

@@ -593,7 +619,7 @@ async function handleIssueCreate(event, issue, forceAssign = false) {
593619
// update db payment
594620
await dbHelper.update(models.Issue, dbIssue.id, {
595621
challengeUUID: issue.challengeUUID,
596-
status: 'challenge_creation_successful',
622+
status: constants.ISSUE_STATUS.CHALLENGE_CREATION_SUCCESSFUL,
597623
updatedAt: new Date()
598624
});
599625
} catch (e) {

utils/topcoder-api-helper.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ async function cancelPrivateContent(id) {
386386

387387
loggerFile.info(`EndPoint: PATCH /challenges/${id}, PATCH parameters: { status: '${constants.CHALLENGE_STATUS.CANCELED}' }, Status Code:null,
388388
Error: 'Failed to cancel challenge.', Details: ${circularJSON.stringify(err)}`);
389-
throw errors.convertTopcoderApiError(err, 'Failed to activate challenge.');
389+
throw errors.convertTopcoderApiError(err, 'Failed to cancel challenge.');
390390
}
391391
}
392392

@@ -426,9 +426,9 @@ async function removeResourceToChallenge(id, handle, roleId) {
426426
DELETE parameters: null, Status Code:${statusCode}, Response:${circularJSON.stringify(response.data)}`);
427427
} catch (err) {
428428
loggerFile.info(`EndPoint: DELETE /resources, DELETE parameters: null, Status Code:null,
429-
Error: 'Failed to add resource to the challenge.', Details: ${circularJSON.stringify(err)}`);
429+
Error: 'Failed to remove resource from the challenge.', Details: ${circularJSON.stringify(err)}`);
430430
logger.error(`Response Data: ${JSON.stringify(err.response.data)}`);
431-
throw errors.convertTopcoderApiError(err, 'Failed to add resource to the challenge.');
431+
throw errors.convertTopcoderApiError(err, 'Failed to remove resource from the challenge.');
432432
}
433433
}
434434

0 commit comments

Comments
 (0)