From 79fdf6fb27b9d13ab25cbc38d3a07d08a8e8fd74 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 2 Jun 2025 16:48:14 +0200 Subject: [PATCH 01/21] feat: get roles by role name --- .../copilotRequest/approveRequest.service.js | 7 +++++++ src/util.js | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index b5164092..e0980b04 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -2,6 +2,7 @@ import _ from 'lodash'; import models from '../../models'; import { COPILOT_REQUEST_STATUS } from '../../constants'; +import util from '../../util'; const resolveTransaction = (transaction, callback) => { if (transaction) { @@ -52,6 +53,12 @@ module.exports = (data, existingTransaction) => { return models.CopilotOpportunity .create(data, { transaction }); })) + .then((opportunity) => { + console.log(opportunity); + const roles = util.getRolesByRoleName('copilot'); + console.log(roles, 'roles by copilot'); + return opportunity; + }) .catch((err) => { transaction.rollback(); return Promise.reject(err); diff --git a/src/util.js b/src/util.js index 43b3c092..5962f419 100644 --- a/src/util.js +++ b/src/util.js @@ -815,6 +815,27 @@ const projectServiceUtils = { } }, + getRolesByRoleName: Promise.coroutine(function* (roleName, logger, requestId) { // eslint-disable-line func-names + try { + const token = yield this.getM2MToken(); + const httpClient = this.getHttpClient({ id: requestId, log: logger }); + return httpClient.get(`${config.identityServiceEndpoint}roles`, { + params: { + filter: `roleName=${roleName}`, + }, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }).then((res) => { + logger.debug(`Roles by ${roleName}: ${JSON.stringify(res.data.result.content)}`); + return _.get(res, 'data.result.content', []).map(r => r.roleName); + }); + } catch (err) { + return Promise.reject(err); + } + }), + /** * Retrieve member details from userIds */ From 4b8c9f71049dafd3ff3f2c0405470421a7fa0219 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 2 Jun 2025 16:54:22 +0200 Subject: [PATCH 02/21] deploy feature branch --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1acd4a4c..5b58794d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -149,7 +149,7 @@ workflows: context : org-global filters: branches: - only: ['develop', 'migration-setup'] + only: ['develop', 'migration-setup', 'pm-1173'] - deployProd: context : org-global filters: From 0c54ecf674f59efc9eceb2b9c286aacb0696fde1 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 2 Jun 2025 17:04:33 +0200 Subject: [PATCH 03/21] deploy feature branch --- src/constants.js | 3 +++ .../copilotRequest/approveRequest.service.js | 4 +++- src/util.js | 23 ++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/constants.js b/src/constants.js index e9362976..4782f307 100644 --- a/src/constants.js +++ b/src/constants.js @@ -301,6 +301,9 @@ export const CONNECT_NOTIFICATION_EVENT = { TOPIC_UPDATED: 'connect.notification.project.topic.updated', POST_CREATED: 'connect.notification.project.post.created', POST_UPDATED: 'connect.notification.project.post.edited', + + // Copilot events + COPILOT_OPPORTUNITY_CREATED: 'connect.notification.project.copilot.opportunity.created', }; export const REGEX = { diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index e0980b04..578cd925 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -56,7 +56,9 @@ module.exports = (data, existingTransaction) => { .then((opportunity) => { console.log(opportunity); const roles = util.getRolesByRoleName('copilot'); - console.log(roles, 'roles by copilot'); + const roleInfo = util.getRoleInfo(roles[0]); + console.log(roles, roleInfo, 'roles by copilot'); + return opportunity; }) .catch((err) => { diff --git a/src/util.js b/src/util.js index 5962f419..4b1fce7e 100644 --- a/src/util.js +++ b/src/util.js @@ -815,6 +815,27 @@ const projectServiceUtils = { } }, + getRoleInfo: Promise.coroutine(function* (roleId, logger, requestId) { // eslint-disable-line func-names + try { + const token = yield this.getM2MToken(); + const httpClient = this.getHttpClient({ id: requestId, log: logger }); + return httpClient.get(`${config.identityServiceEndpoint}roles/${roleId}`, { + params: { + fields: 'subjects' + }, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }).then((res) => { + logger.debug(`Role info by ${roleId}: ${JSON.stringify(res.data.result.content)}`); + return _.get(res, 'data.result.content', []); + }); + } catch (err) { + return Promise.reject(err); + } + }), + getRolesByRoleName: Promise.coroutine(function* (roleName, logger, requestId) { // eslint-disable-line func-names try { const token = yield this.getM2MToken(); @@ -829,7 +850,7 @@ const projectServiceUtils = { }, }).then((res) => { logger.debug(`Roles by ${roleName}: ${JSON.stringify(res.data.result.content)}`); - return _.get(res, 'data.result.content', []).map(r => r.roleName); + return _.get(res, 'data.result.content', []).map(r => r.id); }); } catch (err) { return Promise.reject(err); From 223b7bd8d9ba61b083ef60efd255344c7631515e Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 2 Jun 2025 22:54:39 +0200 Subject: [PATCH 04/21] deploy feature branch --- src/routes/copilotRequest/approveRequest.service.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index 578cd925..b9da5b50 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -53,10 +53,10 @@ module.exports = (data, existingTransaction) => { return models.CopilotOpportunity .create(data, { transaction }); })) - .then((opportunity) => { + .then(async (opportunity) => { console.log(opportunity); - const roles = util.getRolesByRoleName('copilot'); - const roleInfo = util.getRoleInfo(roles[0]); + const roles = await util.getRolesByRoleName('copilot'); + const roleInfo = await util.getRoleInfo(roles[0]); console.log(roles, roleInfo, 'roles by copilot'); return opportunity; From 82dd7978ff0607399c56cef81c3d30ec8d47d2e6 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 2 Jun 2025 23:42:05 +0200 Subject: [PATCH 05/21] deploy feature branch --- src/routes/copilotRequest/approveRequest.js | 2 +- src/routes/copilotRequest/approveRequest.service.js | 6 +++--- src/routes/copilotRequest/create.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/copilotRequest/approveRequest.js b/src/routes/copilotRequest/approveRequest.js index 12fd6a8b..c1371671 100644 --- a/src/routes/copilotRequest/approveRequest.js +++ b/src/routes/copilotRequest/approveRequest.js @@ -35,7 +35,7 @@ module.exports = [ updatedBy: req.authUser.userId, }); - return approveRequest(data) + return approveRequest(req, data) .then(_newCopilotOpportunity => res.status(201).json(_newCopilotOpportunity)) .catch((err) => { if (err.message) { diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index b9da5b50..eb818722 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -12,7 +12,7 @@ const resolveTransaction = (transaction, callback) => { return models.sequelize.transaction(callback); }; -module.exports = (data, existingTransaction) => { +module.exports = (req, data, existingTransaction) => { const { projectId, copilotRequestId } = data; return resolveTransaction(existingTransaction, transaction => @@ -55,8 +55,8 @@ module.exports = (data, existingTransaction) => { })) .then(async (opportunity) => { console.log(opportunity); - const roles = await util.getRolesByRoleName('copilot'); - const roleInfo = await util.getRoleInfo(roles[0]); + const roles = await util.getRolesByRoleName('copilot', req.log, req.id); + const roleInfo = await util.getRoleInfo(roles[0], req.log, req.id); console.log(roles, roleInfo, 'roles by copilot'); return opportunity; diff --git a/src/routes/copilotRequest/create.js b/src/routes/copilotRequest/create.js index 95fa45f2..2b05f524 100644 --- a/src/routes/copilotRequest/create.js +++ b/src/routes/copilotRequest/create.js @@ -98,7 +98,7 @@ module.exports = [ updatedBy: req.authUser.userId, type: copilotRequest.data.projectType, }); - return approveRequest(approveData, transaction).then(() => copilotRequest); + return approveRequest(req, approveData, transaction).then(() => copilotRequest); }).then(copilotRequest => res.status(201).json(copilotRequest)) .catch((err) => { try { From 9793dcc61549c31e6048fcab3bfa9c44171a9530 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 3 Jun 2025 00:46:29 +0200 Subject: [PATCH 06/21] fix: get role by role name --- config/default.json | 1 + config/development.json | 1 + config/production.json | 1 + .../copilotRequest/approveRequest.service.js | 30 ++++++++++++++++--- src/util.js | 4 ++- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/config/default.json b/config/default.json index 43353496..d65b6383 100644 --- a/config/default.json +++ b/config/default.json @@ -54,6 +54,7 @@ "inviteEmailSubject": "You are invited to Topcoder", "inviteEmailSectionTitle": "Project Invitation", "workManagerUrl": "https://challenges.topcoder-dev.com/", + "copilotPortalUrl": "https://copilots.topcoder-dev.com/", "accountsAppUrl": "https://accounts.topcoder-dev.com/", "MAX_REVISION_NUMBER": 100, "UNIQUE_GMAIL_VALIDATION": false, diff --git a/config/development.json b/config/development.json index 5874ef2c..878bc669 100644 --- a/config/development.json +++ b/config/development.json @@ -3,6 +3,7 @@ "pubsubExchangeName": "dev.projects", "attachmentsS3Bucket": "topcoder-dev-media", "workManagerUrl": "https://challenges.topcoder-dev.com/", + "copilotPortalUrl": "https://copilots.topcoder-dev.com/", "fileServiceEndpoint": "https://api.topcoder-dev.com/v5/files", "memberServiceEndpoint": "https://api.topcoder-dev.com/v5/members", "identityServiceEndpoint": "https://api.topcoder-dev.com/v3/", diff --git a/config/production.json b/config/production.json index d784a55e..73399edf 100644 --- a/config/production.json +++ b/config/production.json @@ -1,6 +1,7 @@ { "authDomain": "topcoder.com", "workManagerUrl": "https://challenges.topcoder.com/", + "copilotPortalUrl": "https://copilots.topcoder.com/", "sfdcBillingAccountNameField": "Billing_Account_name__c", "sfdcBillingAccountMarkupField": "Mark_up__c", "sfdcBillingAccountActiveField": "Active__c" diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index eb818722..dc7e5445 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -1,8 +1,10 @@ import _ from 'lodash'; +import config from 'config'; import models from '../../models'; -import { COPILOT_REQUEST_STATUS } from '../../constants'; +import { CONNECT_NOTIFICATION_EVENT, COPILOT_REQUEST_STATUS } from '../../constants'; import util from '../../util'; +import { createEvent } from '../../services/busApi'; const resolveTransaction = (transaction, callback) => { if (transaction) { @@ -54,11 +56,31 @@ module.exports = (req, data, existingTransaction) => { .create(data, { transaction }); })) .then(async (opportunity) => { - console.log(opportunity); const roles = await util.getRolesByRoleName('copilot', req.log, req.id); - const roleInfo = await util.getRoleInfo(roles[0], req.log, req.id); - console.log(roles, roleInfo, 'roles by copilot'); + const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); + req.log.info("getting subjects for roles", roles[0]); + const emailEventType = CONNECT_NOTIFICATION_EVENT.COPILOT_OPPORTUNITY_CREATED; + const copilotPortalUrl = config.get('copilotPortalUrl'); + req.log.info("Sending emails to all copilots about new opportunity"); + subjects.forEach(subject => { + req.log.info("Each copilot members", subject); + createEvent(emailEventType, { + data: { + handle: subject.handle, + opportunityDetailsUrl: `${copilotPortalUrl}/opportunity/${opportunity.id}`, + }, + recipients: [subject.email], + version: 'v3', + from: { + name: config.get('EMAIL_INVITE_FROM_NAME'), + email: config.get('EMAIL_INVITE_FROM_EMAIL'), + }, + categories: [`${process.env.NODE_ENV}:${emailEventType}`.toLowerCase()], + }, req.log); + }); + req.log.info("Finished sending emails to copilots"); + return opportunity; }) .catch((err) => { diff --git a/src/util.js b/src/util.js index 4b1fce7e..80de04a1 100644 --- a/src/util.js +++ b/src/util.js @@ -850,7 +850,9 @@ const projectServiceUtils = { }, }).then((res) => { logger.debug(`Roles by ${roleName}: ${JSON.stringify(res.data.result.content)}`); - return _.get(res, 'data.result.content', []).map(r => r.id); + return _.get(res, 'data.result.content', []) + .filter(item => item.roleName === roleName) + .map(r => r.id); }); } catch (err) { return Promise.reject(err); From 5b29f65fd50dd55a93f5f570adbc8da2933b03e1 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 3 Jun 2025 01:16:58 +0200 Subject: [PATCH 07/21] modified timeout --- src/util.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util.js b/src/util.js index 80de04a1..299da69f 100644 --- a/src/util.js +++ b/src/util.js @@ -840,6 +840,7 @@ const projectServiceUtils = { try { const token = yield this.getM2MToken(); const httpClient = this.getHttpClient({ id: requestId, log: logger }); + httpClient.defaults.timeout = 6000; return httpClient.get(`${config.identityServiceEndpoint}roles`, { params: { filter: `roleName=${roleName}`, From deaed3a9ff7061ebca875ffb84cb5df0b88e9e5b Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Wed, 4 Jun 2025 14:45:29 +0200 Subject: [PATCH 08/21] rebased from develop branch --- src/routes/copilotRequest/approveRequest.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index dc7e5445..34d3cbf2 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -57,8 +57,8 @@ module.exports = (req, data, existingTransaction) => { })) .then(async (opportunity) => { const roles = await util.getRolesByRoleName('copilot', req.log, req.id); - const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); req.log.info("getting subjects for roles", roles[0]); + const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); const emailEventType = CONNECT_NOTIFICATION_EVENT.COPILOT_OPPORTUNITY_CREATED; const copilotPortalUrl = config.get('copilotPortalUrl'); req.log.info("Sending emails to all copilots about new opportunity"); From d4ed7a9fb3899e238a47126f9a8dfbb2aeef7a3e Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Wed, 4 Jun 2025 16:44:13 +0200 Subject: [PATCH 09/21] rebased from develop branch --- src/util.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util.js b/src/util.js index 299da69f..8408654d 100644 --- a/src/util.js +++ b/src/util.js @@ -819,6 +819,7 @@ const projectServiceUtils = { try { const token = yield this.getM2MToken(); const httpClient = this.getHttpClient({ id: requestId, log: logger }); + httpClient.defaults.timeout = 6000; return httpClient.get(`${config.identityServiceEndpoint}roles/${roleId}`, { params: { fields: 'subjects' From 91f23ab9b77505b5c2fbf506e3eaf62ede04b864 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Wed, 4 Jun 2025 17:06:37 +0200 Subject: [PATCH 10/21] rebased from develop branch --- src/util.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/util.js b/src/util.js index 8408654d..049ef68a 100644 --- a/src/util.js +++ b/src/util.js @@ -820,10 +820,8 @@ const projectServiceUtils = { const token = yield this.getM2MToken(); const httpClient = this.getHttpClient({ id: requestId, log: logger }); httpClient.defaults.timeout = 6000; + logger.debug(`${config.identityServiceEndpoint}roles/${roleId}`, "fetching role info"); return httpClient.get(`${config.identityServiceEndpoint}roles/${roleId}`, { - params: { - fields: 'subjects' - }, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, @@ -833,6 +831,7 @@ const projectServiceUtils = { return _.get(res, 'data.result.content', []); }); } catch (err) { + logger.debug(err, "error on getting role info"); return Promise.reject(err); } }), From 31a2b66230ea4b669c9c8c64e9b22757ed1a4678 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Thu, 5 Jun 2025 17:52:10 +0200 Subject: [PATCH 11/21] fix: sync issue --- src/util.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util.js b/src/util.js index 049ef68a..60c71d57 100644 --- a/src/util.js +++ b/src/util.js @@ -822,6 +822,9 @@ const projectServiceUtils = { httpClient.defaults.timeout = 6000; logger.debug(`${config.identityServiceEndpoint}roles/${roleId}`, "fetching role info"); return httpClient.get(`${config.identityServiceEndpoint}roles/${roleId}`, { + params: { + fields: `subjects`, + }, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, From ae5952d9effabded8f703594530c3cb9b9e2f64c Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Thu, 5 Jun 2025 21:19:10 +0200 Subject: [PATCH 12/21] fix: added external action email kaufka type --- src/constants.js | 4 ++-- src/routes/copilotRequest/approveRequest.service.js | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/constants.js b/src/constants.js index f35d1a89..7e20ef93 100644 --- a/src/constants.js +++ b/src/constants.js @@ -303,8 +303,8 @@ export const CONNECT_NOTIFICATION_EVENT = { POST_CREATED: 'connect.notification.project.post.created', POST_UPDATED: 'connect.notification.project.post.edited', - // Copilot events - COPILOT_OPPORTUNITY_CREATED: 'connect.notification.project.copilot.opportunity.created', + // External action email + EXTERNAL_ACTION_EMAIL: 'external.action.email', }; export const REGEX = { diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index 34d3cbf2..a2dfb81a 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -59,23 +59,19 @@ module.exports = (req, data, existingTransaction) => { const roles = await util.getRolesByRoleName('copilot', req.log, req.id); req.log.info("getting subjects for roles", roles[0]); const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); - const emailEventType = CONNECT_NOTIFICATION_EVENT.COPILOT_OPPORTUNITY_CREATED; + const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; const copilotPortalUrl = config.get('copilotPortalUrl'); req.log.info("Sending emails to all copilots about new opportunity"); subjects.forEach(subject => { req.log.info("Each copilot members", subject); createEvent(emailEventType, { data: { - handle: subject.handle, + user_name: subject.handle, opportunityDetailsUrl: `${copilotPortalUrl}/opportunity/${opportunity.id}`, }, + sendgrid_template_id: "d-3efdc91da580479d810c7acd50a4c17f", recipients: [subject.email], - version: 'v3', - from: { - name: config.get('EMAIL_INVITE_FROM_NAME'), - email: config.get('EMAIL_INVITE_FROM_EMAIL'), - }, - categories: [`${process.env.NODE_ENV}:${emailEventType}`.toLowerCase()], + version: '433b1688-c543-4656-a295-efcbea57444d', }, req.log); }); From c16d06ee7596707d82186f0c8a64e3c76e08768c Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Thu, 5 Jun 2025 21:56:25 +0200 Subject: [PATCH 13/21] fix: added external action email kaufka type --- src/routes/copilotRequest/approveRequest.service.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index a2dfb81a..3b79401e 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -62,6 +62,7 @@ module.exports = (req, data, existingTransaction) => { const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; const copilotPortalUrl = config.get('copilotPortalUrl'); req.log.info("Sending emails to all copilots about new opportunity"); + req.log.info(`${copilotPortalUrl}/opportunity/${opportunity.id}`, '`${copilotPortalUrl}/opportunity/${opportunity.id}`'); subjects.forEach(subject => { req.log.info("Each copilot members", subject); createEvent(emailEventType, { From 190c04c3b14f2357a32f50ef1bc9262792ad8e33 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 9 Jun 2025 03:54:03 +0530 Subject: [PATCH 14/21] fix: added external action email kaufka type --- src/routes/copilotRequest/approveRequest.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index 3b79401e..e992dd72 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -67,7 +67,7 @@ module.exports = (req, data, existingTransaction) => { req.log.info("Each copilot members", subject); createEvent(emailEventType, { data: { - user_name: subject.handle, + userName: subject.handle, opportunityDetailsUrl: `${copilotPortalUrl}/opportunity/${opportunity.id}`, }, sendgrid_template_id: "d-3efdc91da580479d810c7acd50a4c17f", From 4c98fe7c655cac3ae3cab776c5391e6588b7fda8 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 06:58:30 +0530 Subject: [PATCH 15/21] fix: added external action email kaufka type --- src/routes/copilotRequest/approveRequest.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index e992dd72..7bab8e1c 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -67,8 +67,8 @@ module.exports = (req, data, existingTransaction) => { req.log.info("Each copilot members", subject); createEvent(emailEventType, { data: { - userName: subject.handle, - opportunityDetailsUrl: `${copilotPortalUrl}/opportunity/${opportunity.id}`, + user_name: subject.handle, + opportunity_details_url: `${copilotPortalUrl}/opportunity/${opportunity.id}`, }, sendgrid_template_id: "d-3efdc91da580479d810c7acd50a4c17f", recipients: [subject.email], From 0ad22c31eeed02676967e7b587b17e1f2d4b91c2 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 07:02:32 +0530 Subject: [PATCH 16/21] fix: added external action email kaufka type --- src/routes/copilotRequest/approveRequest.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index 7bab8e1c..0562c9e2 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -72,7 +72,7 @@ module.exports = (req, data, existingTransaction) => { }, sendgrid_template_id: "d-3efdc91da580479d810c7acd50a4c17f", recipients: [subject.email], - version: '433b1688-c543-4656-a295-efcbea57444d', + version: 'v3', }, req.log); }); From cc5a28d95be2cea5df2dae1bcee89e14b2ab31bf Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 09:25:50 +0530 Subject: [PATCH 17/21] fix: send emails to PMs and creator --- src/routes/copilotOpportunityApply/create.js | 34 +++++++++++++++++-- .../copilotRequest/approveRequest.service.js | 2 -- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/routes/copilotOpportunityApply/create.js b/src/routes/copilotOpportunityApply/create.js index 33daaddb..04867900 100644 --- a/src/routes/copilotOpportunityApply/create.js +++ b/src/routes/copilotOpportunityApply/create.js @@ -1,11 +1,12 @@ import _ from 'lodash'; import validate from 'express-validation'; import Joi from 'joi'; +import config from 'config'; import models from '../../models'; import util from '../../util'; import { PERMISSION } from '../../permissions/constants'; -import { COPILOT_OPPORTUNITY_STATUS } from '../../constants'; +import { CONNECT_NOTIFICATION_EVENT, COPILOT_OPPORTUNITY_STATUS } from '../../constants'; const applyCopilotRequestValidations = { body: Joi.object().keys({ @@ -65,7 +66,36 @@ module.exports = [ } return models.CopilotApplication.create(data) - .then((result) => { + .then(async (result) => { + const pmRole = await util.getRolesByRoleName('Project Manager', req.log, req.id); + const { subjects = [] } = await util.getRoleInfo(pmRole[0], req.log, req.id); + + const creator = await util.getMemberDetailsByUserIds([req.authUser.userId], req.log, req.id); + const listOfSubjects = subjects; + if (creator) { + const isCreatorPartofSubjects = subjects.find(item => item.email === creator[0].email); + if (!isCreatorPartofSubjects) { + listOfSubjects.push({ + email: creator.email, + handle: creator.handle, + }); + } + } + + const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; + const copilotPortalUrl = config.get('copilotPortalUrl'); + listOfSubjects.forEach((subject) => { + createEvent(emailEventType, { + data: { + user_name: subject.handle, + opportunity_details_url: `${copilotPortalUrl}/opportunity/${opportunity.id}#applications`, + }, + sendgrid_template_id: "d-d7c1f48628654798a05c8e09e52db14f", + recipients: [subject.email], + version: 'v3', + }, req.log); + }); + res.status(201).json(result); return Promise.resolve(); }) diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index 0562c9e2..8b46154c 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -57,12 +57,10 @@ module.exports = (req, data, existingTransaction) => { })) .then(async (opportunity) => { const roles = await util.getRolesByRoleName('copilot', req.log, req.id); - req.log.info("getting subjects for roles", roles[0]); const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; const copilotPortalUrl = config.get('copilotPortalUrl'); req.log.info("Sending emails to all copilots about new opportunity"); - req.log.info(`${copilotPortalUrl}/opportunity/${opportunity.id}`, '`${copilotPortalUrl}/opportunity/${opportunity.id}`'); subjects.forEach(subject => { req.log.info("Each copilot members", subject); createEvent(emailEventType, { From b52b16e44dd8b05834163e69464bd8e3d6db9640 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 09:28:53 +0530 Subject: [PATCH 18/21] fix: send emails to PMs and creator --- src/routes/copilotOpportunityApply/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/copilotOpportunityApply/create.js b/src/routes/copilotOpportunityApply/create.js index 04867900..b94a8833 100644 --- a/src/routes/copilotOpportunityApply/create.js +++ b/src/routes/copilotOpportunityApply/create.js @@ -70,7 +70,7 @@ module.exports = [ const pmRole = await util.getRolesByRoleName('Project Manager', req.log, req.id); const { subjects = [] } = await util.getRoleInfo(pmRole[0], req.log, req.id); - const creator = await util.getMemberDetailsByUserIds([req.authUser.userId], req.log, req.id); + const creator = await util.getMemberDetailsByUserIds([opportunity.userId], req.log, req.id); const listOfSubjects = subjects; if (creator) { const isCreatorPartofSubjects = subjects.find(item => item.email === creator[0].email); From 5fbd1974af3b870d471e55a24460e70c5c0799c3 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 14:20:40 +0530 Subject: [PATCH 19/21] fix: send emails to PMs and creator --- src/routes/copilotOpportunityApply/create.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/routes/copilotOpportunityApply/create.js b/src/routes/copilotOpportunityApply/create.js index b94a8833..b7e263ba 100644 --- a/src/routes/copilotOpportunityApply/create.js +++ b/src/routes/copilotOpportunityApply/create.js @@ -7,6 +7,7 @@ import models from '../../models'; import util from '../../util'; import { PERMISSION } from '../../permissions/constants'; import { CONNECT_NOTIFICATION_EVENT, COPILOT_OPPORTUNITY_STATUS } from '../../constants'; +import { createEvent } from '../../services/busApi'; const applyCopilotRequestValidations = { body: Joi.object().keys({ @@ -76,8 +77,8 @@ module.exports = [ const isCreatorPartofSubjects = subjects.find(item => item.email === creator[0].email); if (!isCreatorPartofSubjects) { listOfSubjects.push({ - email: creator.email, - handle: creator.handle, + email: creator[0].email, + handle: creator[0].handle, }); } } From 49356d6e77fd32c7057a5ce8b86ffae82b1292b4 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 16:33:58 +0530 Subject: [PATCH 20/21] fix: review comments --- src/constants.js | 4 ++++ src/routes/copilotOpportunityApply/create.js | 8 ++++---- src/routes/copilotRequest/approveRequest.service.js | 7 +++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/constants.js b/src/constants.js index 7e20ef93..9c96a746 100644 --- a/src/constants.js +++ b/src/constants.js @@ -307,6 +307,10 @@ export const CONNECT_NOTIFICATION_EVENT = { EXTERNAL_ACTION_EMAIL: 'external.action.email', }; +export const TEMPLATE_IDS = { + APPLY_COPILOT: 'd-d7c1f48628654798a05c8e09e52db14f', + CREATE_REQUEST: 'd-3efdc91da580479d810c7acd50a4c17f' +} export const REGEX = { URL: /^(http(s?):\/\/)?(www\.)?[a-zA-Z0-9\.\-\_]+(\.[a-zA-Z]{2,15})+(\:[0-9]{2,5})?(\/[a-zA-Z0-9\_\-\s\.\/\?\%\#\&\=;]*)?$/, // eslint-disable-line }; diff --git a/src/routes/copilotOpportunityApply/create.js b/src/routes/copilotOpportunityApply/create.js index b7e263ba..49e92c2f 100644 --- a/src/routes/copilotOpportunityApply/create.js +++ b/src/routes/copilotOpportunityApply/create.js @@ -6,7 +6,7 @@ import config from 'config'; import models from '../../models'; import util from '../../util'; import { PERMISSION } from '../../permissions/constants'; -import { CONNECT_NOTIFICATION_EVENT, COPILOT_OPPORTUNITY_STATUS } from '../../constants'; +import { CONNECT_NOTIFICATION_EVENT, COPILOT_OPPORTUNITY_STATUS, TEMPLATE_IDS, USER_ROLE } from '../../constants'; import { createEvent } from '../../services/busApi'; const applyCopilotRequestValidations = { @@ -68,13 +68,13 @@ module.exports = [ return models.CopilotApplication.create(data) .then(async (result) => { - const pmRole = await util.getRolesByRoleName('Project Manager', req.log, req.id); + const pmRole = await util.getRolesByRoleName(USER_ROLE.PROJECT_MANAGER, req.log, req.id); const { subjects = [] } = await util.getRoleInfo(pmRole[0], req.log, req.id); const creator = await util.getMemberDetailsByUserIds([opportunity.userId], req.log, req.id); const listOfSubjects = subjects; if (creator) { - const isCreatorPartofSubjects = subjects.find(item => item.email === creator[0].email); + const isCreatorPartofSubjects = subjects.find(item => item.email.toLowerCase() === creator[0].email.toLowerCase()); if (!isCreatorPartofSubjects) { listOfSubjects.push({ email: creator[0].email, @@ -91,7 +91,7 @@ module.exports = [ user_name: subject.handle, opportunity_details_url: `${copilotPortalUrl}/opportunity/${opportunity.id}#applications`, }, - sendgrid_template_id: "d-d7c1f48628654798a05c8e09e52db14f", + sendgrid_template_id: TEMPLATE_IDS.APPLY_COPILOT, recipients: [subject.email], version: 'v3', }, req.log); diff --git a/src/routes/copilotRequest/approveRequest.service.js b/src/routes/copilotRequest/approveRequest.service.js index 8b46154c..d4a2665d 100644 --- a/src/routes/copilotRequest/approveRequest.service.js +++ b/src/routes/copilotRequest/approveRequest.service.js @@ -2,7 +2,7 @@ import _ from 'lodash'; import config from 'config'; import models from '../../models'; -import { CONNECT_NOTIFICATION_EVENT, COPILOT_REQUEST_STATUS } from '../../constants'; +import { CONNECT_NOTIFICATION_EVENT, COPILOT_REQUEST_STATUS, TEMPLATE_IDS, USER_ROLE } from '../../constants'; import util from '../../util'; import { createEvent } from '../../services/busApi'; @@ -56,19 +56,18 @@ module.exports = (req, data, existingTransaction) => { .create(data, { transaction }); })) .then(async (opportunity) => { - const roles = await util.getRolesByRoleName('copilot', req.log, req.id); + const roles = await util.getRolesByRoleName(USER_ROLE.TC_COPILOT, req.log, req.id); const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; const copilotPortalUrl = config.get('copilotPortalUrl'); req.log.info("Sending emails to all copilots about new opportunity"); subjects.forEach(subject => { - req.log.info("Each copilot members", subject); createEvent(emailEventType, { data: { user_name: subject.handle, opportunity_details_url: `${copilotPortalUrl}/opportunity/${opportunity.id}`, }, - sendgrid_template_id: "d-3efdc91da580479d810c7acd50a4c17f", + sendgrid_template_id: TEMPLATE_IDS.CREATE_REQUEST, recipients: [subject.email], version: 'v3', }, req.log); From e34f785116019a2183a60d5ca7b2e97b73a82734 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Tue, 10 Jun 2025 16:35:06 +0530 Subject: [PATCH 21/21] fix: review comments --- src/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.js b/src/constants.js index 9c96a746..02a8db53 100644 --- a/src/constants.js +++ b/src/constants.js @@ -309,7 +309,7 @@ export const CONNECT_NOTIFICATION_EVENT = { export const TEMPLATE_IDS = { APPLY_COPILOT: 'd-d7c1f48628654798a05c8e09e52db14f', - CREATE_REQUEST: 'd-3efdc91da580479d810c7acd50a4c17f' + CREATE_REQUEST: 'd-3efdc91da580479d810c7acd50a4c17f', } export const REGEX = { URL: /^(http(s?):\/\/)?(www\.)?[a-zA-Z0-9\.\-\_]+(\.[a-zA-Z]{2,15})+(\:[0-9]{2,5})?(\/[a-zA-Z0-9\_\-\s\.\/\?\%\#\&\=;]*)?$/, // eslint-disable-line