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

Version 1.2.2 #98

Merged
merged 16 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = {
LOG_LEVEL: process.env.LOG_LEVEL || 'debug',
PARTITION: process.env.PARTITION || 0,
TOPIC: process.env.TOPIC || 'tc-x-events',
TOPIC_NOTIFICATION: process.env.TOPIC_NOTIFICATION || 'notifications.action.create',
KAFKA_OPTIONS: {
connectionString: process.env.KAFKA_URL || 'localhost:9092',
groupId: process.env.KAFKA_GROUP_ID || 'topcoder-x-processor',
Expand All @@ -25,6 +26,11 @@ module.exports = {
passphrase: 'secret', // NOTE:* This configuration specifies the private key passphrase used while creating it.
}
},
MAIL_NOTICIATION: {
type: 'tcx.mail_notification',
sendgridTemplateId: 'xxxxxx',
subject: 'Topcoder X Alert'
},
NEW_CHALLENGE_TEMPLATE: process.env.NEW_CHALLENGE_TEMPLATE || {
status: 'Draft'
},
Expand Down Expand Up @@ -68,5 +74,10 @@ module.exports = {
ROLE_ID_SUBMITTER: process.env.ROLE_ID_SUBMITTER || '732339e7-8e30-49d7-9198-cccf9451e221',
TYPE_ID_TASK: process.env.TYPE_ID_TASK || 'ecd58c69-238f-43a4-a4bb-d172719b9f31',
DEFAULT_TIMELINE_TEMPLATE_ID: process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '53a307ce-b4b3-4d6f-b9a1-3741a58f77e6',
DEFAULT_TRACK_ID: process.env.DEFAULT_TRACK_ID || '9b6fc876-f4d9-4ccb-9dfd-419247628825'
DEFAULT_TRACK_ID: process.env.DEFAULT_TRACK_ID || '9b6fc876-f4d9-4ccb-9dfd-419247628825',
GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION: 3600 * 2,
GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION: 300,
GITLAB_CLIENT_ID: process.env.GITLAB_CLIENT_ID,
GITLAB_CLIENT_SECRET: process.env.GITLAB_CLIENT_SECRET,
GITLAB_OWNER_USER_CALLBACK_URL: process.env.GITLAB_OWNER_USER_CALLBACK_URL
};
3 changes: 3 additions & 0 deletions configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ The following config parameters are supported, they are defined in `config/defau
| NEW_CHALLENGE_DURATION_IN_DAYS | the duration of new challenge | 5 |
|TC_URL| the base URL of topcoder to get the challenge URL| defaults to `https://www.topcoder-dev.com`|
|GITLAB_API_BASE_URL| the URL for gitlab host| defaults to `https://gitlab.com`|
| GITLAB_CLIENT_ID | the GitLab client id | No default - needs to be set up with same value found in topcoder-x-ui |
| GITLAB_CLIENT_SECRET | the GitLab client secret | No default - needs to be set up with same value found in topcoder-x-ui |
| GITLAB_OWNER_USER_CALLBACK_URL | the GitLab callback redirect uri for refreshing copilot token | No default - needs to be set up with same owner user callback value in topcoder-x-ui |
|PAID_ISSUE_LABEL|the label name for paid, should be one of the label configured in topcoder x ui|'tcx_Paid'|
|FIX_ACCEPTED_ISSUE_LABEL|the label name for fix accepted, should be one of the label configured in topcoder x ui|'tcx_FixAccepted'|
|ASSIGNED_ISSUE_LABEL| the label name for assigned, should be one of the label configured in topcoder x ui| 'tcx_Assigned'|
Expand Down
8 changes: 5 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

const config = require('config');
const _ = require('lodash');
const kafka = require('./utils/kafka');
const kafkaConsumer = require('./utils/kafka-consumer');
const logger = require('./utils/logger');

process.on('uncaughtException', (err) => {
Expand All @@ -22,7 +22,9 @@ process.on('unhandledRejection', (err) => {
});

// dump the configuration to logger
const ignoreConfigLog = ['cert', 'key', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET'];
const ignoreConfigLog = ['cert', 'key', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET',
'GITLAB_CLIENT_ID', 'GITLAB_CLIENT_SECRET'];

/**
* Print configs to logger
* @param {Object} params the config params
Expand Down Expand Up @@ -55,4 +57,4 @@ dumpConfigs(config, 0);
logger.debug('--- End of List of Configurations ---');

// run the server
kafka.run();
kafkaConsumer.run();
5 changes: 5 additions & 0 deletions models/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const schema = new Schema({
type: Number,
required: true
},
tags: {
type: String,
required: true,
default: ''
},
rocketChatWebhook: {type: String, required: false},
rocketChatChannelName: {type: String, required: false},
archived: {type: String, required: true},
Expand Down
67 changes: 67 additions & 0 deletions services/ChallengeService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2022 TopCoder, Inc. All rights reserved.
*/
'use strict';

/**
* This service processes incoming pure challenge events.
*
* @author TCSCODER
* @version 1.0
*/
const _ = require('lodash');
const Joi = require('joi');
const logger = require('../utils/logger');
const topcoderApiHelper = require('../utils/topcoder-api-helper');
const dbHelper = require('../utils/db-helper');

/**
* Update challenge tags
* @param {Object} event the event
*/
async function handleChallengeTagsUpdate(event) {
const tags = event.data.tags.split(',');
await Promise.all(
event.data.challengeUUIDsList.map(async (challengeUUIDs) => {
if (_.isString(challengeUUIDs)) { // repoUrl
challengeUUIDs = await dbHelper.queryChallengeUUIDsByRepoUrl(challengeUUIDs);
}
return challengeUUIDs.map(async (challengeUUID) => await topcoderApiHelper.updateChallenge(challengeUUID, {tags}));
}).reduce((a, b) => _.concat(a, b), [])
).then((resps) => {
logger.debug(`handleChallengeTagsUpdate updated ${_.size(resps)} challenges successfully.`);
}).catch((err) => {
logger.error(`handleChallengeTagsUpdate failed. Internal Error: ${err}`);
throw new Error(`handleChallengeTagsUpdate failed. Internal Error: ${err}`);
});
}

/**
* Process pure challenge event.
* @param {Object} event the event
*/
async function process(event) {
Joi.attempt(event, process.schema);

if (event.event === 'challengeTags.update') {
await handleChallengeTagsUpdate(event);
}
}

process.schema = Joi.object().keys({
event: Joi.string().valid('challengeTags.update').required(),
data: Joi.object().keys({
challengeUUIDsList: Joi.array().items(
Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string()))
).required(),
tags: Joi.string().required()
}).required(),
retryCount: Joi.number().integer().default(0).optional()
});


module.exports = {
process
};

logger.buildService(module.exports);
1 change: 1 addition & 0 deletions services/CopilotPaymentService.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ async function handlePaymentAdd(event, payment) {
const newChallenge = {
name: challengeTitle,
projectId: project.tcDirectId,
tags: !!project.tags ? project.tags.split(',') : [],
detailedRequirements: challengeRequirements,
prizes: [payment.amount],
reviewType: 'INTERNAL'
Expand Down
27 changes: 19 additions & 8 deletions services/GithubService.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async function _authenticate(accessToken) {
});
return octokit.rest;
} catch (err) {
throw errors.convertGitHubError(err, 'Failed to authenticate to Github using access token of copilot.');
throw errors.handleGitHubError(err, 'Failed to authenticate to Github using access token of copilot.');
}
}

Expand All @@ -75,7 +75,7 @@ async function _removeAssignees(github, owner, repo, number, assignees) {
assignees
});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during remove assignees from issue.');
throw errors.handleGitHubError(err, 'Error occurred during remove assignees from issue.');
}
}

