diff --git a/app-constants.js b/app-constants.js index 3c40c7e..27bcf46 100644 --- a/app-constants.js +++ b/app-constants.js @@ -8,6 +8,7 @@ const EVENT_ORIGINATOR = 'topcoder-member-api' const EVENT_MIME_TYPE = 'application/json' const TOPICS = { + MemberCreated: 'member.action.profile.create', MemberUpdated: 'member.action.profile.update', EmailChanged: 'member.action.email.profile.emailchange.verification', MemberTraitCreated: 'member.action.profile.trait.create', diff --git a/src/services/MemberService.js b/src/services/MemberService.js index bbf3a59..2ff4d53 100644 --- a/src/services/MemberService.js +++ b/src/services/MemberService.js @@ -64,6 +64,7 @@ function omitMemberAttributes (currentUser, mb) { async function getMember (currentUser, handle, query) { // validate and parse query parameter const selectFields = helper.parseCommaSeparatedString(query.fields, MEMBER_FIELDS) || MEMBER_FIELDS + // query member from Elasticsearch const esQuery = { index: config.ES.MEMBER_PROFILE_ES_INDEX, @@ -80,11 +81,24 @@ async function getMember (currentUser, handle, query) { } // Search with constructed query let members = await esClient.search(esQuery) + if (members.hits.total === 0) { - throw new errors.NotFoundError(`Member with handle: "${handle}" doesn't exist`) + logger.debug(`Member ${handle} not found in ES. Lookup in DynamoDB...`) + try { + // Check if the member handle exists in DynamoDB + members = [ await helper.getMemberByHandle(handle) ] + // Memember was found in DynamoDB but not ES. Send message to member-processor-es + // to index the member in ES. It's safe to use the "create" topic since the processor + // will only create a new item of the item doesn't exist, otherwise it'll perform an update operation. + helper.postBusEvent(constants.TOPICS.MemberCreated, members[0].originalItem()) + } catch (e) { + logger.debug(`Member ${handle} not found in DynamoDB.`) + throw new errors.NotFoundError(`Member with handle: "${handle}" doesn't exist`) + } } else { members = _.map(members.hits.hits, '_source') } + // get the 'maxRating' from stats if (_.includes(selectFields, 'maxRating')) { for (let i = 0; i < members.length; i += 1) { diff --git a/src/services/MemberTraitService.js b/src/services/MemberTraitService.js index 49cc037..f70e1bc 100644 --- a/src/services/MemberTraitService.js +++ b/src/services/MemberTraitService.js @@ -51,6 +51,29 @@ async function getTraits (currentUser, handle, query) { // Search with constructed query const docs = await esClient.search(esQuery) let result = _.map(docs.hits.hits, (item) => item._source) + + if (result.length == 0) { + logger.debug(`MemberTraits for member ${handle} not found in ES. Lookup in DynamoDB...`) + const resultDynamo = await helper.query('MemberTrait', { userId: { eq: member.userId } }) + result = resultDynamo.map(traits => { + traits = traits.originalItem() + traits.traits = JSON.parse(traits.traits) + + if (traits.createdAt != null) { + traits.createdAt = new Date(traits.createdAt).getTime() + } + + if (traits.updatedAt != null) { + traits.updatedAt = new Date(traits.createdAt).getTime() + } + + // index in ES so subsequent API calls pull data from ES + helper.postBusEvent(constants.TOPICS.MemberTraitUpdated, traits) + + return traits + }) + } + // keep only those of given trait ids if (traitIds) { result = _.filter(result, (item) => _.includes(traitIds, item.traitId))