diff --git a/config/default.js b/config/default.js index dbbc549..5e16a9b 100644 --- a/config/default.js +++ b/config/default.js @@ -46,7 +46,9 @@ module.exports = { KAFKA_CONSUMER_RULESETS: { // key is Kafka topic name, value is array of ruleset which have key as handler function name defined in src/processors/index.js - 'challenge.notification.events' : [{handleChallenge : {type:'UPDATE_DRAFT_CHALLENGE', roles: ["Submitter" /** Competitor */, "Copilot", "Reviewer"]}}], + 'challenge.notification.events': [{ handleChallenge: { type: 'UPDATE_DRAFT_CHALLENGE', roles: ["Submitter" /** Competitor */, "Copilot", "Reviewer"] } }], + 'notifications.autopilot.events': [{ handleAutoPilot: { phaseTypeName: 'Checkpoint Screening', state: 'START', roles: ["Copilot", "Reviewer"] } }], + 'submission.notification.create': [{ handleSubmission: { resource: 'submission', roles: ["Copilot", "Reviewer"], selfOnly: true /** Submitter only */ } }], //'notifications.community.challenge.created': ['handleChallengeCreated'], //'notifications.community.challenge.phasewarning': ['handleChallengePhaseWarning'], }, diff --git a/src/common/tcApiHelper.js b/src/common/tcApiHelper.js index f666a35..c57d1a2 100644 --- a/src/common/tcApiHelper.js +++ b/src/common/tcApiHelper.js @@ -260,25 +260,30 @@ function* getUsersInfoFromChallenge(challengeId) { /** * Filter associated challenge's user based on criteria - * @param {Array} usersInfo user object array - * @param {Array} filterCriteria on roles + * @param {Array} usersInfo user object array + * @param {Array} filterOnRoles on roles + * @param {Array} filterOnUsers on user's ids * * @returns {Array} of user object */ -function filterChallengeUsers(usersInfo, filterCriteria = []) { - let users = [] - let totaleRoles = [] +function filterChallengeUsers(usersInfo, filterOnRoles = [], filterOnUsers = []) { + const users = [] // filtered users + const rolesAvailable = [] // available roles in challenge api response _.map(usersInfo, (user) => { - let userId = _.get(user, 'properties.External Reference ID') - let role = _.get(user, 'role') - totaleRoles[role] = 1 - if (filterCriteria.length > 0 && _.indexOf(filterCriteria, role) >= 0) { + const userId = parseInt(_.get(user, 'properties.External Reference ID')) + const role = _.get(user, 'role') + + _.indexOf(rolesAvailable, role) == -1 ? rolesAvailable.push(role) : '' + + if (filterOnRoles.length > 0 && _.indexOf(filterOnRoles, role) >= 0) { users.push({ userId: userId }) - } else if (filterCriteria.length == 0) { + } else if (filterOnUsers.length > 0 && _.indexOf(filterOnUsers, userId) >= 0) { + users.push({ userId: userId }) /** Submitter only case */ + } else if (filterOnRoles.length == 0 && filterOnUsers.length == 0) { users.push({ userId: userId }) } }) - logger.info(`Total roles availables in this challenge are: ${_.keys(totaleRoles).join(',')}`) + logger.info(`Total roles available in this challenge are: ${rolesAvailable.join(',')}`) return users } diff --git a/src/processors/challenge/AutoPilotHandler.js b/src/processors/challenge/AutoPilotHandler.js new file mode 100644 index 0000000..47d6e7e --- /dev/null +++ b/src/processors/challenge/AutoPilotHandler.js @@ -0,0 +1,21 @@ +/** + * Challenge Autopilot general handler. + */ +const co = require('co'); +const service = require('../../services/AutoPilotService'); + +/** + * Handle Kafka JSON message of autopilot. + * + * @param {Object} message the Kafka JSON message + * @param {Object} ruleSets + * + * @return {Promise} promise resolved to notifications + */ +const handle = (message, ruleSets) => co(function* () { + return yield service.handle(message, ruleSets); +}); + +module.exports = { + handle, +}; diff --git a/src/processors/challenge/SubmissionHandler.js b/src/processors/challenge/SubmissionHandler.js new file mode 100644 index 0000000..9850563 --- /dev/null +++ b/src/processors/challenge/SubmissionHandler.js @@ -0,0 +1,21 @@ +/** + * Challenge submission general handler. + */ +const co = require('co'); +const service = require('../../services/SubmissionService'); + +/** + * Handle Kafka JSON message of autopilot. + * + * @param {Object} message the Kafka JSON message + * @param {Object} ruleSets + * + * @return {Promise} promise resolved to notifications + */ +const handle = (message, ruleSets) => co(function* () { + return yield service.handle(message, ruleSets); +}); + +module.exports = { + handle, +}; diff --git a/src/processors/index.js b/src/processors/index.js index 3fbc148..af3844c 100644 --- a/src/processors/index.js +++ b/src/processors/index.js @@ -6,10 +6,14 @@ const ChallengeCreatedHandler = require('./challenge/ChallengeCreatedHandler'); const ChallengePhaseWarningHandler = require('./challenge/ChallengePhaseWarningHandler'); const ChallengeHandler = require('./challenge/ChallengeHandler'); +const AutoPilotHandler = require('./challenge/AutoPilotHandler') +const SubmissionHandler = require('./challenge/SubmissionHandler') // Exports module.exports = { handleChallengeCreated: ChallengeCreatedHandler.handle, handleChallengePhaseWarning: ChallengePhaseWarningHandler.handle, handleChallenge: ChallengeHandler.handle, + handleAutoPilot: AutoPilotHandler.handle, + handleSubmission: SubmissionHandler.handle, }; diff --git a/src/services/AutoPilotService.js b/src/services/AutoPilotService.js new file mode 100644 index 0000000..cf616a9 --- /dev/null +++ b/src/services/AutoPilotService.js @@ -0,0 +1,53 @@ +/** + * Autopilot general handler service. + */ + +'use strict'; + +const joi = require('joi'); +const _ = require('lodash') +const logger = require('../common/logger'); +const tcApiHelper = require('../common/tcApiHelper'); + +/** + * Handle autopilot message + * @param {Object} message the Kafka message + * @param {Object} ruleSets + * @returns {Array} the notifications + */ +function* handle(message, ruleSets) { + + if ((message.payload.phaseTypeName === _.get(ruleSets, "phaseTypeName")) + && (message.payload.state === _.get(ruleSets, "state"))) { + const challengeId = message.payload.projectId + const usersInfo = yield tcApiHelper.getUsersInfoFromChallenge(challengeId) + const filerOnRoles = _.get(ruleSets, "roles") + const users = tcApiHelper.filterChallengeUsers(usersInfo, filerOnRoles) + logger.info(`Successfully filetered ${users.length} users on rulesets ${JSON.stringify(filerOnRoles)} `) + // notify users of message + return yield tcApiHelper.notifyUsersOfMessage(users, message); + } + return {} +} + +handle.schema = { + message: joi.object().keys({ + topic: joi.string().required(), + originator: joi.string().required(), + timestamp: joi.date().required(), + 'mime-type': joi.string().required(), + payload: joi.object().keys({ + phaseTypeName: joi.string().required(), + state: joi.string().required(), + projectId: joi.number().integer().min(1) + }).unknown(true).required(), + }).required(), + ruleSets: joi.object() +} + +// Exports +module.exports = { + handle, +} + +logger.buildService(module.exports); diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index 2228663..f50c8fb 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -20,9 +20,9 @@ function* handle(message, ruleSets) { if (message.payload.type === _.get(ruleSets, "type")) { const challengeId = message.payload.data.id const usersInfo = yield tcApiHelper.getUsersInfoFromChallenge(challengeId) - const filerOnRoles = _.get(ruleSets, "roles") - const users = tcApiHelper.filterChallengeUsers(usersInfo, filerOnRoles) - logger.info(`Successfully filetered ${users.length} users on rulesets ${JSON.stringify(filerOnRoles)} `) + const filterOnRoles = _.get(ruleSets, "roles") + const users = tcApiHelper.filterChallengeUsers(usersInfo, filterOnRoles) + logger.info(`Successfully filetered ${users.length} users on rulesets ${JSON.stringify(filterOnRoles)} `) // notify users of message return yield tcApiHelper.notifyUsersOfMessage(users, message); } diff --git a/src/services/SubmissionService.js b/src/services/SubmissionService.js new file mode 100644 index 0000000..3ce3b86 --- /dev/null +++ b/src/services/SubmissionService.js @@ -0,0 +1,56 @@ +/** + * Submission general handler service. + */ + +'use strict'; + +const joi = require('joi'); +const _ = require('lodash') +const logger = require('../common/logger'); +const tcApiHelper = require('../common/tcApiHelper'); + +/** + * Handle submission message + * @param {Object} message the Kafka message + * @param {Object} ruleSets + * @returns {Array} the notifications + */ +function* handle(message, ruleSets) { + + if (message.payload.resource === _.get(ruleSets, "resource")) { + const challengeId = message.payload.challengeId + const usersInfo = yield tcApiHelper.getUsersInfoFromChallenge(challengeId) + + const filterOnUsers = [] + if (_.get(ruleSets, 'selfOnly')) { + const memberId = _.get(message.payload, "memberId") + filterOnUsers.push(memberId) + } + const filterOnRoles = _.get(ruleSets, "roles") + const users = tcApiHelper.filterChallengeUsers(usersInfo, filterOnRoles, filterOnUsers) + logger.info(`Successfully filetered ${users.length} users on rulesets ${JSON.stringify(filterOnRoles)} `) + // notify users of message + return yield tcApiHelper.notifyUsersOfMessage(users, message); + } + return {} +} + +handle.schema = { + message: joi.object().keys({ + topic: joi.string().required(), + originator: joi.string().required(), + timestamp: joi.date().required(), + 'mime-type': joi.string().required(), + payload: joi.object().keys({ + resource: joi.string().required() + }).unknown(true).required(), + }).required(), + ruleSets: joi.object() +} + +// Exports +module.exports = { + handle, +} + +logger.buildService(module.exports);