Skip to content
This repository has been archived by the owner on Apr 13, 2022. It is now read-only.

Amélioration du modèle des offres d’emploi #70

Closed
wants to merge 2 commits into from
Closed
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
19 changes: 16 additions & 3 deletions apps/api/fixtures/fixed-fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
"experienceRequirements": "* Vous êtes Bac+4 / 5 issu(e) d’une formation supérieure (Ecole d’ingénieurs, Master, DESS…), avec une forte dominante mathématique * Vous avez déjà 4 ans d’expérience en Data Science * Vous avez des bases solides requises en algorithmes de Machine Learning * Vous maitrisez le langage python * Vous présentez un intérêt pour le NLP ou souhaitez approfondir vos connaissances en traitement de données non structurées * Vous êtes intéressé(e) par d’autres technos (Spark, SQL, …) et pouvez vous adapter à un contexte technologique qui évolue * Vous avez une très bonne communication orale * Autonome, passionné(e) par la data et le travail dans une start up * Une connaissance de l’adtech est un plus * Mais surtout : vous avez une passion pour un projet startup qui a de grandes ambitions et une volonté à toute épreuve !",
"jobStartDate": "2020-05-02",
"skills": "Machine learning, Python, Spark, SQL ",
"validThrough": "2020-04-15"
"validThrough": "2020-04-15",
"jobLocationType": "office",
"jobImmediateStart": false,
"baseSalary": {
"value": 45
}
},
{
"title": "Ingénieur Lead Full Stack technico-fonctionnel",
Expand Down Expand Up @@ -61,7 +66,13 @@
"experienceRequirements": "* Expert en développement web. Maîtrise des langages de programmation web * back/front (php, go, bash, js, etc ..), des frameworks (laravel, vue, react, etc ..) * Maîtrise en développement mobile * Connaissance et maitrise des ops: server, monitoring, backup, sécurité * Connaissance du métier de la BU",
"jobStartDate": "2020-05-01",
"skills": "Php, Go, Bash, Js, Laravel, Vue, React, admin sys",
"validThrough": "2020-02-02"
"validThrough": "2020-02-02",
"jobLocationType": "office",
"jobImmediateStart": true,
"baseSalary": {
"minValue": 45,
"maxValue": 55
}
},
{
"title": "R&D Software Engineer",
Expand Down Expand Up @@ -93,6 +104,8 @@
"experienceRequirements": "★ Master in software engineering ★ You can translate real-world problems into automated real-time decision solutions. ★ You can build decision algorithms that work efficiently in regimes with high uncertainty. ★ You have experience in object-oriented and/or functional programming ★ You are deliverable-focused with a pragmatic and business-oriented attitude. ★ You are a team player, yet able to work independently. ★ You are eager to look for creative solutions using state of the art techniques. ★ You have an interest in Energy and IoT applications",
"jobStartDate": "2020-06-01",
"skills": "Java, Kotlin, Docker, Sql, Mongo, Devops",
"validThrough": ""
"validThrough": "",
"jobLocationType": "office",
"jobImmediateStart": false
}
]
23 changes: 23 additions & 0 deletions apps/api/migrations/20200501153317_extend-jobposting-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
exports.up = function (knex) {
return knex.schema.table('job_posting', (table) => {
table.jsonb('base_salary').nullable();
table
.enum('job_location_type', [
'office',
'remote',
'remote and office',
'remote or office',
])
.notNullable()
.defaultTo('office');
table.boolean('job_immediate_start').defaultTo(false);
});
};

exports.down = function (knex) {
return knex.schema.table('job_posting', (table) => {
table.dropColumn('base_salary');
table.dropColumn('job_location_type');
table.dropColumn('job_immediate_start');
});
};
63 changes: 62 additions & 1 deletion apps/api/src/job-posting/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,65 @@ const getOne = async (id) => {
.catch((error) => ({ error }));
};

const jobLocationTypes = [
'office',
'remote',
'remote and office',
'remote or office',
];

/**
* format baseSalary data in a well formated way.
*
* @param {object} apiBaseSalary - data about baseSalary from API
* @returns {object} baseSalary well formated for db save
*/
const formatBaseSalary = (apiBaseSalary) => {
if (
!apiBaseSalary ||
(!apiBaseSalary.value &&
(!apiBaseSalary.minValue || !apiBaseSalary.maxValue))
) {
return null;
}
const {
currency = 'EUR brut annuel',
minValue = null,
maxValue = null,
value = null,
} = apiBaseSalary;

return {
currency,
minValue,
maxValue,
value: value
? value
: minValue && maxValue
? Math.round((parseInt(minValue, 10) + parseInt(maxValue, 10)) / 2)
: null,
};
};

