create organization_model, code refactoring

This commit is contained in:
xfarrow 2024-02-22 11:31:38 +01:00
parent 81dc61fd1f
commit 7fe83ee2e3
4 changed files with 263 additions and 196 deletions

View File

@ -0,0 +1,147 @@
/*
This code is part of Blink
licensed under GPLv3
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
const knex = require('../utils/knex_config');
/**
* Create Organization object
* @param {*} name
* @param {*} location
* @param {*} description
* @param {*} is_hiring
* @returns
*/
function organization(name, location, description, is_hiring){
const organization = {
name: name,
location: location,
description: description,
is_hiring: is_hiring
};
return organization;
}
/**
* Gets an Organization by its identifier
* @param {*} id
* @returns
*/
async function getOrganizationById(id){
const organization = await knex('Organization')
.where('id', id)
.select('*')
.first();
return organization;
}
/**
* Insert an Organization and its relative Administrator
* @param {*} organization
*/
async function insertOrganization(organization, organizationAdministratorId){
await knex.transaction(async (trx) => {
// We have to insert either both in Organization and in OrganizationAdministrator
// or in neither
const organizationResult = await trx('Organization')
.insert(organization, '*');
// Inserting in the "OrganizationAdministrator" table
await trx('OrganizationAdministrator')
.insert({
id_person: organizationAdministratorId,
id_organization: organizationResult[0].id,
});
});
}
/**
* Updates an Organization specified by the OrganizationId, if and
* only if the specified personId is one of its Administrator
* @param {*} organization
* @param {*} organizationId
* @param {*} personId
* @returns true if the row was updated, false otherwise
*/
async function updateOrganizationIfAdministrator(organization, organizationId, personId){
// // const isOrganizationAdmin = await knex('OrganizationAdministrator')
// // .where('id_person', req.jwt.person_id)
// // .where('id_organization', req.params.id)
// // .select('*')
// // .first();
// // // This introduces a Time of check Time of use weakeness
// // // which could'have been fixed by either
// // // 1) Using "whereExists", thanks to the "it's easier to ask for
// // // forgiveness than for permission" padarigm. Or,
// // // 2) Using a serializable transaction.
// // //
// // // The undersigned chose not to follow these approaches because
// // // this does not introduces any serious vulnerability. In this
// // // way it seems more readable.
// // if(!isOrganizationAdmin){
// // return res.status(403).json({error : "Forbidden"});
// // }
// // await knex('Organization')
// // .where('id', req.params.id)
// // .update({
// // name: req.body.name,
// // location: req.body.location,
// // description: req.body.description,
// // is_hiring: req.body.is_hiring
// // });
const numberOfUpdatedRows = await knex('Organization')
.where('id', organizationId)
.whereExists(function(){
this.select('*')
.from('OrganizationAdministrator')
.where('id_person', personId)
.where('id_organization', organizationId)
})
.update(organization);
return numberOfUpdatedRows == 1;
}
/**
* Deletes an Organization if the specified PersonId is
* one of its administrators
* @param {*} organizationId Id of the Organization to delete
* @param {*} personId PersonId of the supposedly administrator
* @returns true if the Organization was successfully deleted, false otherwise
*/
async function deleteOrganizationIfAdmin(organizationId, personId){
const numberOfDeletedRows = await knex('Organization')
.where({ id: organizationId })
.whereExists(function(){
this.select('*')
.from('OrganizationAdministrator')
.where('id_person', personId)
.where('id_organization', organizationId)
})
.del();
return numberOfDeletedRows == 1;
}
// Exporting a function
// means making a JavaScript function defined in one
// module available for use in another module.
module.exports = {
getOrganizationById,
organization,
insertOrganization,
updateOrganizationIfAdministrator,
updateOrganizationIfAdministrator,
deleteOrganizationIfAdmin
};

View File

