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

feat: apply skillsets when a challenge is created #115

Merged
merged 3 commits into from
Nov 15, 2023
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
3 changes: 2 additions & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,15 @@ module.exports = {
GRANT_TYPE: 'client_credentials',

// used as base to construct various URLs
WEBSITE_SECURE: process.env.WEBSITE_SECURE || 'https://topcoderx.topcoder-dev.com',
WEBSITE_SECURE: process.env.WEBSITE_SECURE || 'http://topcoderx.topcoder-dev.com',

ROLE_ID_COPILOT: process.env.ROLE_ID_COPILOT || 'cfe12b3f-2a24-4639-9d8b-ec86726f76bd',
ROLE_ID_ITERATIVE_REVIEWER: process.env.ROLE_ID_ITERATIVE_REVIEWER || 'f6df7212-b9d6-4193-bfb1-b383586fce63',
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',
WORK_TYPE_ID: process.env.WORK_TYPE_ID || 'b658b280-6c4d-11e5-9d70-22000b2c9aef',
GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION: 3600 * 2,
GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION: 300,
GITLAB_CLIENT_ID: process.env.GITLAB_CLIENT_ID,
Expand Down
30 changes: 27 additions & 3 deletions models/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Schema = dynamoose.Schema;
* @property {String} id The id.
* @property {String} title The title.
* @property {Number} tcDirectId The tc direct id.
* @property {String} tags The tags.
* @property {Array<{id: string, name: string}>} tags The tags.
* @property {String} rocketChatWebhook The rocket chat webhook.
* @property {String} rocketChatChannelName The rocket chat channel name.
* @property {String} archived The archived.
Expand All @@ -41,9 +41,33 @@ const schema = new Schema({
required: true
},
tags: {
type: String,
type: 'list',
list: [{
type: 'map',
map: {
id: {type: String, required: true},
name: {type: String, required: true}
}
}],
required: true,
default: ''
default: [],
fromDynamo(value) {
if (value.S) {
return value.S;
}
if (value.L) {
return value.L.map((item) => {
if (item.M && item.M.name && item.M.id) {
return {
id: item.M.id.S,
name: item.M.name.S
};
}
return null;
});
}
return [];
}
},
rocketChatWebhook: {type: String, required: false},
rocketChatChannelName: {type: String, required: false},
Expand Down
9 changes: 7 additions & 2 deletions services/ChallengeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const dbHelper = require('../utils/db-helper');
* @param {Object} event the event
*/
async function handleChallengeTagsUpdate(event) {
const tags = event.data.tags.split(',');
const tags = event.data.tags.map((tag) => tag.name);
await Promise.all(
event.data.challengeUUIDsList.map(async (challengeUUIDs) => {
if (_.isString(challengeUUIDs)) { // repoUrl
Expand Down Expand Up @@ -54,7 +54,12 @@ process.schema = Joi.object().keys({
challengeUUIDsList: Joi.array().items(
Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string()))
).required(),
tags: Joi.string().required()
tags: Joi.array().items(
Joi.object().keys({
id: Joi.string().required(),
name: Joi.string().required()
})
).required()
}).required(),
retryCount: Joi.number().integer().default(0).optional()
});
Expand Down
5 changes: 4 additions & 1 deletion services/CopilotPaymentService.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ async function handlePaymentAdd(event, payment) {
const newChallenge = {
name: challengeTitle,
projectId: project.tcDirectId,
tags: !!project.tags ? project.tags.split(',') : [],
tags: project.tags ? project.tags.map((tag) => tag.name) : [],
detailedRequirements: challengeRequirements,
prizes: [payment.amount],
reviewType: 'INTERNAL'
Expand All @@ -203,6 +203,9 @@ async function handlePaymentAdd(event, payment) {
// Create a new challenge
const challengeUUID = await topcoderApiHelper.createChallenge(newChallenge);

// Apply skills to the challenge
await topcoderApiHelper.applySkillsSet(challengeUUID, project.tags);

logger.debug(`updating database payment with new challenge id:${challengeUUID}`);

// update db payment
Expand Down
5 changes: 4 additions & 1 deletion services/IssueService.js
Original file line number Diff line number Diff line change
Expand Up @@ -635,11 +635,14 @@ async function handleIssueCreate(event, issue, forceAssign = false) {
issue.challengeUUID = await topcoderApiHelper.createChallenge({
name: issue.title,
projectId,
tags: project.tags ? project.tags.split(',') : [],
tags: project.tags ? project.tags.map((tag) => tag.name) : [],
detailedRequirements: issue.body,
prizes: issue.prizes
});

// Apply skills to the challenge
await topcoderApiHelper.applySkillsSetToChallenge(issue.challengeUUID, project.tags);

// Save
// update db payment
await dbHelper.update(models.Issue, dbIssue.id, {
Expand Down
1 change: 1 addition & 0 deletions utils/db-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ async function acquireLockOnUser(userId, lockId, ttl) {
}
});
}

/**
* Release lock on user
* @param {String} id ID of the user
Expand Down
2 changes: 1 addition & 1 deletion utils/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ logger.logFullError = function logFullError(err, signature) {
if (!err || err.logged) {
return;
}
logger.error(`Error happened in ${signature}\n${err.stack}`);
logger.error(`Error happened in ${signature}\n${err.stack || err.message}`);
err.logged = true;
};

Expand Down
38 changes: 37 additions & 1 deletion utils/topcoder-api-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async function createChallenge(challenge) {
}],
timelineTemplateId: config.DEFAULT_TIMELINE_TEMPLATE_ID,
projectId: challenge.projectId,
tags: challenge.tags,
tags: challenge.tags.map((tag) => tag.name),
trackId: config.DEFAULT_TRACK_ID,
legacy: {
pureV5Task: true
Expand Down Expand Up @@ -163,6 +163,41 @@ async function activateChallenge(id) {
}
}

/**
* Apply skills set to the challenge
* @param {String} challengeId the challenge id
* @param {Array<{id: string, name: string}>} tags the list of tags applied to the challenge
*/
async function applySkillsSetToChallenge(challengeId, tags) {
const apiKey = await getM2Mtoken();
logger.debug(`Applying skills set to the challenge ${challengeId}`);
const url = `${config.TC_API_URL}/standardized-skills/work-skills`;
const payload = {
workId: challengeId,
workTypeId: config.WORK_TYPE_ID,
skillIds: tags.map((tag) => tag.id)
};
const params = {
headers: {
authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
};
try {
const response = await axios.post(url, payload, params);
const statusCode = response.status ? response.status : null;
loggerFile.info(`EndPoint: POST /standardized-skills/work-skills,
POST parameters: ${circularJSON.stringify(payload)}, Status Code:${statusCode}, Response: ${circularJSON.stringify(response.data)}`);
logger.debug(`Skills set applied successfully to the challenge ${challengeId}`);
return response.data;
} catch (err) {
loggerFile.info(`EndPoint: POST /standardized-skills/work-skills, POST parameters: ${circularJSON.stringify(payload)}, Status Code:null,
Error: 'Failed to apply skills set to the challenge.', Details: ${circularJSON.stringify(err)}`);
logger.error(`Response Data: ${JSON.stringify(err.response.data)}`);
throw errors.convertTopcoderApiError(err, 'Failed to apply skills set to the challenge.');
}
}

/**
* Get challenge details by id
* @param {String} id challenge ID
Expand Down Expand Up @@ -511,6 +546,7 @@ module.exports = {
createChallenge,
updateChallenge,
activateChallenge,
applySkillsSetToChallenge,
closeChallenge,
getProjectBillingAccountId,
getTopcoderMemberId,
Expand Down