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

Commit 97f0ab4

Browse files
#29 - Proxy to EMSI if the org use EMSI as skill provider
1 parent f15e796 commit 97f0ab4

File tree

5 files changed

+111
-1
lines changed

5 files changed

+111
-1
lines changed

config/default.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ module.exports = {
3636
UBAHN_UPDATE_TOPIC: process.env.UBAHN_UPDATE_TOPIC || 'u-bahn.action.update',
3737
UBAHN_DELETE_TOPIC: process.env.UBAHN_DELETE_TOPIC || 'u-bahn.action.delete',
3838

39+
EMSI: {
40+
CLIENT_ID: process.env.EMSI_CLIENT_ID,
41+
CLIENT_SECRET: process.env.EMSI_CLIENT_SECRET,
42+
GRANT_TYPE: process.env.EMSI_GRANT_TYPE || 'client_credentials',
43+
SCOPE: process.env.EMSI_SCOPE || 'emsi_open',
44+
AUTH_URL: process.env.EMSI_AUTH_URL || 'https://auth.emsicloud.com/connect/token',
45+
BASE_URL: process.env.EMSI_BASE_URL || 'https://skills.emsicloud.com/versions/latest'
46+
},
47+
48+
EMSI_SKILLPROVIDER_ID: process.env.EMSI_SKILLPROVIDER_ID || '7637ae1a-3b7c-44eb-a5ed-10ea02f1885d',
49+
3950
// ElasticSearch
4051
ES: {
4152
HOST: process.env.ES_HOST || 'localhost:9200',

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"ion-js": "^3.1.2",
3030
"js-yaml": "^3.13.1",
3131
"lodash": "^4.17.19",
32+
"node-cache": "^5.1.2",
3233
"querystring": "^0.2.0",
3334
"swagger-ui-express": "^4.1.4",
3435
"tc-bus-api-wrapper": "github:topcoder-platform/tc-bus-api-wrapper",

src/modules/search/controller.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
const esHelper = require('../../common/es-helper')
55
const { injectSearchMeta } = require('../../common/helper')
6+
const service = require('./service')
67

78
/**
89
* Search for users. Returns enriched users
@@ -17,7 +18,7 @@ async function searchUsers (req, res) {
1718
* Search for skills in organization
1819
*/
1920
async function searchSkills (req, res) {
20-
const result = await esHelper.searchSkillsInOrganization(req.query)
21+
const result = await service.getSkills(req.query, req.auth)
2122
res.send(result.result)
2223
}
2324

src/modules/search/service.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
const axios = require('axios')
2+
const config = require('config')
3+
const querystring = require('querystring')
4+
const NodeCache = require('node-cache')
5+
const joi = require('@hapi/joi')
6+
const orgSkillsProviderService = require('../organizationSkillsProvider/service')
7+
const esHelper = require('../../common/es-helper')
8+
9+
// cache the emsi token
10+
const tokenCache = new NodeCache()
11+
12+
/**
13+
* Format EMSI skills like the ones returned by the ES query
14+
* @param {Array} emsiSkills Array of skills
15+
*/
16+
function formatEmsiSkills (emsiSkills) {
17+
return emsiSkills.skills.slice(0, 10).map(skill => ({
18+
name: skill.name,
19+
skillId: skill.id,
20+
skillProviderId: config.EMSI_SKILLPROVIDER_ID
21+
}))
22+
}
23+
24+
/**
25+
* Get emsi token
26+
* @returns {string} the emsi token
27+
*/
28+
async function getEmsiToken () {
29+
let token = tokenCache.get('emsi_token')
30+
if (!token) {
31+
const res = await axios.post(config.EMSI.AUTH_URL, querystring.stringify({
32+
client_id: config.EMSI.CLIENT_ID,
33+
client_secret: config.EMSI.CLIENT_SECRET,
34+
grant_type: config.EMSI.GRANT_TYPE,
35+
scope: config.EMSI.SCOPE
36+
}))
37+
token = res.data.access_token
38+
tokenCache.set('emsi_token', token, res.data.expires_in)
39+
}
40+
return token
41+
}
42+
43+
/**
44+
* Get data from emsi
45+
* @param {String} path the emsi endpoint path
46+
* @param {String} params get params
47+
* @returns {Object} response data
48+
*/
49+
async function getEmsiObject (path, params) {
50+
const token = await getEmsiToken()
51+
const res = await axios.get(`${config.EMSI.BASE_URL}${path}`, { params, headers: { authorization: `Bearer ${token}` } })
52+
return res.data
53+
}
54+
55+
/**
56+
* Get skills by query.
57+
// !Proxies request to EMSI if org uses it as its skill provider
58+
* @param {String} query the query
59+
* @param {Object} auth the auth object
60+
* @returns {Object} the Object with skills
61+
*/
62+
async function getSkills (query, auth) {
63+
let result
64+
const skillProviderIds = await orgSkillsProviderService.search({ organizationId: query.organizationId }, auth)
65+
66+
if (skillProviderIds.result.length === 1 && skillProviderIds.result[0].skillProviderId === config.EMSI_SKILLPROVIDER_ID) {
67+
result = await getEmsiObject('/skills', { q: query.keyword })
68+
return { result: formatEmsiSkills(result) }
69+
}
70+
71+
result = await esHelper.searchSkillsInOrganization(query)
72+
73+
return result
74+
}
75+
76+
getSkills.schema = {
77+
query: joi.object().keys({
78+
organizationId: joi.string().required(),
79+
keyword: joi.string().required()
80+
}),
81+
auth: joi.object()
82+
}
83+
84+
module.exports = { getSkills }

0 commit comments

Comments
 (0)