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

Commit d236550

Browse files
committed
1 parent c80a4bb commit d236550

13 files changed

+237
-76
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ The following config parameters are supported, they are defined in `config/defau
5050
|AUTH0_CLIENT_ID| The Auth0 ClientID for generating Machine-to-machine token ||
5151
|AUTH0_CLIENT_SECRET| The Auth0 Client Secret for generating Machine-to-machine token ||
5252
|ROLE_ID_COPILOT| The registered role id of copilot ||
53+
|ROLE_ID_ITERATIVE_REVIEWER| The registered role id of iterative reviewer ||
5354
|ROLE_ID_SUBMITTER| The registered role id of submitter ||
5455
|TYPE_ID_TASK| The registered type id of a task ||
5556
|DEFAULT_TIMELINE_TEMPLATE_ID| The default timeline template id ||

config/default.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ module.exports = {
6464
WEBSITE_SECURE: process.env.WEBSITE_SECURE || 'https://topcoderx.topcoder-dev.com',
6565

6666
ROLE_ID_COPILOT: process.env.ROLE_ID_COPILOT || 'cfe12b3f-2a24-4639-9d8b-ec86726f76bd',
67+
ROLE_ID_ITERATIVE_REVIEWER: process.env.ROLE_ID_ITERATIVE_REVIEWER || 'f6df7212-b9d6-4193-bfb1-b383586fce63',
6768
ROLE_ID_SUBMITTER: process.env.ROLE_ID_SUBMITTER || '732339e7-8e30-49d7-9198-cccf9451e221',
6869
TYPE_ID_TASK: process.env.TYPE_ID_TASK || 'ecd58c69-238f-43a4-a4bb-d172719b9f31',
6970
DEFAULT_TIMELINE_TEMPLATE_ID: process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '53a307ce-b4b3-4d6f-b9a1-3741a58f77e6',

configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ The following config parameters are supported, they are defined in `config/defau
3535
|AUTH0_CLIENT_ID| The Auth0 ClientID for generating Machine-to-machine token ||
3636
|AUTH0_CLIENT_SECRET| The Auth0 Client Secret for generating Machine-to-machine token ||
3737
|ROLE_ID_COPILOT| The registered role id of copilot ||
38+
|ROLE_ID_ITERATIVE_REVIEWER| The registered role id of iterative reviewer ||
3839
|ROLE_ID_SUBMITTER| The registered role id of submitter ||
3940
|TYPE_ID_TASK| The registered type id of a task ||
4041
|DEFAULT_TIMELINE_TEMPLATE_ID| The default timeline template id ||

