This commit is contained in:
xfarrow 2024-10-21 16:37:51 +02:00
parent b0bfd1fe59
commit ba4f1a5d8b
8 changed files with 57 additions and 26 deletions

View File

@ -14,19 +14,20 @@
const knex = require('../utils/knex_config'); const knex = require('../utils/knex_config');
const OrganizationAdmin = require('../models/organization_admin_model'); const OrganizationAdmin = require('../models/organization_admin_model');
async function insert(requester, organizationId, title, description, requirements, salary, salaryFrequency, salaryCurrency, location, tags) { async function insert(requester, organizationId, title, description, salaryMin, salaryMax, salaryFrequency, salaryCurrency, location, remote, contractType, tags) {
const isAdmin = await OrganizationAdmin.isAdmin(requester, organizationId); const isAdmin = await OrganizationAdmin.isAdmin(requester, organizationId);
if (isAdmin) { if (isAdmin) {
return await knex.transaction(async (tr) => { return await knex.transaction(async (tr) => {
const jobOffer = await tr('JobOffer').insert({ const jobOffer = await tr('JobOffer').insert({
organization_id: organizationId,
title, title,
description, description,
requirements, salary: salaryMin != null ? knex.raw(`int4range('[${salaryMin}, ${salaryMax}]')`) : null,
salary,
salary_frequency: salaryFrequency, salary_frequency: salaryFrequency,
salary_currency: salaryCurrency,
location, location,
organization_id: organizationId, remote,
salary_currency: salaryCurrency contract_type: contractType
}) })
.returning('*'); .returning('*');

View File

@ -13,6 +13,13 @@
const knex = require('../utils/knex_config'); const knex = require('../utils/knex_config');
/**
* Given an array of strings, return an array of
* database tags
*
* @param {*} tags
* @returns
*/
async function findByTags(tags) { async function findByTags(tags) {
if(!tags){ if(!tags){
return null; return null;

View File

@ -35,16 +35,30 @@ async function insert(req, res) {
} }
const tags = await Tag.findByTags(req.body.tags); const tags = await Tag.findByTags(req.body.tags);
let salaryMin = null;
let salaryMax = null;
if (req.body.salary != null && req.body.salary.length >= 1) {
salaryMin = req.body.salary[0];
if (req.body.salary.length == 2) {
salaryMax = req.body.salary[1];
} else {
salaryMax = salaryMin;
}
}
const insertedJobOffer = await JobOffer.insert( const insertedJobOffer = await JobOffer.insert(
req.jwt.person_id, req.jwt.person_id,
req.params.id, // organization id req.params.id, // organization id
req.body.title, req.body.title,
req.body.description, req.body.description,
req.body.requirements, salaryMin,
req.body.salary, salaryMax,
req.body.salary_frequency, req.body.salaryFrequency,
req.body.salary_currency, req.body.salaryCurrency,
req.body.location, req.body.location,
req.body.remote,
req.body.contractType,
tags); tags);
if (insertedJobOffer) { if (insertedJobOffer) {
@ -109,7 +123,7 @@ async function findByOrganizationId(req, res) {
errors: errors.array() errors: errors.array()
}); });
} }
const result = await JobOffer.findByOrganizationId(req.params.id); const result = await JobOffer.findByOrganizationId(req.params.id);
return res.status(200).send(result); return res.status(200).send(result);
} catch (error) { } catch (error) {

View File

@ -32,7 +32,7 @@ async function addOrganizationAdmin(req, res) {
errors: errors.array() errors: errors.array()
}); });
} }
const success = await organizationAdmin.insert(req.body.person_id, req.params.organizationId, req.jwt.person_id); const success = await organizationAdmin.insert(req.body.personId, req.params.organizationId, req.jwt.person_id);
if (success) { if (success) {
return res.status(204).send(); return res.status(204).send();
} }

View File

@ -24,23 +24,34 @@ const insertValidator = [
check('title').trim().notEmpty().escape().isLength({ check('title').trim().notEmpty().escape().isLength({
max: 2048 max: 2048
}), }),
check('description').trim().escape().isLength({ check('description').optional().trim().escape().isLength({
max: 4096 max: 4096
}), }),
check('requirements').trim().escape().isLength({ check('salary').optional().isArray().withMessage('Salary must be an array').custom((value) => {
max: 4096 if (value.length < 1 || value.length > 2) {
}), throw new Error('Salary array must have between 1 and 2 elements');
check('salary').trim().notEmpty().escape().isCurrency(), }
check('salary_frequency').trim().notEmpty().escape().isLength({ if (value !== null && !value.every((element) => typeof element === 'number')) {
throw new Error('Salary array elements must be numbers');
}
return true;
}),
check('salaryFrequency').trim().notEmpty().escape().isLength({
max: 64 max: 64
}), }),
check('salary_currency').trim().notEmpty().escape().isLength({ check('salaryCurrency').optional().trim().notEmpty().escape().isLength({
max: 64 max: 64
}), }),
check('location').trim().escape().isLength({ check('location').optional().trim().escape().isLength({
max: 256 max: 256
}), }),
check('tags').custom(tags => { check('remote').optional().trim().escape().isLength({
max: 256
}),
check('contractType').trim().escape().isLength({
max: 256
}),
check('tags').optional().custom(tags => {
if (!Array.isArray(tags)) { if (!Array.isArray(tags)) {
throw new Error('tags must be an array'); throw new Error('tags must be an array');
} }

View File

@ -17,7 +17,7 @@ const {
} = require("express-validator"); } = require("express-validator");
const addOrganizationAdminValidator = [ const addOrganizationAdminValidator = [
check('person_id').trim().notEmpty().escape(), check('personId').trim().notEmpty().escape(),
check('organizationId').trim().notEmpty().escape() check('organizationId').trim().notEmpty().escape()
]; ];

View File

@ -23,8 +23,7 @@ const createOrganizationValidator = [
check('location').trim().escape().isLength({ check('location').trim().escape().isLength({
max: 256 max: 256
}), }),
check('description').optional().trim().escape(), check('description').optional().trim().escape()
check('isHiring').optional().isBoolean()
]; ];
const updateOrganizationValidator = [ const updateOrganizationValidator = [
@ -34,8 +33,7 @@ const updateOrganizationValidator = [
check('location').trim().escape().isLength({ check('location').trim().escape().isLength({
max: 256 max: 256
}), }),
check('description').optional().trim().escape(), check('description').optional().trim().escape()
check('isHiring').optional().isBoolean()
]; ];
const deleteOrGetOrganizationValidator = [ const deleteOrGetOrganizationValidator = [

View File

@ -3,7 +3,7 @@ CREATE TYPE SalaryCurrency as ENUM ('EUR', 'USD', 'GBP');
CREATE TYPE RemotePosition as ENUM ('YES', 'NO', 'NOT_SPECIFIED', 'PARTIALLY'); CREATE TYPE RemotePosition as ENUM ('YES', 'NO', 'NOT_SPECIFIED', 'PARTIALLY');
CREATE TYPE ContractType as ENUM ('FULL-TIME','PART-TIME','INTERNSHIP','CONTRACT','FREELANCE','TEMPORARY','SEASONAL','APPRENTICESHIP','VOLUNTEER','ZERO-HOURS','FIXED-TERM','CASUAL','PROBATIONARY','SECONDMENT','JOB-SHARING'); CREATE TYPE ContractType as ENUM ('FULL-TIME','PART-TIME','INTERNSHIP','CONTRACT','FREELANCE','TEMPORARY','SEASONAL','APPRENTICESHIP','VOLUNTEER','ZERO-HOURS','FIXED-TERM','CASUAL','PROBATIONARY','SECONDMENT','JOB-SHARING');
CREATE TYPE ExperienceType as ENUM ('EDUCATION', 'WORK', 'VOLOUNTEER'); CREATE TYPE ExperienceType as ENUM ('EDUCATION', 'WORK', 'VOLOUNTEER');
CREATE TYPE SalaryFrequency as ENUM ('WEEKLY', 'YEARLY'); CREATE TYPE SalaryFrequency as ENUM ('HOURLY', 'WEEKLY', 'YEARLY');
CREATE TYPE InfoType AS ENUM ('EMAIL', 'PHONE', 'WEBSITE', 'GIT', 'MASTODON', 'YOUTUBE', 'FACEBOOK', 'INSTAGRAM', 'OTHER'); CREATE TYPE InfoType AS ENUM ('EMAIL', 'PHONE', 'WEBSITE', 'GIT', 'MASTODON', 'YOUTUBE', 'FACEBOOK', 'INSTAGRAM', 'OTHER');
-- Table: Person -- Table: Person