Skip to content

Commit 543b505

Browse files
author
vikasrohit
authored
Merge pull request #9 from topcoder-platform/feature/populate-member-details
Feature/populate member details
2 parents e2c233f + c0d7c04 commit 543b505

File tree

6 files changed

+98
-5
lines changed

6 files changed

+98
-5
lines changed

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ The following parameters can be set in config files or in env variables:
2525
- UPDATE_DATA_TOPIC: update data Kafka topic, default value is 'project.action.update'
2626
- DELETE_DATA_TOPIC: delete data Kafka topic, default value is 'project.action.delete'
2727
- KAFKA_MESSAGE_ORIGINATOR: Kafka topic originator, default value is 'project-api'
28+
- MEMBER_SERVICE_ENDPOINT: used to get member details
29+
- AUTH0_URL: AUTH0 URL, used to get M2M token
30+
- AUTH0_PROXY_SERVER_URL: AUTH0 proxy server URL, used to get M2M token
31+
- AUTH0_AUDIENCE: AUTH0 audience, used to get M2M token
32+
- TOKEN_CACHE_TIME: AUTH0 token cache time, used to get M2M token
33+
- AUTH0_CLIENT_ID: AUTH0 client id, used to get M2M token
34+
- AUTH0_CLIENT_SECRET: AUTH0 client secret, used to get M2M token
2835
- esConfig: config object for Elasticsearch
2936

3037
Refer to `esConfig` variable in `config/default.js` for ES related configuration.
@@ -69,12 +76,20 @@ Config for tests are at `config/test.js`, it overrides some default config.
6976
- In the `docker-es` folder, run `docker-compose up`
7077

7178
## Local deployment
72-
7379
- Install dependencies `npm i`
7480
- Run code lint check `npm run lint`, running `npm run lint:fix` can fix some lint errors if any
7581
- Initialize Elasticsearch, create configured Elasticsearch index if not present: `npm run sync:es`
7682
- Start processor app `npm start`
7783

84+
Note that you need to set AUTH0 related environment variables belows before you can start the processor.
85+
86+
- AUTH0_URL
87+
- AUTH0_AUDIENCE
88+
- TOKEN_CACHE_TIME
89+
- AUTH0_CLIENT_ID
90+
- AUTH0_CLIENT_SECRET
91+
- AUTH0_PROXY_SERVER_URL
92+
7893
## Local Deployment with Docker
7994

