From 53406040eae28211544230c9c05397c38b6fb4ad Mon Sep 17 00:00:00 2001 From: Dave Luhman Date: Sun, 12 May 2024 16:15:52 -0500 Subject: [PATCH] searching by status is fixed. ToolID is next up --- src/config/db.js | 2 +- src/middleware/tool.js | 701 +++++++++++++++++++++-------------------- src/views/profile.hbs | 2 +- 3 files changed, 367 insertions(+), 338 deletions(-) diff --git a/src/config/db.js b/src/config/db.js index 3b703dbe..a62c34a2 100644 --- a/src/config/db.js +++ b/src/config/db.js @@ -48,7 +48,7 @@ async function createDefaultServiceAssignments() { name: 'DEPOT', description: 'Default stockroom for serialized tools', type: 'Stockroom', - active: true, + active: true }, { _id: '64a34b651288871770df1087', diff --git a/src/middleware/tool.js b/src/middleware/tool.js index bc28582f..d2ab858c 100644 --- a/src/middleware/tool.js +++ b/src/middleware/tool.js @@ -1,3 +1,5 @@ +import e from 'express' +import ServiceAssignment from '../models/ServiceAssignment.model.js' import Tool from '../models/Tool.model.js' import ToolHistory from '../models/ToolHistory.model.js' import { deduplicateArray, mutateToArray, paginate } from './util.js' @@ -70,374 +72,401 @@ async function getToolByID(req, res, next) { } return next() } -/** - * - * @param {string} req.body.searchBy The key to search by - * @param {string} req.body.searchValue The terms to search for - * @param {number} req.query.p Page Number - * @param {object} res.locals.pagination {page: targetPage, pageCount: pageCount} pagination data - * @param {array} res.locals.tools returns array of tools in response - * @param {*} next - * @returns {array} - */ -async function searchTools(req, res, next) { - console.info('[MW] searchTools-in'.bgBlue.white) - const { sortField, sortOrder } = req.user.preferences - const { searchBy, searchTerm } = req.body - switch (searchBy) { - case 'Search By': - res.locals.message = 'You must specify search parameters' - return next() - case 'serviceAssignment': - res.locals.searchBy = searchBy - res.locals.searchTerm = searchTerm - res.locals.tools = await Tool.where('serviceAssignment') - .equals(searchTerm) - .sort({ [sortField]: sortOrder }) - .exec() - break - case 'category': - res.locals.searchBy = searchBy - res.locals.searchTerm = searchTerm - res.locals.tools = await Tool.where('category') - .equals(searchTerm) - .sort({ [sortField]: sortOrder }) - .exec() - break - case 'status': - res.locals.searchBy = searchBy - res.locals.searchTerm = searchTerm - res.locals.tools = await Tool.find().where('serviceAssignment.type').equals(searchBy === 'Checked Out' ? !'Stockroom' : 'Stockroom').sort( - { [sortField]: sortOrder } - ) - break - default: - res.locals.searchTerm = searchTerm - res.locals.searchBy = searchBy - res.locals.tools = await Tool.find({ - [searchBy]: { $eq: searchTerm } - }).sort({ [sortField]: sortOrder }) - break - } - res.locals.totalFound = res.locals.tools.length - console.info('[MW] searchTools-out'.bgWhite.blue) - return next() -} -/** - * - * @param {object} req.body The tool object to create - * @param {string} res.locals.message The message to display to the user - * @param {*} next - * @returns - */ -async function createTool(req, res, next) { - try { - console.info('[MW] createTool-in'.bgBlue.white) - const { - serialNumber, - modelNumber, - barcode, - description, - toolID, - serviceAssignment, - category, - manufacturer, - width, - height, - length, - weight - } = req.body - if (!(serialNumber || modelNumber) || !barcode) { - throw new Error({ message: 'Missing required fields', status: 400 }) +async function getCheckedInTools() { + const tools = await Tool.find().where('archived').equals(false) + const activeServiceAssignmentsDocs = await ServiceAssignment.find().where('type').equals('Stockroom') + const activeServiceAssignmentArray = activeServiceAssignmentsDocs.map(item => { return item._id.valueOf() }) + const checkedInTools = [] + for (let i = 0; i < tools.length; i++) { + for (let ii = 0; ii < activeServiceAssignmentArray.length; ii++) { + if (activeServiceAssignmentArray[ii] == tools[i].serviceAssignment?._id) { + checkedInTools.push(tools[i]) + } + }} + return checkedInTools + } + async function getCheckedOutTools() { + const tools = await Tool.find().where('archived').equals(false) + const activeServiceAssignmentsDocs = await ServiceAssignment.find().where('type').ne('Stockroom') + const activeServiceAssignmentArray = activeServiceAssignmentsDocs.map(item => { return item._id.valueOf() }) + const checkedInTools = [] + for (let i = 0; i < tools.length; i++) { + for (let ii = 0; ii < activeServiceAssignmentArray.length; ii++) { + if (activeServiceAssignmentArray[ii] == tools[i].serviceAssignment?._id) { + checkedInTools.push(tools[i]) + } + }} + return checkedInTools } - const existing = await Tool.findOne({ - $or: [{ serialNumber }, { barcode }] - }) - if (existing) { - res.locals.tools = mutateToArray(existing) - throw new Error({ message: 'Tool already exists', status: 400 }) + /** + * + * @param {string} req.body.searchBy The key to search by + * @param {string} req.body.searchValue The terms to search for + * @param {number} req.query.p Page Number + * @param {object} res.locals.pagination {page: targetPage, pageCount: pageCount} pagination data + * @param {array} res.locals.tools returns array of tools in response + * @param {*} next + * @returns {array} + */ + async function searchTools(req, res, next) { + console.info('[MW] searchTools-in'.bgBlue.white) + const { sortField, sortOrder } = req.user.preferences + const { searchBy, searchTerm } = req.body + let tools + switch (searchBy) { + case 'Search By': + res.locals.message = 'You must specify search parameters' + return next() + case 'serviceAssignment': + res.locals.searchBy = searchBy + res.locals.searchTerm = searchTerm + res.locals.tools = await Tool.where('serviceAssignment') + .equals(searchTerm) + .sort({ [sortField]: sortOrder }) + .exec() + break + case 'category': + res.locals.searchBy = searchBy + res.locals.searchTerm = searchTerm + res.locals.tools = await Tool.where('category') + .equals(searchTerm) + .sort({ [sortField]: sortOrder }) + .exec() + break + case 'status': + res.locals.searchBy = searchBy + res.locals.searchTerm = searchTerm + if(searchTerm === 'Checked In') res.locals.tools = await getCheckedInTools() + else res.locals.tools = await getCheckedOutTools() + break + default: + res.locals.searchTerm = searchTerm + res.locals.searchBy = searchBy + res.locals.tools = await Tool.find({ + [searchBy]: { $eq: searchTerm } + }).sort({ [sortField]: sortOrder }) + break } - // TODO: verify input data is sanitized - const newTool = await Tool.create({ - serialNumber, - modelNumber, - barcode, - description, - toolID, - serviceAssignment, - category, - manufacturer, - size: { - height, + res.locals.totalFound = res.locals.tools.length + console.info('[MW] searchTools-out'.bgWhite.blue) + return next() + } + + /** + * + * @param {object} req.body The tool object to create + * @param {string} res.locals.message The message to display to the user + * @param {*} next + * @returns + */ + async function createTool(req, res, next) { + try { + console.info('[MW] createTool-in'.bgBlue.white) + const { + serialNumber, + modelNumber, + barcode, + description, + toolID, + serviceAssignment, + category, + manufacturer, width, + height, length, weight - }, - updatedBy: req.user._id, - createdBy: req.user._id - }) - if (!newTool) { - throw new Error({ message: 'Could not create tool', status: 500 }) - } - await ToolHistory.create({ - _id: newTool._id, - history: [newTool] - }) - res.locals.message = 'Successfully Made A New Tool' - res.locals.tools = [newTool] - res.locals.pagination = { pageCount: 1 } - res.status(201) - console.info(`[MW] Tool Successfully Created ${newTool._id}`.green) - console.info('[MW] createTool-out-3'.bgWhite.blue) - next() - } catch (error) { - res.locals.message = error.message - res.status(error.status || 500).redirect('back') - } -} - -async function updateToolHistory(toolID) { - const oldTool = await Tool.findById(toolID) - await ToolHistory.findByIdAndUpdate( - { _id: toolID }, - { - $push: { history: oldTool }, - $inc: { __v: 1 }, - $set: { updatedAt: Date.now() } - } - ) -} - -/** - * - * @param {*} req.body._id The id of the tool to update - * @param {*} res - * @param {*} next - */ -async function updateTool(req, res, next) { - console.info('[MW] updateTool-in'.bgBlue.white) - const ut = async (newToolData) => { - const { - id, - modelNumber, - description, - toolID, - serviceAssignment, - category, - manufacturer, - width, - height, - length, - weight - } = newToolData - updateToolHistory(id) - const updatedTool = await Tool.findByIdAndUpdate( - { $eq: id }, - { + } = req.body + if (!(serialNumber || modelNumber) || !barcode) { + throw new Error({ message: 'Missing required fields', status: 400 }) + } + const existing = await Tool.findOne({ + $or: [{ serialNumber }, { barcode }] + }) + if (existing) { + res.locals.tools = mutateToArray(existing) + throw new Error({ message: 'Tool already exists', status: 400 }) + } + // TODO: verify input data is sanitized + const newTool = await Tool.create({ + serialNumber, modelNumber, + barcode, description, toolID, serviceAssignment, category, manufacturer, size: { - width, height, + width, length, weight }, + updatedBy: req.user._id, + createdBy: req.user._id + }) + if (!newTool) { + throw new Error({ message: 'Could not create tool', status: 500 }) + } + await ToolHistory.create({ + _id: newTool._id, + history: [newTool] + }) + res.locals.message = 'Successfully Made A New Tool' + res.locals.tools = [newTool] + res.locals.pagination = { pageCount: 1 } + res.status(201) + console.info(`[MW] Tool Successfully Created ${newTool._id}`.green) + console.info('[MW] createTool-out-3'.bgWhite.blue) + next() + } catch (error) { + res.locals.message = error.message + res.status(error.status || 500).redirect('back') + } + } + + async function updateToolHistory(toolID) { + const oldTool = await Tool.findById(toolID) + await ToolHistory.findByIdAndUpdate( + { _id: toolID }, + { + $push: { history: oldTool }, $inc: { __v: 1 }, $set: { updatedAt: Date.now() } - }, - { new: true } + } ) - - return updatedTool - } - const updatedToolArray = [] - if (typeof req.body.id === 'string') { - console.table(req.body) - const updatedTool = await ut(req.body) - updatedToolArray.push(updatedTool) } - if (Array.isArray(req.body._id) && req.body._id.length > 0) { - for (let i = 0; i < req.body.id.length > 100; i++) { - const updatedTool = await ut({ - _id: req.body.id[i], - modelNumber: req.body.modelNumber[i], - description: req.body.description[i], - toolID: req.body.toolID[i], - serviceAssignment: req.body.serviceAssignment[i], - category: req.body.category[i], - manufacturer: req.body.manufacturer[i], - size: { - width: req.body.size.width[i], - height: req.body.size.height[i], - length: req.body.size.length[i], - weight: req.body.size.weight[i] + + /** + * + * @param {*} req.body._id The id of the tool to update + * @param {*} res + * @param {*} next + */ + async function updateTool(req, res, next) { + console.info('[MW] updateTool-in'.bgBlue.white) + const ut = async (newToolData) => { + const { + id, + modelNumber, + description, + toolID, + serviceAssignment, + category, + manufacturer, + width, + height, + length, + weight + } = newToolData + updateToolHistory(id) + const updatedTool = await Tool.findByIdAndUpdate( + { $eq: id }, + { + modelNumber, + description, + toolID, + serviceAssignment, + category, + manufacturer, + size: { + width, + height, + length, + weight + }, + $inc: { __v: 1 }, + $set: { updatedAt: Date.now() } }, - $inc: { __v: 1 }, - $set: { updatedAt: Date.now() } - }) + { new: true } + ) + + return updatedTool + } + const updatedToolArray = [] + if (typeof req.body.id === 'string') { + console.table(req.body) + const updatedTool = await ut(req.body) updatedToolArray.push(updatedTool) } + if (Array.isArray(req.body._id) && req.body._id.length > 0) { + for (let i = 0; i < req.body.id.length > 100; i++) { + const updatedTool = await ut({ + _id: req.body.id[i], + modelNumber: req.body.modelNumber[i], + description: req.body.description[i], + toolID: req.body.toolID[i], + serviceAssignment: req.body.serviceAssignment[i], + category: req.body.category[i], + manufacturer: req.body.manufacturer[i], + size: { + width: req.body.size.width[i], + height: req.body.size.height[i], + length: req.body.size.length[i], + weight: req.body.size.weight[i] + }, + $inc: { __v: 1 }, + $set: { updatedAt: Date.now() } + }) + updatedToolArray.push(updatedTool) + } + } + res.locals.tools = updatedToolArray + res.locals.pagination = { page: 1, pageCount: 1 } + res.status(200) + console.info('[MW] Successfully Updated Tools: '.green + updatedToolArray) + console.info('[MW] updateTool-out-1'.bgWhite.blue) + next() } - res.locals.tools = updatedToolArray - res.locals.pagination = { page: 1, pageCount: 1 } - res.status(200) - console.info('[MW] Successfully Updated Tools: '.green + updatedToolArray) - console.info('[MW] updateTool-out-1'.bgWhite.blue) - next() -} -/** - * archiveTool - Archives a tool - * @param {string} req.params.id The id of the tool to archive - * @param {string} res.locals.message The message to display to the user - * @param {array} res.locals.tools The tool that was archived - * @param {number} res.status The status code to return - * @param {*} next - */ -async function archiveTool(req, res, next) { - console.info('[MW] archiveTool-in'.bgBlue.white) - const { id } = req.params - const archivedTool = await Tool.findByIdAndUpdate( - { _id: id }, - { archived: true }, - { new: true } - ) - await ToolHistory.findByIdAndUpdate( - { _id: id }, - { $push: { history: [archivedTool] } }, - { new: true } - ) - res.locals.message = 'Successfully Marked Tool Archived' - res.locals.tools = [archivedTool] - res.status(201) - console.info('[MW] archiveTool-out-1'.bgWhite.blue) - next() -} - -async function checkTools(req, res, next) { - if (!req.body.searchTerms) { - res.locals.message = 'No Tools Submitted For Status Change' - console.warn('[MW checkTools-out-1'.bgWhite.blue) - res.status(400).redirect('back') - return next() - } - const search = deduplicateArray(req.body.searchTerms.split(/\r?\n/)) - const toolsToBeChanged = await lookupToolWrapper(search) - if (toolsToBeChanged.length === 0) { - res.locals.message = 'No Tools Found Matching ' - } - res.locals.target = (req.body.serviceAssignmentInput === '') ? req.body.serviceAssignmentSelector : req.body.serviceAssignmentInput - res.locals.tools = toolsToBeChanged - next() -} -/** - * - * @param {string} searchTerm search target - * @param {string} searchField optional, key to search - if not provided, will search all fields - * @returns {object} - */ -async function lookupTool(searchTerm) { - searchTerm = searchTerm.toUpperCase() - let result = await Tool.findOne({ serialNumber: { $eq: searchTerm } }) - if (!result) { - result = await Tool.findOne({ barcode: { $eq: searchTerm } }) - } - if (!result) { - result = await Tool.findOne({ toolID: { $eq: searchTerm } }) + /** + * archiveTool - Archives a tool + * @param {string} req.params.id The id of the tool to archive + * @param {string} res.locals.message The message to display to the user + * @param {array} res.locals.tools The tool that was archived + * @param {number} res.status The status code to return + * @param {*} next + */ + async function archiveTool(req, res, next) { + console.info('[MW] archiveTool-in'.bgBlue.white) + const { id } = req.params + const archivedTool = await Tool.findByIdAndUpdate( + { _id: id }, + { archived: true }, + { new: true } + ) + await ToolHistory.findByIdAndUpdate( + { _id: id }, + { $push: { history: [archivedTool] } }, + { new: true } + ) + res.locals.message = 'Successfully Marked Tool Archived' + res.locals.tools = [archivedTool] + res.status(201) + console.info('[MW] archiveTool-out-1'.bgWhite.blue) + next() } - if (!result) { - result = {} + + async function checkTools(req, res, next) { + if (!req.body.searchTerms) { + res.locals.message = 'No Tools Submitted For Status Change' + console.warn('[MW checkTools-out-1'.bgWhite.blue) + res.status(400).redirect('back') + return next() + } + const search = deduplicateArray(req.body.searchTerms.split(/\r?\n/)) + const toolsToBeChanged = await lookupToolWrapper(search) + if (toolsToBeChanged.length === 0) { + res.locals.message = 'No Tools Found Matching ' + } + res.locals.target = (req.body.serviceAssignmentInput === '') ? req.body.serviceAssignmentSelector : req.body.serviceAssignmentInput + res.locals.tools = toolsToBeChanged + next() } - console.log(result) - return result -} -/** - * @name lookupToolWrapper - * @desc iterator for looking up multiple search terms for checkTools - * @param {*} searchTerms - * @return {*} array of tools, with dummy objects if nothing is found - */ -async function lookupToolWrapper(searchTerms) { - const tools = [] - for (let i = 0; i < searchTerms.length; i++) { - const result = await lookupTool(searchTerms[i]) + /** + * + * @param {string} searchTerm search target + * @param {string} searchField optional, key to search - if not provided, will search all fields + * @returns {object} + */ + async function lookupTool(searchTerm) { + searchTerm = searchTerm.toUpperCase() + let result = await Tool.findOne({ serialNumber: { $eq: searchTerm } }) + if (!result) { + result = await Tool.findOne({ barcode: { $eq: searchTerm } }) + } + if (!result) { + result = await Tool.findOne({ toolID: { $eq: searchTerm } }) + } + if (!result) { + result = {} + } console.log(result) - if (result?.serialNumber === undefined) { - tools.push({ - serialNumber: searchTerms[i] - }) - } else tools.push(result) + return result + } + /** + * @name lookupToolWrapper + * @desc iterator for looking up multiple search terms for checkTools + * @param {*} searchTerms + * @return {*} array of tools, with dummy objects if nothing is found + */ + async function lookupToolWrapper(searchTerms) { + const tools = [] + for (let i = 0; i < searchTerms.length; i++) { + const result = await lookupTool(searchTerms[i]) + console.log(result) + if (result?.serialNumber === undefined) { + tools.push({ + serialNumber: searchTerms[i] + }) + } else tools.push(result) + } + return tools } - return tools -} -async function submitCheckInOut(req, res, next) { - const id = mutateToArray(req.body.id) - const newServiceAssignment = mutateToArray(req.body.newServiceAssignment) - const newTools = [] - for (let i = 0; i < id.length; i++) { - if (id[i] === 'toolNotFound') break - updateToolHistory(id[i]) - newTools.push( - await Tool.findByIdAndUpdate( - { _id: id[i] }, - { - serviceAssignment: newServiceAssignment[i], - $inc: { __v: 1 }, - $set: { updatedAt: Date.now() } - }, - { new: true } + async function submitCheckInOut(req, res, next) { + const id = mutateToArray(req.body.id) + const newServiceAssignment = mutateToArray(req.body.newServiceAssignment) + const newTools = [] + for (let i = 0; i < id.length; i++) { + if (id[i] === 'toolNotFound') break + updateToolHistory(id[i]) + newTools.push( + await Tool.findByIdAndUpdate( + { _id: id[i] }, + { + serviceAssignment: newServiceAssignment[i], + $inc: { __v: 1 }, + $set: { updatedAt: Date.now() } + }, + { new: true } + ) ) - ) + } + res.locals.tools = newTools + res.locals.message = `${newTools.length} tool(s) have been updated` + next() } - res.locals.tools = newTools - res.locals.message = `${newTools.length} tool(s) have been updated` - next() -} -const generatePrinterFriendlyToolList = async (req, res, next) => { - try { - if (!res.locals.tools) return next() - const { tools } = res.locals - const printerFriendlyToolArray = await tools.map((tool) => { - const { - serialNumber, - modelNumber, - toolID, - barcode, - description - } = tool - return { - serialNumber, - modelNumber, - toolID, - barcode, - description - } - }) - if (printerFriendlyToolArray?.length === 0) throw new Error('There was a problem creating the printer friendly data') - res.locals.printerFriendlyTools = printerFriendlyToolArray || [] - return next() - } catch (err) { - res.locals.message = err.message - res.locals.printerFriendlyTools = [] - return next() + const generatePrinterFriendlyToolList = async (req, res, next) => { + try { + if (!res.locals.tools) return next() + const { tools } = res.locals + const printerFriendlyToolArray = await tools.map((tool) => { + const { + serialNumber, + modelNumber, + toolID, + barcode, + description + } = tool + return { + serialNumber, + modelNumber, + toolID, + barcode, + description + } + }) + if (printerFriendlyToolArray?.length === 0) throw new Error('There was a problem creating the printer friendly data') + res.locals.printerFriendlyTools = printerFriendlyToolArray || [] + return next() + } catch (err) { + res.locals.message = err.message + res.locals.printerFriendlyTools = [] + return next() + } } -} -export { - getAllTools, - getActiveTools, - getToolByID, - searchTools, - createTool, - updateTool, - archiveTool, - checkTools, - submitCheckInOut, - generatePrinterFriendlyToolList -} + export { + getAllTools, + getActiveTools, + getToolByID, + searchTools, + createTool, + updateTool, + archiveTool, + checkTools, + submitCheckInOut, + generatePrinterFriendlyToolList + } diff --git a/src/views/profile.hbs b/src/views/profile.hbs index 05fe44d9..759fa1e6 100644 --- a/src/views/profile.hbs +++ b/src/views/profile.hbs @@ -1,4 +1,4 @@ -
+

User Profile