diff --git a/src/middleware/process-payload.ts b/src/middleware/process-payload.ts new file mode 100644 index 0000000000..d767fa5179 --- /dev/null +++ b/src/middleware/process-payload.ts @@ -0,0 +1,65 @@ +/** + * Will check the fields system table for any special operations that need to be done on the field + * value, this can include hashing the value or generating a UUID + */ + +import { RequestHandler } from 'express'; +import asyncHandler from 'express-async-handler'; +import { FieldInfo } from '../types/field'; +import bcrypt from 'bcrypt'; + +type Operation = 'create' | 'update'; + +/** + * @TODO + * + * This needs a bit of extra thinking. + * - There's a difference between update / create payload processing + * - Some processing types need the whole payload (slug) + * - What happens for fields that aren't in the payload but need to be set on create? + */ + +const processPayload = (operation: Operation) => { + const middleware: RequestHandler = asyncHandler(async (req, res, next) => { + // Get the fields that have a special operation associated with them + const fieldsInPayload = Object.keys(req.body); + + const fieldInfoForFields = await req.loaders.fields.loadMany( + fieldsInPayload.map((field) => ({ + collection: req.collection, + field: field, + })) + ); + + const specialFields = fieldInfoForFields.filter((field) => { + if (field instanceof Error) return false; + return field.special !== null; + }) as FieldInfo[]; + + for (const field of specialFields) { + req.body[field.field] = await processField(req.collection, field, req.body, operation); + } + + next(); + }); + + return middleware; +}; + +async function processField( + collection: string, + field: FieldInfo, + payload: Record, + operation: Operation +) { + switch (field.special) { + case 'hash': + return await hash(payload[field.field]); + } +} + +async function hash(value: string | number) { + return await bcrypt.hash(value, Number(process.env.SALT_ROUNDS)); +} + +export default processPayload; diff --git a/src/routes/items.ts b/src/routes/items.ts index 2a4ce6b791..acb041cbdb 100644 --- a/src/routes/items.ts +++ b/src/routes/items.ts @@ -2,15 +2,17 @@ import express from 'express'; import asyncHandler from 'express-async-handler'; import { createItem, readItems, readItem, updateItem, deleteItem } from '../services/items'; import sanitizeQuery from '../middleware/sanitize-query'; -import collectionExists from '../middleware/collection-exists'; +import validateCollection from '../middleware/validate-collection'; import validateQuery from '../middleware/validate-query'; import * as MetaService from '../services/meta'; +import processPayload from '../middleware/process-payload'; const router = express.Router(); router.post( '/:collection', - collectionExists, + validateCollection, + processPayload('create'), asyncHandler(async (req, res) => { await createItem(req.params.collection, req.body); res.status(200).end(); @@ -19,7 +21,7 @@ router.post( router.get( '/:collection', - collectionExists, + validateCollection, sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -37,7 +39,7 @@ router.get( router.get( '/:collection/:pk', - collectionExists, + validateCollection, asyncHandler(async (req, res) => { const record = await readItem(req.params.collection, req.params.pk); @@ -49,7 +51,7 @@ router.get( router.patch( '/:collection/:pk', - collectionExists, + validateCollection, asyncHandler(async (req, res) => { await updateItem(req.params.collection, req.params.pk, req.body); return res.status(200).end(); @@ -58,7 +60,7 @@ router.patch( router.delete( '/:collection/:pk', - collectionExists, + validateCollection, asyncHandler(async (req, res) => { await deleteItem(req.params.collection, req.params.pk); return res.status(200).end();