diff --git a/.circleci/config.yml b/.circleci/config.yml index 95a3f99..245808c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -108,6 +108,7 @@ workflows: only: - develop - CORE-103 + - CORE-65 # Production builds are exectuted only on tagged commits to the testing # master branch. diff --git a/config/default.js b/config/default.js index eb9cf9e..81109ba 100644 --- a/config/default.js +++ b/config/default.js @@ -81,5 +81,7 @@ module.exports = { SUPPORT_EMAIL: process.env.SUPPORT_EMAIL || 'support@topcoder.com' }, + HARMONY_LAMBDA_FUNCTION: process.env.HARMONY_LAMBDA_FUNCTION || 'arn:aws:lambda:us-east-1:811668436784:function:harmony-api-dev-processMessage', + AUTOMATED_TESTING_NAME_PREFIX: process.env.AUTOMATED_TESTING_NAME_PREFIX || 'POSTMANE2E-' } diff --git a/src/common/helper.js b/src/common/helper.js index 17905bd..dcef0f6 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -520,7 +520,44 @@ async function advanceChallengePhase (challengeId, phase, operation, numAttempts } } +const harmonyClient = new AWS.Lambda({ apiVersion: 'latest', maxRetries: 2 }) +/** + * Send event to Harmony. + * @param {String} eventType The event type + * @param {String} payloadType The payload type + * @param {Object} payload The event payload + * @param {Number} billingAccountId The billing account id + * @returns {Promise} + */ +async function sendHarmonyEvent (eventType, payloadType, payload, billingAccountId) { + const event = { + publisher: config.KAFKA_MESSAGE_ORIGINATOR, + timestamp: new Date().getTime(), + eventType, + payloadType, + payload, + billingAccountId + } + + const result = await harmonyClient.invoke({ + FunctionName: config.HARMONY_LAMBDA_FUNCTION, + InvocationType: 'RequestResponse', + Payload: JSON.stringify(event), + LogType: 'None' + }).promise() + + if (result.FunctionError) { + console.error( + 'Failed to send Harmony event', + result.FunctionError, + _.toString(result.Payload) + ) + throw new Error(result.FunctionError) + } +} + module.exports = { + sendHarmonyEvent, wrapExpress, autoWrapExpress, getMemberInfoById, diff --git a/src/services/ResourceRoleService.js b/src/services/ResourceRoleService.js index 1024c3a..4b30999 100644 --- a/src/services/ResourceRoleService.js +++ b/src/services/ResourceRoleService.js @@ -60,6 +60,7 @@ async function createResourceRole (resourceRole) { const entity = await helper.create('ResourceRole', _.assign({ id: uuid(), nameLower }, resourceRole)) const ret = _.pick(entity, payloadFields) await helper.postEvent(config.RESOURCE_ROLE_CREATE_TOPIC, ret) + await helper.sendHarmonyEvent('CREATE', 'ResourceRole', { ...ret, nameLower }) return ret } catch (err) { if (!helper.isCustomError(err)) { @@ -96,6 +97,7 @@ async function updateResourceRole (resourceRoleId, data) { const entity = await helper.update(resourceRole, data) const ret = _.pick(entity, payloadFields) await helper.postEvent(config.RESOURCE_ROLE_UPDATE_TOPIC, ret) + await helper.sendHarmonyEvent('UPDATE', 'ResourceRole', { ...ret, nameLower: data.nameLower }) return ret } catch (err) { if (!helper.isCustomError(err)) { diff --git a/src/services/ResourceService.js b/src/services/ResourceService.js index 49185ba..706e89c 100644 --- a/src/services/ResourceService.js +++ b/src/services/ResourceService.js @@ -379,18 +379,20 @@ async function createResource (currentUser, resource) { createdBy: currentUser.handle || currentUser.sub }, resource)) + const eventPayload = _.pick(ret, payloadFields) // Create resources in ES const esClient = await helper.getESClient() await esClient.create({ index: config.ES.ES_INDEX, type: config.ES.ES_TYPE, id: ret.id, - body: _.pick(ret, payloadFields), + body: eventPayload, refresh: 'true' // refresh ES so that it is visible for read operations instantly }) + await helper.sendHarmonyEvent('CREATE', 'Resource', eventPayload, _.get(challenge, 'billing.billingAccountId')) - logger.debug(`Created resource: ${JSON.stringify(_.pick(ret, payloadFields))}`) - await helper.postEvent(config.RESOURCE_CREATE_TOPIC, _.pick(ret, payloadFields)) + logger.debug(`Created resource: ${JSON.stringify(eventPayload)}`) + await helper.postEvent(config.RESOURCE_CREATE_TOPIC, eventPayload) if (!_.get(challenge, 'task.isTask', false) && resource.roleId === config.SUBMITTER_RESOURCE_ROLE_ID) { const forumUrl = _.get(challenge, 'discussions[0].url') let templateId = config.REGISTRATION_EMAIL.SENDGRID_TEMPLATE_ID @@ -451,7 +453,7 @@ async function deleteResource (currentUser, resource) { try { const challengeId = resource.challengeId - const { allResources, memberId, handle } = await init(currentUser, challengeId, resource) + const { allResources, memberId, handle, challenge } = await init(currentUser, challengeId, resource) const ret = _.reduce(allResources, (result, r) => _.toString(r.memberId) === _.toString(memberId) && r.roleId === resource.roleId ? r : result, @@ -474,6 +476,7 @@ async function deleteResource (currentUser, resource) { logger.debug(`Deleted resource, posting to Bus API: ${JSON.stringify(_.pick(ret, payloadFields))}`) await helper.postEvent(config.RESOURCE_DELETE_TOPIC, _.pick(ret, payloadFields)) + await helper.sendHarmonyEvent('DELETE', 'Resource', { id: ret.id, roleId: ret.roleId, challengeId }, _.get(challenge, 'billing.billingAccountId')) return ret } catch (err) { logger.error(`Delete Resource Error ${JSON.stringify(err)}`)