mirror of
				https://github.com/xfarrow/blink
				synced 2025-06-27 09:03:02 +02:00 
			
		
		
		
	create organization_model, code refactoring
This commit is contained in:
		
							
								
								
									
										147
									
								
								backend/apis/nodejs/src/models/organization_model.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								backend/apis/nodejs/src/models/organization_model.js
									
									
									
									
									
										Normal 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 | ||||
| }; | ||||
| @@ -25,7 +25,7 @@ const bcrypt = require('bcrypt'); | ||||
|  * @param {*} place_of_living  | ||||
|  * @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 = { | ||||
|         email: email.toLowerCase(), | ||||
|         password: password, | ||||
| @@ -139,7 +139,7 @@ async function deletePerson(person_id){ | ||||
| // means making a JavaScript function defined in one | ||||
| // module available for use in another module. | ||||
| module.exports = { | ||||
|     createPerson, | ||||
|     person, | ||||
|     getPersonByEmail, | ||||
|     getPersonById, | ||||
|     getPersonByEmailAndPassword, | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|     IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| const knex = require('../utils/knex_config'); | ||||
| const organization_model = require('../models/organization_model'); | ||||
|  | ||||
| /** | ||||
|  * POST Request | ||||
| @@ -24,198 +24,118 @@ const knex = require('../utils/knex_config'); | ||||
|  */ | ||||
| async function createOrganization(req, res){ | ||||
|  | ||||
|     // Ensure that the required fields are present before proceeding | ||||
|     if (!req.body.name) { | ||||
|       return res.status(400).json({ error : "Invalid request"}); | ||||
|     } | ||||
|    | ||||
|     try{ | ||||
|       const insertedOrganization = 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({ | ||||
|             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){ | ||||
|       console.error('Error creating Organization:', error); | ||||
|       res.status(500).json({error : "Internal server error"}); | ||||
|     } | ||||
|   // Ensure that the required fields are present before proceeding | ||||
|   if (!req.body.name) { | ||||
|     return res.status(400).json({ error : "Invalid request"}); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * PUT Request | ||||
|    * Updates an Organization's details | ||||
|    * | ||||
|    * Required field(s): none. | ||||
|    */ | ||||
|   async function updateOrganization(req, res){ | ||||
|   try{ | ||||
|     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); | ||||
|     return res.status(200).json({ Organization: organization }); | ||||
|   } | ||||
|   catch (error){ | ||||
|     console.error('Error creating Organization:', error); | ||||
|     res.status(500).json({error : "Internal server error"}); | ||||
|   } | ||||
| } | ||||
|    | ||||
|     const updateOrganization = {}; | ||||
| /** | ||||
|  * PUT Request | ||||
|  * Updates an Organization's details | ||||
|  * | ||||
|  * Required field(s): none. | ||||
|  */ | ||||
| async function updateOrganization(req, res){ | ||||
|  | ||||
|     if(req.body.name){ | ||||
|       updateOrganization.name = req.body.name; | ||||
|     } | ||||
|   const updateOrganization = {}; | ||||
|  | ||||
|     if(req.body.location){ | ||||
|       updateOrganization.location = req.body.location; | ||||
|     } | ||||
|    | ||||
|     if(req.body.description){ | ||||
|       updateOrganization.description = req.body.description; | ||||
|     } | ||||
|    | ||||
|     if(req.body.is_hiring){ | ||||
|       updateOrganization.is_hiring = req.body.is_hiring; | ||||
|     } | ||||
|    | ||||
|     if (Object.keys(updateOrganization).length === 0) { | ||||
|       return res.status(400).json({ error : "Bad request. No data to update"}); | ||||
|     } | ||||
|    | ||||
|     try { | ||||
|    | ||||
|       // // 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 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"}); | ||||
|       } | ||||
|       else{ | ||||
|         return res.status(404).json({error : "Organization either not found or insufficient permissions"}); | ||||
|       } | ||||
|     }  | ||||
|     catch (error) { | ||||
|       console.log(error); | ||||
|       return res.status(500).json({error : "Internal server error"}); | ||||
|     } | ||||
|   if(req.body.name){ | ||||
|     updateOrganization.name = req.body.name; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * DELETE Request | ||||
|    *  | ||||
|    * Deletes the specified organization if the logged user is | ||||
|    * one of its administrator  | ||||
|    */ | ||||
|   async function deleteOrganization(req, res){ | ||||
|     const organizationIdToDelete = req.params.id; | ||||
|    | ||||
|     try { | ||||
|    | ||||
|       // Delete organization if admin | ||||
|       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"}); | ||||
|       } | ||||
|       else{ | ||||
|         return res.status(200).json({success: true}); | ||||
|       } | ||||
|          | ||||
|     } | ||||
|     catch (error) { | ||||
|       console.error(error); | ||||
|       return res.status(500).json({error : "Internal server error"}); | ||||
|     } | ||||
|   if(req.body.location){ | ||||
|     updateOrganization.location = req.body.location; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * GET Request | ||||
|    *  | ||||
|    * Obtains an organization by its identifier. | ||||
|    *  | ||||
|    * Required field(s): none. | ||||
|    *  | ||||
|    * @returns the organization. | ||||
|    */ | ||||
|   async function getOrganization(req, res){ | ||||
|     const organizationId = req.params.id; | ||||
|     try { | ||||
|       const organization = await knex('Organization') | ||||
|         .where('id', organizationId) | ||||
|         .select('*') | ||||
|         .first(); | ||||
|       if(organization) { | ||||
|         return res.status(200).json(organization); | ||||
|       } | ||||
|       else{ | ||||
|         return res.status(404).json({error : "Not found"}); | ||||
|       } | ||||
|     } | ||||
|     catch (error) { | ||||
|       console.error("Error retrieving an organization: " + error); | ||||
|       return res.status(500).json({error : "Internal server error"}); | ||||
|     } | ||||
|   if(req.body.description){ | ||||
|     updateOrganization.description = req.body.description; | ||||
|   } | ||||
|  | ||||
|   module.exports = { | ||||
|     createOrganization, | ||||
|     getOrganization, | ||||
|     updateOrganization, | ||||
|     deleteOrganization | ||||
|   if(req.body.is_hiring){ | ||||
|     updateOrganization.is_hiring = req.body.is_hiring; | ||||
|   } | ||||
|  | ||||
|   if (Object.keys(updateOrganization).length === 0) { | ||||
|     return res.status(400).json({ error : "Bad request. No data to update"}); | ||||
|   } | ||||
|  | ||||
|   try { | ||||
|     const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id); | ||||
|     if(isUpdateSuccessful){ | ||||
|       return res.status(200).json({ success : "true"}); | ||||
|     } | ||||
|     else{ | ||||
|       return res.status(404).json({error : "Organization either not found or insufficient permissions"}); | ||||
|     } | ||||
|   }  | ||||
|   catch (error) { | ||||
|     console.log(error); | ||||
|     return res.status(500).json({error : "Internal server error"}); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * DELETE Request | ||||
|  *  | ||||
|  * Deletes the specified organization if the logged user is | ||||
|  * one of its administrator  | ||||
|  */ | ||||
| async function deleteOrganization(req, res){ | ||||
|   try { | ||||
|     const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id); | ||||
|     if(isDeleteSuccessful){ | ||||
|       return res.status(403).json({error: "Forbidden"}); | ||||
|     } | ||||
|     else{ | ||||
|       return res.status(200).json({success: true}); | ||||
|     } | ||||
|   } | ||||
|   catch (error) { | ||||
|     console.error(error); | ||||
|     return res.status(500).json({error : "Internal server error"}); | ||||
|   } | ||||
| } | ||||
|    | ||||
| /** | ||||
|  * GET Request | ||||
|  *  | ||||
|  * Obtains an organization by its identifier. | ||||
|  *  | ||||
|  * Required field(s): none. | ||||
|  *  | ||||
|  * @returns the organization. | ||||
|  */ | ||||
| async function getOrganization(req, res){ | ||||
|   try { | ||||
|     const organization = await organization_model.getOrganizationById(req.params.id); | ||||
|     if(organization) { | ||||
|       return res.status(200).json(organization); | ||||
|     } | ||||
|     else{ | ||||
|       return res.status(404).json({error : "Not found"}); | ||||
|     } | ||||
|   } | ||||
|   catch (error) { | ||||
|     console.error("Error retrieving an organization: " + error); | ||||
|     return res.status(500).json({error : "Internal server error"}); | ||||
|   } | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|   createOrganization, | ||||
|   getOrganization, | ||||
|   updateOrganization, | ||||
|   deleteOrganization | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ async function registerPerson(req, res){ | ||||
|     if(existingUser){ | ||||
|       return res.status(409).json({ error: "E-mail already in use" }); | ||||
|     } | ||||
|     const personToInsert = person_model.createPerson( | ||||
|     const personToInsert = person_model.person( | ||||
|       req.body.email,  | ||||
|       await hashPasswordPromise, | ||||
|       req.body.display_name, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user