Workflow and API validation for input file types

(still needs to be ckecked if a pdf is valid)
This commit is contained in:
Felix Kaspar 2023-12-21 16:42:00 +01:00
parent efd8b48a3f
commit 3e10972efa
6 changed files with 37 additions and 40 deletions

View File

@ -7,6 +7,7 @@ import { Operator } from '@stirling-pdf/shared-operations/src/functions';
import { PdfFile } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile'; import { PdfFile } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile';
import { respondWithPdfFiles } from 'utils/endpoint-utils'; 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) { router.post('/:func', upload.array("file"), async function(req: Request, res: Response) {
handleEndpoint(req, res); handleEndpoint(req, res);
@ -31,15 +32,20 @@ function handleEndpoint(req: Request, res: Response) {
const operator = getOperatorByName(req.params.func); const operator = getOperatorByName(req.params.func);
if(operator) { if(operator) {
const operation = new operator({type: req.params.func, values: req.body}); const action: Action = {type: req.params.func, values: req.body};
const validationResults = operation.validate();
if(validationResults.valid) { const validationResults = operator.schema.validate({input: pdfFiles, values: action.values});
operation.run(pdfFiles, (progress) => {}).then(pdfFiles => {
respondWithPdfFiles(res, pdfFiles, req.params.func + "_result"); if(validationResults.error) {
}) res.status(400).json(validationResults.error);
} }
else { 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 { else {

View File

@ -48,6 +48,8 @@ router.post("/:workflowUuid?", [
if(req.body.async === "false") { if(req.body.async === "false") {
console.log("Don't do async"); console.log("Don't do async");
// TODO: Check if file type == inputType for operator
traverseOperations(workflow.actions, inputs, (state) => { traverseOperations(workflow.actions, inputs, (state) => {
console.log("State: ", state); console.log("State: ", state);
}).then(async (pdfResults) => { }).then(async (pdfResults) => {
@ -88,6 +90,8 @@ router.post("/:workflowUuid?", [
} }
}); });
// TODO: Check if file type == inputType for operator
traverseOperations(workflow.actions, inputs, (state) => { traverseOperations(workflow.actions, inputs, (state) => {
console.log("State: ", state); console.log("State: ", state);
if(activeWorkflow.eventStream) if(activeWorkflow.eventStream)

View File

@ -99,9 +99,9 @@ export class Impose extends Operator {
protected static outputSchema = JoiPDFFileSchema.label(translationObject.outputs.pdfFile.name).description(translationObject.outputs.pdfFile.description); protected static outputSchema = JoiPDFFileSchema.label(translationObject.outputs.pdfFile.name).description(translationObject.outputs.pdfFile.description);
static schema = Joi.object({ static schema = Joi.object({
input: Impose.inputSchema.required(), input: Impose.inputSchema,
values: Impose.valueSchema.required(), values: Impose.valueSchema.required(),
output: Impose.outputSchema.optional() output: Impose.outputSchema
}).label(translationObject.operators.nup.friendlyName).description(translationObject.operators.nup.description); }).label(translationObject.operators.nup.friendlyName).description(translationObject.operators.nup.description);
@ -141,19 +141,4 @@ export class Impose extends Operator {
return result; 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 }
}
} }

View File

@ -22,9 +22,9 @@ export class Operator {
protected static valueSchema: Joi.Schema; protected static valueSchema: Joi.Schema;
protected static outputSchema: Joi.Schema; protected static outputSchema: Joi.Schema;
static schema: Joi.ObjectSchema<{ static schema: Joi.ObjectSchema<{
input: Joi.Schema; input: any;
values: Joi.Schema; values: any;
output: Joi.Schema; output: any;
}>; }>;
actionValues: any; actionValues: any;
@ -36,13 +36,6 @@ export class Operator {
async run(input: any[], progressCallback: (progress: Progress) => void): Promise<any[]> { async run(input: any[], progressCallback: (progress: Progress) => void): Promise<any[]> {
return []; 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 */ /** This function should be used if the Operation may take multiple files as inputs and only outputs one file */

View File

@ -19,10 +19,11 @@ export function validateOperations(actions: Action[]): { valid: boolean, reason?
if(!operator) { if(!operator) {
return { valid: false, reason: `action.type ${action.type} does not exist` } 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) { // TODO: convert everything to joiresult format
return validationResult; if(validationResult.error) {
return { valid: false, reason: validationResult.error.message};
} }
if (action.actions) { if (action.actions) {

View File

@ -1,8 +1,17 @@
import Joi from "joi"; import Joi from "joi";
import { PdfFile } from "./PdfFile"; import { PdfFile } from "./PdfFile";
export const JoiPDFFileSchema = Joi.binary().custom((value: Express.Multer.File[] | PdfFile, helpers) => { export const JoiPDFFileSchema = Joi.binary().custom((value: Express.Multer.File[] | PdfFile | PdfFile[], helpers) => {
if (!(value instanceof PdfFile)) { 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 { try {
return PdfFile.fromMulterFiles(value); return PdfFile.fromMulterFiles(value);
} catch (error) { } 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'); throw new Error('value is not of type PdfFile');
} }
} }
return value;
}, "pdffile validation"); }, "pdffile validation");