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

Removes EMSI dependency and integrates /search/skills endpoint for auto suggestion #628

Merged
merged 2 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,5 @@ Configuration for the application is at `config/default.js` and `config/producti
- TEMPLATE_S3_BUCKET: the template s3 bucket name, default value is 'ubahn'
- UPLOAD_S3_BUCKET: the upload s3 bucket name, default value is 'ubahn'
- S3_OBJECT_URL_EXPIRY_TIME: the s3 url expiry time, default value is '1 hour'
- EMSI_CLIENT_ID: emsi oAuth 2.0 client id, used to get emis oAuth 2.0 token
- EMSI_CLIENT_SECRET: emsi oAuth 2.0 client secret, used to get emsi oAuth 2.0 token
- EMSI_GRANT_TYPE: emsi oAuth 2.0 grant_type, used to get emsi oAuth 2.0 token, should always be the string 'client_credentials'
- EMSI_SCOPE: emsi oAuth 2.0 scope, used to get emsi oAuth 2.0 token, default value is 'emsi_open'
- EMSI_AUTH_URL: emsi oAuth 2.0 auth url, used to get emsi oAuth 2.0 token, default value is 'https://auth.emsicloud.com/connect/token'
- EMSI_BASE_URL: emsi base url, used to get emsi skills, default value is 'https://skills.emsicloud.com/versions/latest'

Also check out the client folder's README file for additional configurations to set for the front end. You can find the required configurations under client/src/config.js
2 changes: 0 additions & 2 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ REACT_APP_API_URL => The endpoint from which the application retrieves the users

REACT_BULK_UPLOAD_TEMPLATE_ID => The id of the database record which is associated with the bulk upload template file. You would need to query the backend to get the id and then set it against this variable

REACT_APP_EMSI_SKILLPROVIDER_ID => The skill provider id with name 'EMSI'. Denotes that the skills with an externalId are using EMSI as the skill provider.

REACT_APP_ATTRIBUTE_ID_LOCATION
REACT_APP_ATTRIBUTE_ID_COMPANY
REACT_APP_ATTRIBUTE_ID_TITLE
Expand Down
9 changes: 5 additions & 4 deletions client/src/components/EditProfileModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import ProfileCard from "../ProfileCard";
import SuggestionBox from "../SuggestionBox";

import style from "./style.module.scss";
import config from "../../config";

export default function EditProfileModal({
onCancel,
Expand Down Expand Up @@ -64,7 +63,9 @@ export default function EditProfileModal({
const addSkill = (skill) => {
// Verify that the skill does not already exist on the user
const index = localUser.skills.findIndex(
(existingSkill) => existingSkill.externalId === skill.id
(existingSkill) =>
existingSkill.skillProviderId === skill.skillProviderId &&
existingSkill.externalId === skill.skillId
);
const exists = localUser.skills[index];

Expand All @@ -78,10 +79,10 @@ export default function EditProfileModal({
delete skills[index].isDeleted;
} else {
skills.push({
externalId: skill.id, // The skill id returned from EMSI becomes externalId in our db
externalId: skill.skillId, // The skill id returned from API becomes externalId in our db
isNew: true,
name: skill.name,
skillProviderId: config.EMSI_SKILLPROVIDER_ID,
skillProviderId: skill.skillProviderId,
});
}

Expand Down
14 changes: 12 additions & 2 deletions client/src/components/FiltersSideMenu/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,13 @@ export default function SearchTabFilters() {
const addSkillToFilter = (skill) => {
const skillFilters = JSON.parse(JSON.stringify(search.selectedSkills));

if (skillFilters.findIndex((s) => s.id === skill.id) !== -1) {
if (
skillFilters.findIndex(
(s) =>
s.skillProviderId === skill.skillProviderId &&
s.skillId === skill.skillId
) !== -1
) {
return;
}

Expand All @@ -152,7 +158,11 @@ export default function SearchTabFilters() {

const removeSkillFromFilter = (skill) => {
const skillFilters = JSON.parse(JSON.stringify(search.selectedSkills));
const index = skillFilters.findIndex((s) => s.id === skill.id);
const index = skillFilters.findIndex(
(s) =>
s.skillProviderId === skill.skillProviderId &&
s.skillId === skill.skillId
);

if (index === -1) {
return;
Expand Down
8 changes: 5 additions & 3 deletions client/src/components/SuggestionBox/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import Autosuggest from "react-autosuggest";
import config from "../../config";
import api from "../../services/api";
import { getSingleOrg } from "../../services/user-org";
import style from "./style.module.scss";
import _ from "lodash";
import { useSearch, FILTERS } from "../../lib/search";
Expand Down Expand Up @@ -59,12 +60,13 @@ const getSkillsSuggestions = async (apiClient, inputValue) => {
}

term = encodeURIComponent(term);
const organizationId = getSingleOrg();

const url = `${config.API_PREFIX}/skills?q=${term}`;
const url = `${config.API_URL}/search/skills?organizationId=${organizationId}&keyword=${term}`;

const { data } = await apiClient.get(url);

return data.skills;
return data;
};

/**
Expand Down Expand Up @@ -118,7 +120,7 @@ export default function SuggestionBox({
const [suggestions, setSuggestions] = React.useState([]);
const [value, setValue] = React.useState("");

const onChange = (event, { newValue }) => setValue(newValue.trim());
const onChange = (event, { newValue }) => setValue(newValue);

const onSuggestionsFetchRequested = async ({ value }) => {
if (purpose === "locations") {
Expand Down
1 change: 0 additions & 1 deletion client/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export default {
GROUPS_PER_PAGE: process.env.REACT_APP_GROUPS_PER_PAGE || 1000,

BULK_UPLOAD_TEMPLATE_ID: process.env.REACT_APP_BULK_UPLOAD_TEMPLATE_ID,
EMSI_SKILLPROVIDER_ID: process.env.REACT_APP_EMSI_SKILLPROVIDER_ID,

DEFAULT_SORT_ORDER: "name",
ITEMS_PER_PAGE: 12,
Expand Down
11 changes: 1 addition & 10 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,5 @@ module.exports = {
TEMPLATE_FILE_MIMETYPE: process.env.TEMPLATE_FILE_MIMETYPE || 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
TEMPLATE_S3_BUCKET: process.env.TEMPLATE_S3_BUCKET || 'ubahn',
UPLOAD_S3_BUCKET: process.env.UPLOAD_S3_BUCKET || 'ubahn',
S3_OBJECT_URL_EXPIRY_TIME: process.env.S3_OBJECT_URL_EXPIRY_TIME || 60 * 60,

EMSI: {
CLIENT_ID: process.env.EMSI_CLIENT_ID,
CLIENT_SECRET: process.env.EMSI_CLIENT_SECRET,
GRANT_TYPE: process.env.EMSI_GRANT_TYPE || 'client_credentials',
SCOPE: process.env.EMSI_SCOPE || 'emsi_open',
AUTH_URL: process.env.EMSI_AUTH_URL || 'https://auth.emsicloud.com/connect/token',
BASE_URL: process.env.EMSI_BASE_URL || 'https://skills.emsicloud.com/versions/latest'
}
S3_OBJECT_URL_EXPIRY_TIME: process.env.S3_OBJECT_URL_EXPIRY_TIME || 60 * 60
}
3 changes: 0 additions & 3 deletions docker/sample.api.env
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ AUTH_SECRET=
AWS_ACCESS_KEY_ID=
AWS_REGION=
AWS_SECRET_ACCESS_KEY=
EMSI_CLIENT_ID=
EMSI_CLIENT_SECRET=
NODE_ENV=
REACT_APP_API_PREFIX=
REACT_APP_API_URL=
REACT_APP_AUTH0_AUDIENCE=
REACT_APP_AUTH0_CLIENTID=
REACT_APP_AUTH0_DOMAIN=
REACT_APP_BULK_UPLOAD_TEMPLATE_ID=
REACT_APP_EMSI_SKILLPROVIDER_ID=
REACT_APP_GROUPS_API_URL=
TEMPLATE_S3_BUCKET=
TOKEN_CACHE_TIME=
Expand Down
37 changes: 1 addition & 36 deletions src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,40 +288,6 @@ async function postEvent (topic, payload) {
await busApiClient.postEvent(message)
}

// cache the emsi token
const tokenCache = new NodeCache()

/**
* Get emsi token
* @returns {string} the emsi token
*/
async function getEmsiToken () {
let token = tokenCache.get('emsi_token')
if (!token) {
const res = await axios.post(config.EMSI.AUTH_URL, querystring.stringify({
client_id: config.EMSI.CLIENT_ID,
client_secret: config.EMSI.CLIENT_SECRET,
grant_type: config.EMSI.GRANT_TYPE,
scope: config.EMSI.SCOPE
}))
token = res.data.access_token
tokenCache.set('emsi_token', token, res.data.expires_in)
}
return token
}

/**
* Get data from emsi
* @param {String} path the emsi endpoint path
* @param {String} params get params
* @returns {Object} response data
*/
async function getEmsiObject (path, params) {
const token = await getEmsiToken()
const res = await axios.get(`${config.EMSI.BASE_URL}${path}`, { params, headers: { authorization: `Bearer ${token}` } })
return res.data
}

module.exports = {
wrapExpress,
autoWrapExpress,
Expand All @@ -334,6 +300,5 @@ module.exports = {
generateS3Url,
scan,
validateDuplicate,
postEvent,
getEmsiObject
postEvent
}
18 changes: 0 additions & 18 deletions src/controllers/SkillController.js

This file was deleted.

9 changes: 0 additions & 9 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,6 @@ module.exports = {
scopes: [constants.Scopes.GetTemplate, constants.Scopes.AllTemplate]
}
},
'/skills': {
get: {
controller: 'SkillController',
method: 'getEntity',
auth: 'jwt',
access: constants.AllAuthenticatedUsers,
scopes: [constants.Scopes.GetSkill, constants.Scopes.AllSkill]
}
},
'/health': {
get: {
controller: 'HealthCheckController',
Expand Down
21 changes: 0 additions & 21 deletions src/services/SkillService.js

This file was deleted.