8095
To run the Challenge ES Processor using docker, follow the below steps
@@ -254,4 +269,4 @@ info: {
254269
- Then in the app console, you will see error messages
255270

256271
- To test the health check API, run `export PORT=5000`, start the processor, then browse `http://localhost:5000/health` in a browser,
257-
and you will see result `{"checksRun":1}`
272+
and you will see result `{"checksRun":1}`

config/default.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ module.exports = {
1717
DELETE_DATA_TOPIC: process.env.DELETE_DATA_TOPIC || 'project.action.delete',
1818
KAFKA_MESSAGE_ORIGINATOR: process.env.KAFKA_MESSAGE_ORIGINATOR || 'project-api',
1919

20+
MEMBER_SERVICE_ENDPOINT: process.env.MEMBER_SERVICE_ENDPOINT || 'https://api.topcoder-dev.com/v3/members',
21+
22+
AUTH0_URL: process.env.AUTH0_URL,
23+
AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL,
24+
AUTH0_AUDIENCE: process.env.AUTH0_AUDIENCE,
25+
TOKEN_CACHE_TIME: process.env.TOKEN_CACHE_TIME,
26+
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
27+
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET,
28+
2029
esConfig: {
2130
HOST: process.env.ES_HOST || 'localhost:9200',
2231
AWS_REGION: process.env.AWS_REGION || 'us-east-1', // AWS Region to be used if we use AWS ES

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
"joi": "^14.3.1",
3131
"lodash": "^4.17.11",
3232
"no-kafka": "^3.4.3",
33+
"tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6",
3334
"topcoder-healthcheck-dropin": "^1.0.3",
35+
"urlencode": "^1.1.0",
3436
"winston": "^3.2.1"
3537
},
3638
"standard": {

src/common/helper.js

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,27 @@
55
const AWS = require('aws-sdk')
66
const config = require('config')
77
const elasticsearch = require('elasticsearch')
8+
const _ = require('lodash')
9+
const tcCoreLib = require('tc-core-library-js')
10+
const urlencode = require('urlencode')
811

912
const logger = require('./logger')
1013

1114
AWS.config.region = config.get('esConfig.AWS_REGION')
1215
// ES Client mapping
1316
const esClients = {}
1417

18+
const m2m = tcCoreLib.auth.m2m(config)
19+
const tcCoreLibUtil = tcCoreLib.util(config)
20+
21+
/**
22+
* Get machine to machine token.
23+
* @returns {Promise} promise which resolves to the m2m token
24+
*/
25+
async function getM2MToken () {
26+
return m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET)
27+
}
28+
1529
/**
1630
* Get ES Client
1731
* @return {Object} Elastic Host Client Instance
@@ -126,9 +140,35 @@ async function updateMetadadaESPromise (updateDocHandler) {
126140
})
127141
}
128142

143+
/**
144+
* Retrieve member details from userIds
145+
*
146+
* @param {Array} userIds the list of userIds
147+
* @returns {Promise} the member details
148+
*/
149+
async function getMemberDetailsByUserIds (userIds) {
150+
try {
151+
const token = await getM2MToken()
152+
const httpClient = tcCoreLibUtil.getHttpClient({ id: `projectMemberService_${userIds.join('_')}`, log: logger })
153+
return httpClient.get(`${config.MEMBER_SERVICE_ENDPOINT}/_search`, {
154+
params: {
155+
query: `${_.map(userIds, id => `userId:${id}`).join(urlencode(' OR ', 'utf8'))}`,
156+
fields: 'userId,handle,firstName,lastName,email'
157+
},
158+
headers: {
159+
'Content-Type': 'application/json',
160+
Authorization: `Bearer ${token}`
161+
}
162+
}).then(res => _.get(res, 'data.result.content', null))
163+
} catch (err) {
164+
return Promise.reject(err)
165+
}
166+
}
167+
129168
module.exports = {
130169
getESClient,
131170
updateProjectESPromise,
132171
updateTimelineESPromise,
133-
updateMetadadaESPromise
172+
updateMetadadaESPromise,
173+
getMemberDetailsByUserIds
134174
}

src/services/ProcessorServiceProjectMember.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,30 @@ async function create (message) {
5353
async function updateDocPromise (doc) {
5454
const members = _.isArray(doc._source.members) ? doc._source.members : []
5555
const existingMemberIndex = _.findIndex(members, p => p.id === message.id)// if member does not exists already
56+
let member = message
57+
58+
// try to populate member with user details
59+
// the code should move on, as it's not critical and is only used for searching at the moment
60+
try {
61+
const membersDetails = await helper.getMemberDetailsByUserIds([message.userId])
62+
const memberDetails = membersDetails[0]
63+
if (memberDetails) {
64+
member = _.merge(message, _.pick(memberDetails, 'handle', 'firstName', 'lastName', 'email'))
65+
logger.debug(`Successfully got user details for member (userId:${message.userId})`)
66+
} else {
67+
throw new Error(`Didn't fine user details for member (userId:${message.userId})`)
68+
}
69+
} catch (err) {
70+
logger.error(`Cannot populate member (userId:${message.userId}) with user details.`)
71+
logger.debug(`Error during populating member (userId:${message.userId}) with user details`, err)
72+
}
73+
5674
if (existingMemberIndex === -1) {
57-
members.push(message)
75+
members.push(member)
5876
} else { // if member already exists, ideally we should never land here, but code handles the buggy indexing
5977
// replaces the old inconsistent index where previously member was not removed from the index but deleted
6078
// from the database
61-
members.splice(existingMemberIndex, 1, message)
79+
members.splice(existingMemberIndex, 1, member)
6280
}
6381
return _.assign(doc._source, { members })
6482
}

test/e2e/processor.project.index.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const Joi = require('joi')
1111
const ProcessorService = require('../../src/services/ProcessorService')
1212
const testHelper = require('../common/testHelper')
1313
const logger = require('../../src/common/logger')
14+
const helper = require('../../src/common/helper')
1415

1516
const {
1617
projectId,
@@ -799,13 +800,21 @@ xdescribe('TC Phase Product Topic Tests', () => {
799800
})
800801

801802
describe('TC Project Member Topic Tests', () => {
803+
let getMemberDetailsByUserIds
804+
802805
before(async () => {
803806
// runs before all tests in this block
804807
await ProcessorService.create(projectCreatedMessage)
808+
getMemberDetailsByUserIds = helper.getMemberDetailsByUserIds
809+
helper.getMemberDetailsByUserIds = async (userIds) => {
810+
return [] // return empty details
811+
}
805812
})
806813
after(async () => {
807814
// runs after all tests in this block
808815
await ProcessorService.deleteMessage(projectDeletedMessage)
816+
// restore the method
817+
helper.getMemberDetailsByUserIds = getMemberDetailsByUserIds
809818
})
810819

811820
it('create project member message', async () => {

0 commit comments

Comments
 (0)