Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 5e38832

Browse files
#24 - Scrap individual service and controller for org skill provider and instead use generic one AND integrate with ES
1 parent 0d2de55 commit 5e38832

File tree

8 files changed

+195
-222
lines changed

8 files changed

+195
-222
lines changed

config/default.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ module.exports = {
8989
},
9090
userskill: {
9191
userField: process.env.USER_SKILL_PROPERTY_NAME || 'skills'
92+
},
93+
// sub resources under organization
94+
organizationskillprovider: {
95+
orgField: process.env.ORGANIZATION_SKILLPROVIDER_PROPERTY_NAME || 'skillProviders'
9296
}
9397
}
9498
}

scripts/constants.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ const userResources = {
6464
}
6565
}
6666

67+
const organizationResources = {
68+
organizationskillprovider: {
69+
propertyName: config.get('ES.DOCUMENTS.organizationskillprovider.orgField'),
70+
relateKey: 'skillProviderId'
71+
}
72+
}
73+
6774
const modelToESIndexMapping = {
6875
User: 'user',
6976
Role: 'role',
@@ -82,5 +89,8 @@ const modelToESIndexMapping = {
8289
}
8390

8491
module.exports = {
85-
topResources, userResources, modelToESIndexMapping
92+
topResources,
93+
userResources,
94+
organizationResources,
95+
modelToESIndexMapping
8696
}

scripts/db/genData.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ const _ = require('lodash')
22
const models = require('../../src/models')
33
const logger = require('../../src/common/logger')
44
const { getESClient } = require('../../src/common/es-client')
5-
const { topResources, userResources, modelToESIndexMapping } = require('../constants')
5+
const {
6+
topResources,
7+
userResources,
8+
organizationResources,
9+
modelToESIndexMapping
10+
} = require('../constants')
611

712
async function insertIntoES (modelName, body) {
813
const esResourceName = modelToESIndexMapping[modelName]
@@ -66,6 +71,33 @@ async function insertIntoES (modelName, body) {
6671
refresh: 'true'
6772
})
6873
}
74+
} else if (_.includes(_.keys(organizationResources), esResourceName)) {
75+
const orgResource = organizationResources[esResourceName]
76+
77+
const organization = await client.getSource({
78+
index: topResources.organization.index,
79+
type: topResources.organization.type,
80+
id: body.organizationId
81+
})
82+
83+
const relateId = body[orgResource.relateKey]
84+
85+
if (!organization[orgResource.propertyName]) {
86+
organization[orgResource.propertyName] = []
87+
}
88+
89+
if (_.some(organization[orgResource.propertyName], [orgResource.relateKey, relateId])) {
90+
logger.error(`Can't create existing ${esResourceName} with the ${orgResource.relateKey}: ${relateId}, organizationId: ${body.organizationId}`)
91+
} else {
92+
organization[orgResource.propertyName].push(body)
93+
await client.update({
94+
index: topResources.organization.index,
95+
type: topResources.organization.type,
96+
id: body.organizationId,
97+
body: { doc: organization },
98+
refresh: 'true'
99+
})
100+
}
69101
}
70102
}
71103

src/common/es-helper.js

Lines changed: 112 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@ const esClient = require('./es-client').getESClient()
99
const DOCUMENTS = config.ES.DOCUMENTS
1010
const RESOURCES = Object.keys(DOCUMENTS)
1111

12-
const SUB_DOCUMENTS = {}
13-
const SUB_PROPERTIES = []
12+
const SUB_USER_DOCUMENTS = {}
13+
const SUB_ORG_DOCUMENTS = {}
14+
const SUB_USER_PROPERTIES = []
15+
const SUB_ORG_PROPERTIES = []
1416
_.forOwn(DOCUMENTS, (value, key) => {
1517
if (value.userField) {
16-
SUB_DOCUMENTS[key] = value
17-
SUB_PROPERTIES.push(value.userField)
18+
SUB_USER_DOCUMENTS[key] = value
19+
SUB_USER_PROPERTIES.push(value.userField)
20+
} else if (value.orgField) {
21+
SUB_ORG_DOCUMENTS[key] = value
22+
SUB_ORG_PROPERTIES.push(value.orgField)
1823
}
1924
})
2025