@ -25,7 +25,7 @@ const bcrypt = require('bcrypt');
* @param {*} place_of_living * @param {*} place_of_living
* @returns * @returns
*/ */
function createPerson(email, password, display_name, date_of_birth, available, enabled, place_of_living) { function person(email, password, display_name, date_of_birth, available, enabled, place_of_living) {
const person = { const person = {
email: email.toLowerCase(), email: email.toLowerCase(),
password: password, password: password,
@ -139,7 +139,7 @@ async function deletePerson(person_id){
// means making a JavaScript function defined in one // means making a JavaScript function defined in one
// module available for use in another module. // module available for use in another module.
module.exports = { module.exports = {
createPerson, person,
getPersonByEmail, getPersonByEmail,
getPersonById, getPersonById,
getPersonByEmailAndPassword, getPersonByEmailAndPassword,

View File

@ -11,7 +11,7 @@
IN THE SOFTWARE. IN THE SOFTWARE.
*/ */
const knex = require('../utils/knex_config'); const organization_model = require('../models/organization_model');
/** /**
* POST Request * POST Request
@ -30,27 +30,9 @@ async function createOrganization(req, res){
} }
try{ try{
const insertedOrganization = await knex.transaction(async (trx) => { const organization = organization_model.organization(req.body.name, req.body.location, req.body.description, req.body.is_hiring);
await organization_model.insertOrganization(organization, req.jwt.person_id);
// We have to insert either both in Organization and in OrganizationAdministrator return res.status(200).json({ Organization: organization });
// or in neither
const organizationResult = await trx('Organization')
.insert({
name: req.body.name,
location: req.body.location,
description: req.body.description,
is_hiring: req.body.is_hiring,
}, '*');
// Inserting in the "OrganizationAdministrator" table
await trx('OrganizationAdministrator')
.insert({
id_person: req.jwt.person_id,
id_organization: organizationResult[0].id,
});
return organizationResult[0];
});
return res.status(200).json({ Organization: insertedOrganization });
} }
catch (error){ catch (error){
console.error('Error creating Organization:', error); console.error('Error creating Organization:', error);
@ -89,52 +71,8 @@ async function createOrganization(req, res){
} }
try { try {
const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id);
// // const isOrganizationAdmin = await knex('OrganizationAdministrator') if(isUpdateSuccessful){
// // .where('id_person', req.jwt.person_id)
// // .where('id_organization', req.params.id)
// // .select('*')
// // .first();
// // // This introduces a Time of check Time of use weakeness
// // // which could'have been fixed by either
// // // 1) Using "whereExists", thanks to the "it's easier to ask for
// // // forgiveness than for permission" padarigm. Or,
// // // 2) Using a serializable transaction.
// // //
// // // The undersigned chose not to follow these approaches because
// // // this does not introduces any serious vulnerability. In this
// // // way it seems more readable.
// // if(!isOrganizationAdmin){
// // return res.status(403).json({error : "Forbidden"});
// // }
// // await knex('Organization')
// // .where('id', req.params.id)
// // .update({
// // name: req.body.name,
// // location: req.body.location,
// // description: req.body.description,
// // is_hiring: req.body.is_hiring
// // });
const updatedRows = await knex('Organization')
.where('id', req.params.id)
.whereExists(function(){
this.select('*')
.from('OrganizationAdministrator')
.where('id_person', req.jwt.person_id)
.where('id_organization', req.params.id)
})
.update({
name: req.body.name,
location: req.body.location,
description: req.body.description,
is_hiring: req.body.is_hiring
});
if(updatedRows == 1){
return res.status(200).json({ success : "true"}); return res.status(200).json({ success : "true"});
} }
else{ else{
@ -154,28 +92,14 @@ async function createOrganization(req, res){
* one of its administrator * one of its administrator
*/ */
async function deleteOrganization(req, res){ async function deleteOrganization(req, res){
const organizationIdToDelete = req.params.id;
try { try {
const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id);
// Delete organization if admin if(isDeleteSuccessful){
const deletedRows = await knex('Organization')
.where({ id: organizationIdToDelete })
.whereExists(function(){
this.select('*')
.from('OrganizationAdministrator')
.where('id_person', req.jwt.person_id)
.where('id_organization', organizationIdToDelete)
})
.del();
if(deletedRows == 0){
return res.status(403).json({error: "Forbidden"}); return res.status(403).json({error: "Forbidden"});
} }
else{ else{
return res.status(200).json({success: true}); return res.status(200).json({success: true});
} }
} }
catch (error) { catch (error) {
console.error(error); console.error(error);
@ -193,12 +117,8 @@ async function createOrganization(req, res){
* @returns the organization. * @returns the organization.
*/ */
async function getOrganization(req, res){ async function getOrganization(req, res){
const organizationId = req.params.id;
try { try {
const organization = await knex('Organization') const organization = await organization_model.getOrganizationById(req.params.id);
.where('id', organizationId)
.select('*')
.first();
if(organization) { if(organization) {
return res.status(200).json(organization); return res.status(200).json(organization);
} }

View File

@ -52,7 +52,7 @@ async function registerPerson(req, res){
if(existingUser){ if(existingUser){
return res.status(409).json({ error: "E-mail already in use" }); return res.status(409).json({ error: "E-mail already in use" });
} }
const personToInsert = person_model.createPerson( const personToInsert = person_model.person(
req.body.email, req.body.email,
await hashPasswordPromise, await hashPasswordPromise,
req.body.display_name, req.body.display_name,