Expand All @@ -93,6 +93,17 @@ async function _getUsernameById(id) {
return user ? user.login : null;
}

/**
* Get github issue url
* @param {String} repoPath the repo path
* @param {Number} number the issue number
* @returns {String} the url
* @private
*/
function _getIssueUrl(repoPath, number) {
return `https://github.com/${repoPath}/issues/${number}`;
}

/**
* updates the title of github issue
* @param {Object} copilot the copilot
Expand All @@ -107,7 +118,7 @@ async function updateIssue(copilot, repoFullName, number, title) {
try {
await github.issues.update({owner, repo, issue_number: number, title});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during updating issue.');
throw errors.handleGitHubError(err, 'Error occurred during updating issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue title is updated for issue number ${number}`);
}
Expand Down Expand Up @@ -139,7 +150,7 @@ async function assignUser(copilot, repoFullName, number, user) {
}
await github.issues.addAssignees({owner, repo, issue_number: number, assignees: [user]});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during assigning issue user.');
throw errors.handleGitHubError(err, 'Error occurred during assigning issue user.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue with number ${number} is assigned to ${user}`);
}
Expand Down Expand Up @@ -184,7 +195,7 @@ async function createComment(copilot, repoFullName, number, body) {
body = helper.prepareAutomatedComment(body, copilot);
await github.issues.createComment({owner, repo, issue_number: number, body});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during creating comment on issue.');
throw errors.handleGitHubError(err, 'Error occurred during creating comment on issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github comment is added on issue with message: "${body}"`);
}
Expand Down Expand Up @@ -262,7 +273,7 @@ async function markIssueAsPaid(copilot, repoFullName, number, challengeUUID, exi
const body = helper.prepareAutomatedComment(commentMessage, copilot);
await github.issues.createComment({owner, repo, issue_number: number, body});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during updating issue as paid.');
throw errors.handleGitHubError(err, 'Error occurred during updating issue as paid.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue title is updated for as paid and fix accepted for ${number}`);
}
Expand Down Expand Up @@ -291,7 +302,7 @@ async function changeState(copilot, repoFullName, number, state) {
try {
await github.issues.update({owner, repo, issue_number: number, state});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during updating status of issue.');
throw errors.handleGitHubError(err, 'Error occurred during updating status of issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue state is updated to '${state}' for issue number ${number}`);
}
Expand All @@ -317,7 +328,7 @@ async function addLabels(copilot, repoFullName, number, labels) {
try {
await github.issues.update({owner, repo, issue_number: number, labels});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during adding label in issue.');
throw errors.handleGitHubError(err, 'Error occurred during adding label in issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue is updated with new labels for ${number}`);
}
Expand Down
Loading