From 3e10972efa0022fbb7bf38887bce5ae2bf04b448 Mon Sep 17 00:00:00 2001 From: Felix Kaspar Date: Thu, 21 Dec 2023 16:42:00 +0100 Subject: [PATCH] Workflow and API validation for input file types (still needs to be ckecked if a pdf is valid) --- .../api/dynamic-operations-controller.ts | 20 ++++++++++++------- .../src/routes/api/workflow-controller.ts | 4 ++++ shared-operations/src/functions/impose.ts | 19 ++---------------- shared-operations/src/functions/index.ts | 13 +++--------- .../src/workflow/validateOperations.ts | 7 ++++--- shared-operations/src/wrappers/PdfFileJoi.ts | 14 ++++++++++--- 6 files changed, 37 insertions(+), 40 deletions(-) diff --git a/server-node/src/routes/api/dynamic-operations-controller.ts b/server-node/src/routes/api/dynamic-operations-controller.ts index f5ac99507..546147f30 100644 --- a/server-node/src/routes/api/dynamic-operations-controller.ts +++ b/server-node/src/routes/api/dynamic-operations-controller.ts @@ -7,6 +7,7 @@ import { Operator } from '@stirling-pdf/shared-operations/src/functions'; import { PdfFile } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile'; import { respondWithPdfFiles } from 'utils/endpoint-utils'; +import { Action } from '@stirling-pdf/shared-operations/declarations/Action'; router.post('/:func', upload.array("file"), async function(req: Request, res: Response) { handleEndpoint(req, res); @@ -31,15 +32,20 @@ function handleEndpoint(req: Request, res: Response) { const operator = getOperatorByName(req.params.func); if(operator) { - const operation = new operator({type: req.params.func, values: req.body}); - const validationResults = operation.validate(); - if(validationResults.valid) { - operation.run(pdfFiles, (progress) => {}).then(pdfFiles => { - respondWithPdfFiles(res, pdfFiles, req.params.func + "_result"); - }) + const action: Action = {type: req.params.func, values: req.body}; + + const validationResults = operator.schema.validate({input: pdfFiles, values: action.values}); + + if(validationResults.error) { + res.status(400).json(validationResults.error); } else { - res.status(400).json(validationResults); + action.values = validationResults.value.values; + const operation = new operator(action); + + operation.run(validationResults.value.input, (progress) => {}).then(pdfFiles => { + respondWithPdfFiles(res, pdfFiles, req.params.func + "_result"); + }) } } else { diff --git a/server-node/src/routes/api/workflow-controller.ts b/server-node/src/routes/api/workflow-controller.ts index 4ee0d6f8e..ee805d8bf 100644 --- a/server-node/src/routes/api/workflow-controller.ts +++ b/server-node/src/routes/api/workflow-controller.ts @@ -48,6 +48,8 @@ router.post("/:workflowUuid?", [ if(req.body.async === "false") { console.log("Don't do async"); + // TODO: Check if file type == inputType for operator + traverseOperations(workflow.actions, inputs, (state) => { console.log("State: ", state); }).then(async (pdfResults) => { @@ -88,6 +90,8 @@ router.post("/:workflowUuid?", [ } }); + // TODO: Check if file type == inputType for operator + traverseOperations(workflow.actions, inputs, (state) => { console.log("State: ", state); if(activeWorkflow.eventStream) diff --git a/shared-operations/src/functions/impose.ts b/shared-operations/src/functions/impose.ts index e6a254c3b..75cfd9bb4 100644 --- a/shared-operations/src/functions/impose.ts +++ b/shared-operations/src/functions/impose.ts @@ -99,9 +99,9 @@ export class Impose extends Operator { protected static outputSchema = JoiPDFFileSchema.label(translationObject.outputs.pdfFile.name).description(translationObject.outputs.pdfFile.description); static schema = Joi.object({ - input: Impose.inputSchema.required(), + input: Impose.inputSchema, values: Impose.valueSchema.required(), - output: Impose.outputSchema.optional() + output: Impose.outputSchema }).label(translationObject.operators.nup.friendlyName).description(translationObject.operators.nup.description); @@ -141,19 +141,4 @@ export class Impose extends Operator { return result; }) } - - validate(): { valid: boolean; reason?: string | undefined; } { - let baseValidationResults = super.validate(); - if(!baseValidationResults.valid) - return baseValidationResults; - - // TODO: Fully integrate joi in the base and remove this func - - this.actionValues = Impose.valueSchema.validate(this.actionValues); - - if(this.actionValues.error) - return { valid: false, reason: this.actionValues } - - return { valid: true } - } } \ No newline at end of file diff --git a/shared-operations/src/functions/index.ts b/shared-operations/src/functions/index.ts index 7d62cd086..709b7c7bf 100644 --- a/shared-operations/src/functions/index.ts +++ b/shared-operations/src/functions/index.ts @@ -22,9 +22,9 @@ export class Operator { protected static valueSchema: Joi.Schema; protected static outputSchema: Joi.Schema; static schema: Joi.ObjectSchema<{ - input: Joi.Schema; - values: Joi.Schema; - output: Joi.Schema; + input: any; + values: any; + output: any; }>; actionValues: any; @@ -36,13 +36,6 @@ export class Operator { async run(input: any[], progressCallback: (progress: Progress) => void): Promise { return []; } - - validate(): ValidationResult { - if(!this.actionValues) { - return { valid: false, reason: "The Operators action values were empty."} - } - return { valid: true }; - } } /** This function should be used if the Operation may take multiple files as inputs and only outputs one file */ diff --git a/shared-operations/src/workflow/validateOperations.ts b/shared-operations/src/workflow/validateOperations.ts index 55039806a..f01f7a79f 100644 --- a/shared-operations/src/workflow/validateOperations.ts +++ b/shared-operations/src/workflow/validateOperations.ts @@ -19,10 +19,11 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason? if(!operator) { return { valid: false, reason: `action.type ${action.type} does not exist` } } - const validationResult = new operator(action).validate(); + const validationResult = operator.schema.validate({values: action.values}); - if(!validationResult.valid) { - return validationResult; + // TODO: convert everything to joiresult format + if(validationResult.error) { + return { valid: false, reason: validationResult.error.message}; } if (action.actions) { diff --git a/shared-operations/src/wrappers/PdfFileJoi.ts b/shared-operations/src/wrappers/PdfFileJoi.ts index 1fd9ef16f..f06dc9178 100644 --- a/shared-operations/src/wrappers/PdfFileJoi.ts +++ b/shared-operations/src/wrappers/PdfFileJoi.ts @@ -1,8 +1,17 @@ import Joi from "joi"; import { PdfFile } from "./PdfFile"; -export const JoiPDFFileSchema = Joi.binary().custom((value: Express.Multer.File[] | PdfFile, helpers) => { - if (!(value instanceof PdfFile)) { +export const JoiPDFFileSchema = Joi.binary().custom((value: Express.Multer.File[] | PdfFile | PdfFile[], helpers) => { + if (value instanceof PdfFile) { + return value; + } + else if (Array.isArray(value)) { + if(value.every((e) => e instanceof PdfFile)) + return value; + else + throw new Error("Some elements in the array are not of type PdfFile"); + } + else { try { return PdfFile.fromMulterFiles(value); } catch (error) { @@ -10,5 +19,4 @@ export const JoiPDFFileSchema = Joi.binary().custom((value: Express.Multer.File[ throw new Error('value is not of type PdfFile'); } } - return value; }, "pdffile validation"); \ No newline at end of file