From 0eef869a543f325038852f7cade57ffa290aee2e Mon Sep 17 00:00:00 2001 From: Michael Baghel Date: Tue, 22 Jun 2021 18:48:04 +0400 Subject: [PATCH 1/2] Make skill matching case-insensitive in getRoleBySkills --- src/services/TeamService.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index bc236cf1..3ec4acdb 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -13,7 +13,7 @@ const errors = require('../common/errors') const JobService = require('./JobService') const ResourceBookingService = require('./ResourceBookingService') const HttpStatus = require('http-status-codes') -const { Op } = require('sequelize') +const { Op, where, fn, col } = require('sequelize') const models = require('../models') const stopWords = require('../../data/stopWords.json') const { getAuditM2Muser } = require('../common/helper') @@ -799,17 +799,30 @@ roleSearchRequest.schema = Joi.object() * @returns {Role} the best matching Role */ async function getRoleBySkills (skills) { + // Case-insensitive search for roles matching any of the given skills const lowerCaseSkills = skills.map(skill => skill.toLowerCase()) - // find all roles which includes any of the given skills const queryCriteria = { - where: { listOfSkills: { [Op.overlap]: lowerCaseSkills } }, + where: where( + fn( + 'string_to_array', + fn( + 'lower', + fn( + 'array_to_string', + col('list_of_skills'), + ',' + ) + ), + ',' + ), + {[Op.overlap]: lowerCaseSkills }), raw: true } const roles = await Role.findAll(queryCriteria) if (roles.length > 0) { let result = _.each(roles, role => { - // calculate each found roles matching rate - role.skillsMatch = _.intersection(role.listOfSkills, lowerCaseSkills).length / skills.length + // calculate each found roles matching rate (must again be made case-insensitive) + role.skillsMatch = _.intersection(role.listOfSkills.map(skill => skill.toLowerCase()), lowerCaseSkills).length / skills.length // each role can have multiple rates, get the maximum of global rates role.maxGlobal = _.maxBy(role.rates, 'global').global }) From 8043bcd98565ff6f09ca25577e09085e85aa05cd Mon Sep 17 00:00:00 2001 From: Michael Baghel Date: Wed, 23 Jun 2021 01:40:47 +0400 Subject: [PATCH 2/2] Add job title to RoleSearchRequest service and model. Update swagger and add migration. Add previousRoleSearchId to RoleSearchRequest service. --- docs/swagger.yaml | 7 +++++++ ...-06-22-role-search-request-add-job-title.js | 18 ++++++++++++++++++ src/models/RoleSearchRequest.js | 5 +++++ src/services/TeamService.js | 11 +++++++---- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 migrations/2021-06-22-role-search-request-add-job-title.js diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6ffdf86d..26b389f4 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -5249,6 +5249,9 @@ components: jobDescription: type: string description: "The description of the job." + jobTitle: + type: string + description: "An optional job title." - type: object required: - skills @@ -5281,6 +5284,10 @@ components: format: float description: "Rate at which searched skills match the given role" example: 0.75 + jobTitle: + type: string + description: "Optional job title." + example: "Lead Application Developer" SubmitTeamRequestBody: properties: teamName: diff --git a/migrations/2021-06-22-role-search-request-add-job-title.js b/migrations/2021-06-22-role-search-request-add-job-title.js new file mode 100644 index 00000000..c1df8fba --- /dev/null +++ b/migrations/2021-06-22-role-search-request-add-job-title.js @@ -0,0 +1,18 @@ +const config = require('config') + +/** + * Add jobTitle field to the RoleSearchRequest model. + */ + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn({ tableName: 'role_search_requests', schema: config.DB_SCHEMA_NAME }, 'job_title', + { + type: Sequelize.STRING(100), + allowNull: true + }) + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn({ tableName: 'role_search_requests', schema: config.DB_SCHEMA_NAME}, 'job_title') + } +} \ No newline at end of file diff --git a/src/models/RoleSearchRequest.js b/src/models/RoleSearchRequest.js index 384b74d0..c79ae84f 100644 --- a/src/models/RoleSearchRequest.js +++ b/src/models/RoleSearchRequest.js @@ -62,6 +62,11 @@ module.exports = (sequelize) => { type: Sequelize.UUID }) }, + jobTitle: { + field: 'job_title', + type: Sequelize.STRING(100), + allowNull: true + }, createdBy: { field: 'created_by', type: Sequelize.UUID, diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 3ec4acdb..c5276332 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -776,11 +776,12 @@ async function roleSearchRequest (currentUser, data) { } data.roleId = role.id // create roleSearchRequest entity with found roleId - const { id: roleSearchRequestId } = await createRoleSearchRequest(currentUser, data) + const { id: roleSearchRequestId, jobTitle } = await createRoleSearchRequest(currentUser, data) + const entity = jobTitle ? { jobTitle, roleSearchRequestId } : { roleSearchRequestId }; // clean Role role = await _cleanRoleDTO(currentUser, role) // return Role - return _.assign(role, { roleSearchRequestId }) + return _.assign(role, entity) } roleSearchRequest.schema = Joi.object() @@ -789,8 +790,10 @@ roleSearchRequest.schema = Joi.object() data: Joi.object().keys({ roleId: Joi.string().uuid(), jobDescription: Joi.string().max(255), - skills: Joi.array().items(Joi.string().uuid().required()) - }).required().min(1) + skills: Joi.array().items(Joi.string().uuid().required()), + jobTitle: Joi.string().max(100), + previousRoleSearchRequestId: Joi.string().uuid() + }).required().or('roleId', 'jobDescription', 'skills') }).required() /**