models/Issue.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const schema = new Schema({
4343
required: true,
4444
index: {
4545
global: true,
46-
rangeKey: 'id',
46+
rangeKey: 'number',
4747
project: true,
4848
name: 'RepositoryIdIndex'
4949
}

models/Project.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@ const schema = new Schema({
2121
title: {type: String, required: true},
2222
tcDirectId: {
2323
type: Number,
24+
required: true
25+
},
26+
repoUrl: {
27+
type: String,
2428
required: true,
2529
index: {
2630
global: true,
27-
rangeKey: 'id',
31+
rangeKey: 'archived',
2832
project: true,
29-
name: 'TcDirectIdIndex'
33+
name: 'RepoUrlIndex'
3034
}
3135
},
32-
repoUrl: {type: String, required: true},
3336
repoId: {type: String, required: false},
3437
rocketChatWebhook: {type: String, required: false},
3538
rocketChatChannelName: {type: String, required: false},

models/User.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const schema = new Schema({
3737
required: true,
3838
index: {
3939
global: true,
40-
rangeKey: 'id',
40+
rangeKey: 'type',
4141
project: true,
4242
name: 'UsernameIndex'
4343
}

models/UserMapping.js

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,42 @@ const schema = new Schema({
2323
name: 'TopcoderUsernameIndex'
2424
}
2525
},
26-
githubUsername: String,
27-
gitlabUsername: String,
28-
githubUserId: Number,
29-
gitlabUserId: Number
26+
githubUsername: {
27+
type: String,
28+
index: {
29+
global: true,
30+
project: true,
31+
rangKey: 'id',
32+
name: 'GithubUsernameIndex'
33+
}
34+
},
35+
gitlabUsername: {
36+
type: String,
37+
index: {
38+
global: true,
39+
project: true,
40+
rangKey: 'id',
41+
name: 'GitlabUsernameIndex'
42+
}
43+
},
44+
githubUserId: {
45+
type: Number,
46+
index: {
47+
global: true,
48+
project: true,
49+
rangKey: 'id',
50+
name: 'GithubUserIdIndex'
51+
}
52+
},
53+
gitlabUserId: {
54+
type: Number,
55+
index: {
56+
global: true,
57+
project: true,
58+
rangKey: 'id',
59+
name: 'GitlabUserIdIndex'
60+
}
61+
}
3062
});
3163

3264
module.exports = schema;

services/EventService.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async function handleEventGracefully(event, data, err) {
5050
// reschedule event
5151
if (event.retryCount < config.RETRY_COUNT) {
5252
logger.debug('Scheduling event for next retry');
53-
const newEvent = { ...event };
53+
const newEvent = {...event};
5454
newEvent.retryCount += 1;
5555
delete newEvent.copilot;
5656
const timeoutKey = setTimeout(async () => {
@@ -79,17 +79,15 @@ async function handleEventGracefully(event, data, err) {
7979
} else if (event.event === 'issue.created') {
8080
if (err.name === 'ProcessorError' && err.statusCode && err.message) {
8181
// comment for challenge creation failed
82-
comment = `[${err.statusCode}]: ${err.message}`
82+
comment = `[${err.statusCode}]: ${err.message}`;
8383
} else {
8484
// comment for challenge creation failed
8585
comment = 'The challenge creation on the Topcoder platform failed. Please contact support to try again';
8686
}
8787
} else if (event.event === 'copilotPayment.add') {
8888
// comment for copilot payment challenge create failed
8989
comment = 'The copilot payment challenge creation on the Topcoder platform failed. Please contact support to try again';
90-
await dbHelper.remove(models.CopilotPayment, {
91-
id: { eq: data.id }
92-
});
90+
await dbHelper.removeCopilotPayment(models.CopilotPayment, data.id);
9391
// we dont need to put comment for copilot payment
9492
return;
9593
}

services/GithubService.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function _parseRepoUrl(fullName) {
3333
const results = fullName.split('/');
3434
const repo = results[results.length - 1];
3535
const owner = _(results).slice(0, results.length - 1).join('/');
36-
return { owner, repo };
36+
return {owner, repo};
3737
}
3838

3939
/**

services/IssueService.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,7 @@ async function ensureChallengeExists(event, issue, create = true) {
108108
*/
109109
async function getProjectDetail(event) {
110110
const fullRepoUrl = gitHelper.getFullRepoUrl(event);
111-
const project = await dbHelper.scanOne(models.Project, {
112-
repoUrl: fullRepoUrl,
113-
archived: 'false'
114-
});
111+
const project = await dbHelper.queryOneActiveProject(models.Project, fullRepoUrl);
115112

116113
return project;
117114
}
@@ -202,7 +199,11 @@ async function handleIssueAssignment(event, issue, force = false) {
202199
}
203200
return;
204201
}
205-
202+
// if the issue has payment success we'll ignore this process.
203+
if (dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_PAYMENT_SUCCESSFUL) {
204+
logger.debugWithContext('Ignoring this issue processing. The issue has challenge_payment_successful.', event, issue);
205+
return;
206+
}
206207
// Handle multiple assignees. TC-X allows only one assignee.
207208
if (event.data.issue.assignees && event.data.issue.assignees.length > 1) {
208209
const comment = 'Topcoder-X only supports a single assignee on a ticket to avoid issues with payment';
@@ -332,7 +333,11 @@ async function handleIssueUpdate(event, issue) {
332333
}
333334
return;
334335
}
335-
336+
// if the issue has payment success we'll ignore this process.
337+
if (dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_PAYMENT_SUCCESSFUL) {
338+
logger.debugWithContext('Ignoring this issue processing. The issue has challenge_payment_successful.', event, issue);
339+
return;
340+
}
336341
if (dbIssue.title === issue.title &&
337342
dbIssue.body === issue.body &&
338343
dbIssue.prizes.length === issue.prizes.length &&
@@ -410,7 +415,7 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
410415
let comment = 'This ticket was not processed for payment. If you would like to process it for payment,';
411416
comment += ' please reopen it, add the ```' + config.FIX_ACCEPTED_ISSUE_LABEL + '``` label, and then close it again';// eslint-disable-line
412417
await gitHelper.createComment(event, issue.number, comment);
413-
closeChallenge = true;
418+
return;
414419
}
415420

416421
// if issue is close with cancelled label
@@ -493,8 +498,8 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
493498
event.createCopilotPayments = createCopilotPayments;
494499

495500
if (createCopilotPayments) {
496-
logger.debugWithContext(`Setting copilot payment`);
497-
501+
logger.debugWithContext('Setting copilot payment');
502+
498503
const updateBody = {
499504
prizeSets: [{
500505
type: 'placement',
@@ -504,13 +509,11 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
504509
type: 'copilot',
505510
prizes: [{type: 'USD', value: 40}]
506511
}
507-
]
512+
]
508513
};
509514
await topcoderApiHelper.updateChallenge(dbIssue.challengeUUID, updateBody);
510-
511-
}
512-
else {
513-
logger.debugWithContext('Create copilot payments is unchecked on the Topcoder-X project setup, so skipping', event, issue);
515+
} else {
516+
logger.debugWithContext('Create copilot payments is unchecked on the Topcoder-X project setup, so skipping', event, issue);
514517
}
515518

516519
logger.debugWithContext(`Getting the topcoder member ID for member name: ${assigneeMember.topcoderUsername}`, event, issue);
@@ -525,15 +528,6 @@ async function handleIssueClose(event, issue) { // eslint-disable-line
525528
logger.debugWithContext('Assignee is already set, so skipping', event, issue);
526529
}
527530

528-
// activate challenge
529-
530-
if (challenge.status === 'Draft') {
531-
await topcoderApiHelper.activateChallenge(dbIssue.challengeUUID);
532-
//HACK - sleep 30 seconds so the legacy processor has time to "catch up"
533-
// logger.debugWithContext('Sleeping for 1 seconds after activation so everything propagates...', event, issue);
534-
// await new Promise(resolve => setTimeout(resolve, 1000));
535-
}
536-
537531
logger.debugWithContext(`Closing challenge with winner ${assigneeMember.topcoderUsername}(${winnerId})`, event, issue);
538532
await topcoderApiHelper.closeChallenge(dbIssue.challengeUUID, winnerId, assigneeMember.topcoderUsername);
539533
event.paymentSuccessful = true;
@@ -644,11 +638,11 @@ async function handleIssueCreate(event, issue, forceAssign = false) {
644638
status: constants.ISSUE_STATUS.CHALLENGE_CREATION_SUCCESSFUL,
645639
updatedAt: new Date()
646640
});
647-
641+
648642
logger.debugWithContext(`Adding copilot to issue: ${event.copilot.topcoderUsername}`, event, issue);
649643
// get copilot tc user id
650644
await topcoderApiHelper.addResourceToChallenge(issue.challengeUUID, event.copilot.topcoderUsername, config.ROLE_ID_COPILOT);
651-
645+
await topcoderApiHelper.addResourceToChallenge(issue.challengeUUID, event.copilot.topcoderUsername, config.ROLE_ID_ITERATIVE_REVIEWER);
652646
} catch (e) {
653647
logger.error(`Challenge creation failure: ${e}`);
654648
delete issueCreationLock[creationLockKey];
@@ -698,6 +692,11 @@ async function handleIssueLabelUpdated(event, issue) {
698692
logger.debugWithContext('DB record not found. Issue label update ignored.', event, issue);
699693
return;
700694
}
695+
// if the issue has payment success we'll ignore this process.
696+
if (dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_PAYMENT_SUCCESSFUL) {
697+
logger.debugWithContext('Ignoring this issue processing. The issue has challenge_payment_successful.', event, issue);
698+
return;
699+
}
701700
await dbHelper.update(models.Issue, dbIssue.id, {
702701
labels: issue.labels,
703702
updatedAt: new Date()
@@ -720,6 +719,11 @@ async function handleIssueUnAssignment(event, issue) {
720719
// Ignore it.
721720
return;
722721
}
722+
// if the issue has payment success we'll ignore this process.
723+
if (dbIssue.status === constants.ISSUE_STATUS.CHALLENGE_PAYMENT_SUCCESSFUL) {
724+
logger.debugWithContext('Ignoring this issue processing. The issue has challenge_payment_successful.', event, issue);
725+
return;
726+
}
723727
if (dbIssue.assignee) {
724728
const assigneeUserId = await gitHelper.getUserIdByLogin(event, dbIssue.assignee);
725729
if (!assigneeUserId) {
@@ -861,10 +865,7 @@ async function process(event) {
861865
const fullRepoUrl = gitHelper.getFullRepoUrl(event);
862866
event.data.repository.repoUrl = fullRepoUrl;
863867

864-
const project = await dbHelper.scanOne(models.Project, {
865-
repoUrl: fullRepoUrl,
866-
archived: 'false'
867-
});
868+
const project = await dbHelper.queryOneActiveProject(models.Project, fullRepoUrl);
868869

869870
issue.projectId = project.id;
870871

services/UserService.js

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,20 @@ async function getTCUserName(provider, gitUser) {
2828
const criteria = {};
2929
if (_.isNumber(gitUser) || v.isUUID(gitUser)) {
3030
if (provider === 'github') {
31-
criteria.githubUserId = gitUser;
31+
return await dbHelper.queryOneUserMappingByGithubUserId(models.UserMapping, gitUser);
3232
} else if (provider === 'gitlab') {
33-
criteria.gitlabUserId = gitUser;
33+
return await dbHelper.queryOneUserMappingByGitlabUserId(models.UserMapping, gitUser);
3434
}
3535
} else if (_.isString(gitUser) || v.isEmail(gitUser)) {
3636
if (provider === 'github') {
37-
criteria.githubUsername = gitUser;
37+
return await dbHelper.queryOneUserMappingByGithubUsername(models.UserMapping, gitUser);
3838
} else if (provider === 'gitlab') {
39-
criteria.gitlabUsername = gitUser;
39+
return await dbHelper.queryOneUserMappingByGitlabUsername(models.UserMapping, gitUser);
4040
}
4141
}
4242
if (_.isEmpty(criteria)) {
4343
throw new Error('Can\'t find the TCUserName. Invalid gitUser.');
4444
}
45-
return await dbHelper.scanOne(models.UserMapping, criteria);
4645
}
4746

4847
getTCUserName.schema = {
@@ -65,19 +64,16 @@ async function getRepositoryCopilotOrOwner(provider, repoFullName) {
6564
} else if (provider === 'gitlab') {
6665
fullRepoUrl = `${config.GITLAB_API_BASE_URL}/${repoFullName}`;
6766
}
68-
const project = await dbHelper.scanOne(models.Project, {
69-
repoUrl: fullRepoUrl
70-
});
67+
const project = await dbHelper.queryOneActiveProject(models.Project, fullRepoUrl);
7168

7269
const hasCopilot = project.copilot !== undefined; // eslint-disable-line no-undefined
7370
if (!project || !project.owner) {
7471
// throw this repo is not managed by Topcoder x tool
7572
throw new Error(`This repository '${repoFullName}' is not managed by Topcoder X tool.`);
7673
}
7774

78-
const userMapping = await dbHelper.scanOne(models.UserMapping, {
79-
topcoderUsername: {eq: hasCopilot ? project.copilot.toLowerCase() : project.owner.toLowerCase()}
80-
});
75+
const userMapping = await dbHelper.queryOneUserMappingByTCUsername(
76+
models.UserMapping, hasCopilot ? project.copilot.toLowerCase() : project.owner.toLowerCase());
8177

8278
logger.debug('userMapping');
8379
logger.debug(userMapping);
@@ -87,11 +83,8 @@ async function getRepositoryCopilotOrOwner(provider, repoFullName) {
8783
(provider === 'gitlab' && !userMapping.gitlabUserId)) {
8884
throw new Error(`Couldn't find githost username for '${provider}' for this repository '${repoFullName}'.`);
8985
}
90-
const user = await dbHelper.scanOne(models.User, {
91-
username: provider === 'github' ? userMapping.githubUsername : // eslint-disable-line no-nested-ternary
92-
userMapping.gitlabUsername,
93-
type: provider
94-
});
86+
const user = await dbHelper.queryOneUserByType(models.User,
87+
provider === 'github' ? userMapping.githubUsername : userMapping.gitlabUsername, provider); // eslint-disable-line no-nested-ternary
9588

9689
if (!user && !hasCopilot) {
9790
// throw no copilot is configured

0 commit comments

Comments
 (0)