From 4206f367df1dceac3da2ae2af72367b50c0164d2 Mon Sep 17 00:00:00 2001 From: Federico Hurtado <fed_home@Federicos-Mac-mini.local> Date: Tue, 5 Nov 2024 12:00:57 -0500 Subject: [PATCH] Basic functionality achieved of generalized search function. Need to define allowed fields and test it now. --- backend/repository/peopleRepository.js | 59 ++++++++++++++++++++++++++ backend/routes/peopleRoutes.js | 4 +- backend/service/peopleService.js | 6 +++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/backend/repository/peopleRepository.js b/backend/repository/peopleRepository.js index 8afe193..2dcb137 100644 --- a/backend/repository/peopleRepository.js +++ b/backend/repository/peopleRepository.js @@ -251,10 +251,69 @@ async function updatePerson(personId, personInfo) { } } +// Define a whitelist of allowed fields to prevent SQL injection +const allowedSearchFields = [ + "gradYear", + "degreeYear", + "city", + "stateId", + "contactNumber", + "firstName", + "lastName", +]; + +async function search(filters) { + //begin by selecting all people + let baseQuery = ` + SELECT p.*, pd.degreeYear, a.city, a.stateId, c.contactNumber + FROM people p + LEFT JOIN peopleDegree pd ON p.peopleId = pd.peopleId + LEFT JOIN peopleXAddress pa ON p.peopleId = pa.peopleId + LEFT JOIN address a ON pa.addressId = a.addressId + LEFT JOIN peopleContact c ON p.peopleId = c.peopleId + WHERE 1=1 +`; + + // add filters to the base query in order to keep refining the set of people returned + let queryValues = []; + for (const filter of filters) { + console.log("Filter: ", filter); + + // extract field or value + let field = filter.field ? filter.field : null; + let value = filter.value ? filter.value : null; + + // throw error if the field or value is missing + if (field == null || value == null) { + throw new Error( + `Missing field or value in filter: ${JSON.stringify(filter)}` + ); + } + + // make sure the search field is allowed + if (!allowedSearchFields.includes(field)) { + throw new Error(`Invalid field specified: ${field}`); + } + + // Add condition and value to the query + baseQuery += ` AND ${field} = ?`; + queryValues.push(value); + } + + try { + const [results] = await pool.query(baseQuery, queryValues); + return results; + } catch (error) { + console.log("Error in repository w/ base query"); + throw error; + } +} + module.exports = { addPerson, searchPeopleByName, deletePersonById, updatePerson, getPersonById, + search, }; diff --git a/backend/routes/peopleRoutes.js b/backend/routes/peopleRoutes.js index b8beaa8..4bd806f 100644 --- a/backend/routes/peopleRoutes.js +++ b/backend/routes/peopleRoutes.js @@ -260,7 +260,7 @@ peopleRouter.get("/fullInfo/:id", async (req, res) => { peopleRouter.post("/search", async (req, res) => { // filters is an array of { field, value } pairs - const filters = req.body.filters; + let filters = req.body.filters; if (filters == null || !Array.isArray(filters) || filters.length == 0) { res.status(400).json({ message: "Missing filters." }); @@ -273,7 +273,7 @@ peopleRouter.post("/search", async (req, res) => { res.status(200).json({ people: results }); } catch (error) { console.log("Error in search route: ", error); - res.status(500).json({ message: "Internal service error." }); + res.status(500).json({ message: `Internal service error: ${error}` }); } }); diff --git a/backend/service/peopleService.js b/backend/service/peopleService.js index de7b084..940d5d7 100644 --- a/backend/service/peopleService.js +++ b/backend/service/peopleService.js @@ -23,6 +23,7 @@ const { deletePersonById, updatePerson, getPersonById, + search, } = require("../repository/peopleRepository"); const { addPeopleInvolvement, @@ -344,10 +345,15 @@ async function updateInvolvementsForPerson(personId, involevements) { } } +async function generalSearch(filters) { + return search(filters); +} + module.exports = { createPerson, findByName, deleteById, updatePersonById, getPersonFullDetails, + generalSearch, }; -- GitLab