/**
* Prepare data from API for create or update a jobPosting in db.
*
* @param {object} apiData - data from API
* @returns {object} data well formated for db save
*/
const prepareDataForDb = (apiData) => {
const formatedBaseSalary = formatBaseSalary(apiData.baseSalary);
return {
...apiData,
jobLocationType: jobLocationTypes.includes(apiData.jobLocationType)
? apiData.jobLocationType
: 'office',
baseSalary: formatedBaseSalary
? JSON.stringify(formatedBaseSalary)
: null,
};
};

/**
* Return the created jobPosting
*
Expand All @@ -212,7 +271,7 @@ const createOne = async (apiData) => {

return client(tableName)
.returning('id')
.insert(apiData)
.insert(prepareDataForDb(apiData))
.then(([newJobPostingId]) => {
return getOneByIdQuery(client, newJobPostingId).then(
formatJobPostingForAPI
Expand Down Expand Up @@ -290,9 +349,11 @@ const updateOne = async (id, apiData) => {
module.exports = {
createOne,
deleteOne,
formatBaseSalary,
formatJobPostingForAPI,
getOne,
getPaginatedList,
prepareDataForDb,
renameFiltersFromAPI,
updateOne,
};
78 changes: 78 additions & 0 deletions apps/api/src/job-posting/repository.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const {
formatBaseSalary,
prepareDataForDb,
formatJobPostingForAPI,
renameFiltersFromAPI,
} = require('./repository');
Expand Down Expand Up @@ -38,6 +40,82 @@ describe('jobPosting repository', () => {
});
});

describe('prepareDataForDb', () => {
it('should set default job location type if it is not set', () => {
const formatedData = prepareDataForDb({});
expect(formatedData.jobLocationType).toEqual('office');
});

it('should set default job location type if ray data is not valid', () => {
const formatedData = prepareDataForDb({
jobLocationType: 'maison',
});
expect(formatedData.jobLocationType).toEqual('office');
});

it('should stringify base salary if it is not null', () => {
const formatedData = prepareDataForDb({
jobLocationType: 'maison',
baseSalary: { value: 10 },
});
expect(formatedData.baseSalary).toEqual(
JSON.stringify({
currency: 'EUR brut annuel',
minValue: null,
maxValue: null,
value: 10,
})
);
});
});
describe('formatBaseSalary', () => {
it('should return null if base salary is null', () => {
expect(formatBaseSalary(null)).toBeNull();
});

it('should return null if base salary neither value neither minValue AND maxValue', () => {
expect(formatBaseSalary({})).toBeNull();
expect(formatBaseSalary({ minValue: 10 })).toBeNull();
expect(formatBaseSalary({ maxValue: 20 })).toBeNull();
expect(
formatBaseSalary({ minValue: 10, maxValue: 20 })
).not.toBeNull();
expect(formatBaseSalary({ value: 20 })).not.toBeNull();
});

it('should compute value from minValue and maxValue if value is not set', () => {
const baseSalary = formatBaseSalary({
minValue: 10,
maxValue: 20,
});
expect(baseSalary.value).toEqual(15);
});

it('should not compute value from minValue and maxValue if value is not set', () => {
const baseSalary = formatBaseSalary({
minValue: 10,
maxValue: 20,
value: 12,
});
expect(baseSalary.value).toEqual(12);
});

it('should set default currency if currency is not set', () => {
const baseSalary = formatBaseSalary({
value: 12,
});
expect(baseSalary.currency).toEqual('EUR brut annuel');
});

it('should not set default currency if currency is set', () => {
const baseSalary = formatBaseSalary({
currency: 'USD',
value: 12,
});
expect(baseSalary.currency).toEqual('USD');
});
});

describe('formatJobPostingForAPI', () => {
it('should return an empty object if return from db is null', () => {
expect(formatJobPostingForAPI(null)).toEqual({});
Expand Down
3 changes: 3 additions & 0 deletions tests-e2e/api/job-postings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,9 @@ describe('JobPostings API Endpoints', () => {
jobStartDate: '2020-05-02',
skills: 'JavaScript, Devops, Php, ...',
validThrough: null,
baseSalary: null,
jobImmediateStart: false,
jobLocationType: 'office',
hiringOrganization: {
name: 'Flexcity',
image:
Expand Down