@@ -241,7 +246,7 @@ const FILTER_CHAIN = {
241246
},
242247
// sub resource
243248
userskill: {
244-
queryFielid: 'skillId',
249+
queryField: 'skillId',
245250
enrichNext: 'skill',
246251
idField: 'skillId'
247252
},
@@ -261,6 +266,11 @@ const FILTER_CHAIN = {
261266
userattribute: {
262267
enrichNext: 'attribute',
263268
idField: 'attributeId'
269+
},
270+
organizationskillprovider: {
271+
queryField: 'skillProviderId',
272+
enrichNext: 'skillprovider',
273+
idField: 'skillProviderId'
264274
}
265275
}
266276

@@ -269,13 +279,15 @@ function getTotalCount (total) {
269279
}
270280

271281
function escapeRegex (str) {
282+
/* eslint-disable no-useless-escape */
272283
return str
273284
.replace(/[\*\+\-=~><\"\?^\${}\(\)\:\!\/[\]\\\s]/g, '\\$&') // replace single character special characters
274285
.replace(/\|\|/g, '\\||') // replace ||
275286
.replace(/\&\&/g, '\\&&') // replace &&
276287
.replace(/AND/g, '\\A\\N\\D') // replace AND
277288
.replace(/OR/g, '\\O\\R') // replace OR
278289
.replace(/NOT/g, '\\N\\O\\T') // replace NOT
290+
/* eslint-enable no-useless-escape */
279291
}
280292

281293
async function getOrganizationId (handle) {
@@ -398,8 +410,8 @@ async function enrichResource (resource, enrichIdProp, item) {
398410
* @returns {Promise<*>} the promise of enriched user
399411
*/
400412
async function enrichUser (user) {
401-
for (const subProp of Object.keys(SUB_DOCUMENTS)) {
402-
const subDoc = SUB_DOCUMENTS[subProp]
413+
for (const subProp of Object.keys(SUB_USER_DOCUMENTS)) {
414+
const subDoc = SUB_USER_DOCUMENTS[subProp]
403415
const subData = user[subDoc.userField]
404416
const filterChain = FILTER_CHAIN[subProp]
405417
if (subData && subData.length > 0) {
@@ -440,23 +452,43 @@ async function getFromElasticSearch (resource, ...args) {
440452

441453
const doc = DOCUMENTS[resource]
442454
const userDoc = DOCUMENTS.user
443-
const subDoc = SUB_DOCUMENTS[resource]
455+
const orgDoc = DOCUMENTS.organization
456+
const subUserDoc = SUB_USER_DOCUMENTS[resource]
457+
const subOrgDoc = SUB_ORG_DOCUMENTS[resource]
444458
const filterChain = FILTER_CHAIN[resource]
445459

460+
let esQuery
461+
446462
// construct ES query
447-
const esQuery = {
448-
index: doc.userField ? userDoc.index : doc.index,
449-
type: doc.userField ? userDoc.type : doc.type,
450-
id: doc.userField ? params.userId : id
463+
if (doc.userField) {
464+
esQuery = {
465+
index: userDoc.index,
466+
type: userDoc.type,
467+
id: params.userId
468+
}
469+
} else if (doc.orgField) {
470+
esQuery = {
471+
index: orgDoc.index,
472+
type: orgDoc.type,
473+
id: params.organizationId
474+
}
475+
} else {
476+
esQuery = {
477+
index: doc.index,
478+
type: doc.type,
479+
id: id
480+
}
451481
}
452482

453483
if (resource === 'user') {
454484
// handle enrich
455485
if (!params.enrich) {
456-
esQuery._source_excludes = SUB_PROPERTIES.join(',')
486+
esQuery._source_excludes = SUB_USER_PROPERTIES.join(',')
457487
}
458-
} else if (subDoc) {
459-
esQuery._source_includes = subDoc.userField
488+
} else if (subUserDoc) {
489+
esQuery._source_includes = subUserDoc.userField
490+
} else if (subOrgDoc) {
491+
esQuery._source_includes = subOrgDoc.orgField
460492
}
461493

462494
logger.debug(`ES query for get ${resource}: ${JSON.stringify(esQuery, null, 2)}`)
@@ -469,14 +501,22 @@ async function getFromElasticSearch (resource, ...args) {
469501
const groups = await groupApi.getGroups(user.id)
470502
user.groups = groups
471503
return user
472-
} else if (subDoc) {
504+
} else if (subUserDoc) {
473505
// find top sub doc by sub.id
474-
const found = result[subDoc.userField].find(sub => sub[filterChain.idField] === params[filterChain.idField])
506+
const found = result[subUserDoc.userField].find(sub => sub[filterChain.idField] === params[filterChain.idField])
475507
if (found) {
476508
return found
477509
} else {
478510
throw new Error(`${resource} of userId ${params.userId}, ${params[filterChain.idField]} is not found from ES`)
479511
}
512+
} else if (subOrgDoc) {
513+
// find top sub doc by sub.id
514+
const found = result[subOrgDoc.orgField].find(sub => sub[filterChain.idField] === params[filterChain.idField])
515+
if (found) {
516+
return found
517+
} else {
518+
throw new Error(`${resource} of organizationId ${params.organizationId}, ${params[filterChain.idField]} is not found from ES`)
519+
}
480520
}
481521
return result
482522
}
@@ -527,7 +567,14 @@ function setResourceFilterToEsQuery (resFilters, esQuery) {
527567
if (resFilters.length > 0) {
528568
for (const filter of resFilters) {
529569
const doc = DOCUMENTS[filter.resource]
530-
let matchField = doc.userField ? `${doc.userField}.${filter.queryField}` : `${filter.queryField}`
570+
let matchField
571+
if (doc.userField) {
572+
matchField = `${doc.userField}.${filter.queryField}`
573+
} else if (doc.orgField) {
574+
matchField = `${doc.orgField}.${filter.queryField}`
575+
} else {
576+
matchField = `${filter.queryField}`
577+
}
531578
if (filter.queryField !== 'name' && filter.queryField !== 'isInactive') {
532579
matchField = matchField + '.keyword'
533580
}
@@ -917,11 +964,20 @@ async function resolveResFilter (filter, initialRes) {
917964

918965
// return the value if this is end of the filter
919966
if (filter.resource === initialRes || !filterChain.filterNext) {
920-
return {
921-
resource: filter.resource,
922-
userField: doc.userField,
923-
queryField: filter.queryField,
924-
value: filter.value
967+
if (doc.orgField) {
968+
return {
969+
resource: filter.resource,
970+
orgField: doc.orgField,
971+
queryField: filter.queryField,
972+
value: filter.value
973+
}
974+
} else {
975+
return {
976+
resource: filter.resource,
977+
userField: doc.userField,
978+
queryField: filter.queryField,
979+
value: filter.value
980+
}
925981
}
926982
}
927983

@@ -998,7 +1054,9 @@ async function searchElasticSearch (resource, ...args) {
9981054
const authUser = args[1]
9991055
const doc = DOCUMENTS[resource]
10001056
const userDoc = DOCUMENTS.user
1001-
const topSubDoc = SUB_DOCUMENTS[resource]
1057+
const orgDoc = DOCUMENTS.organization
1058+
const topUserSubDoc = SUB_USER_DOCUMENTS[resource]
1059+
const topOrgSubDoc = SUB_ORG_DOCUMENTS[resource]
10021060
if (!params.page) {
10031061
params.page = 1
10041062
}
@@ -1051,8 +1109,8 @@ async function searchElasticSearch (resource, ...args) {
10511109

10521110
// construct ES query
10531111
const esQuery = {
1054-
index: doc.userField ? userDoc.index : doc.index,
1055-
type: doc.userField ? userDoc.type : doc.type,
1112+
index: doc.userField ? userDoc.index : (doc.orgField ? orgDoc.index : doc.index),
1113+
type: doc.userField ? userDoc.type : (doc.orgField ? orgDoc.type : doc.type),
10561114
size: params.perPage,
10571115
from: (params.page - 1) * params.perPage, // Es Index starts from 0
10581116
body: {
@@ -1104,9 +1162,9 @@ async function searchElasticSearch (resource, ...args) {
11041162
})
11051163
} else {
11061164
// do not return sub-resources
1107-
esQuery._source_excludes = SUB_PROPERTIES.join(',')
1165+
esQuery._source_excludes = SUB_USER_PROPERTIES.join(',')
11081166
}
1109-
} else if (topSubDoc) {
1167+
} else if (topUserSubDoc) {
11101168
// add userId match
11111169
const userFC = FILTER_CHAIN.user
11121170
const userIdMatchField = `${userFC.idField}.keyword`
@@ -1115,13 +1173,30 @@ async function searchElasticSearch (resource, ...args) {
11151173
[userIdMatchField]: params.userId
11161174
}
11171175
})
1118-
esQuery._source_includes = topSubDoc.userField
1176+
esQuery._source_includes = topUserSubDoc.userField
1177+
} else if (topOrgSubDoc) {
1178+
// add organizationId match
1179+
const orgFC = FILTER_CHAIN.organization
1180+
const orgIdMatchField = `${orgFC.idField}.keyword`
1181+
esQuery.body.query.bool.must.push({
1182+
match: {
1183+
[orgIdMatchField]: params.organizationId
1184+
}
1185+
})
1186+
esQuery._source_includes = topOrgSubDoc.orgField
11191187
}
11201188

11211189
// set pre res filter results
11221190
if (!params.enrich && preResFilterResults.length > 0) {
11231191
for (const filter of preResFilterResults) {
1124-
const matchField = filter.userField ? `${filter.userField}.${filter.queryField}` : `${filter.queryField}`
1192+
let matchField
1193+
if (filter.userField) {
1194+
matchField = `${filter.userField}.${filter.queryField}`
1195+
} else if (filter.orgField) {
1196+
matchField = `${filter.orgField}.${filter.queryField}`
1197+
} else {
1198+
matchField = `${filter.queryField}`
1199+
}
11251200
setFilterValueToEsQuery(esQuery, matchField, filter.value, filter.queryField)
11261201
}
11271202
}
@@ -1152,11 +1227,16 @@ async function searchElasticSearch (resource, ...args) {
11521227
const groups = await groupApi.getGroups(user.id)
11531228
user.groups = groups
11541229
}
1155-
} else if (topSubDoc) {
1156-
result = docs.hits.hits[0]._source[topSubDoc.userField]
1230+
} else if (topUserSubDoc) {
1231+
result = docs.hits.hits[0]._source[topUserSubDoc.userField]
11571232
// for sub-resource query, it returns all sub-resource items in one user,
11581233
// so needs filtering and also page size
11591234
result = applySubResFilters(result, preResFilterResults, ownResFilters, params.perPage)
1235+
} else if (topOrgSubDoc) {
1236+
result = docs.hits.hits[0]._source[topOrgSubDoc.orgField]
1237+
// for sub-resource query, it returns all sub-resource items in one organization,
1238+
// so needs filtering and also page size
1239+
result = applySubResFilters(result, preResFilterResults, ownResFilters, params.perPage)
11601240
} else {
11611241
result = docs.hits.hits.map(hit => hit._source)
11621242
}

src/common/service-helper.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ const OP_TO_TOPIC = {
1414
}
1515

1616
// Used for determining the payload structure when posting to bus api
17-
const SUB_DOCUMENTS = {}
17+
const SUB_USER_DOCUMENTS = {}
18+
const SUB_ORG_DOCUMENTS = {}
1819
_.forOwn(config.ES.DOCUMENTS, (value, key) => {
1920
if (value.userField) {
20-
SUB_DOCUMENTS[key] = value
21+
SUB_USER_DOCUMENTS[key] = value
22+
} else if (value.orgField) {
23+
SUB_ORG_DOCUMENTS[key] = value
2124
}
2225
})
2326

@@ -293,7 +296,7 @@ function getServiceMethods (Model, createSchema, patchSchema, searchSchema, buil
293296
let payload
294297
await get(id, auth, params) // check exist
295298
await models.DBHelper.delete(Model, id, buildQueryByParams(params))
296-
if (SUB_DOCUMENTS[resource]) {
299+
if (SUB_USER_DOCUMENTS[resource] || SUB_ORG_DOCUMENTS[resource]) {
297300
payload = _.assign({}, params)
298301
} else {
299302
payload = {
@@ -313,10 +316,5 @@ function getServiceMethods (Model, createSchema, patchSchema, searchSchema, buil
313316
}
314317

315318
module.exports = {
316-
getServiceMethods,
317-
makeSureRefExist,
318-
makeSureUnique,
319-
getResource,
320-
buildQueryByParams,
321-
publishMessage
319+
getServiceMethods
322320
}

0 commit comments

Comments
 (0)