diff --git a/server-node/src/routes/api/api-controller.ts b/server-node/src/routes/api/api-controller.ts index 77e03872f..4be925944 100644 --- a/server-node/src/routes/api/api-controller.ts +++ b/server-node/src/routes/api/api-controller.ts @@ -1,8 +1,7 @@ import express, { Request, Response } from 'express'; import workflow from './workflow-controller'; -// import operations from './operations-controller'; -// import conversions from './conversions-controller'; +import dynamicOperations from './dynamic-operations-controller'; const router = express.Router(); @@ -11,8 +10,7 @@ router.get("/", (req: Request, res: Response) => { res.status(501).json({"Error": "Unfinished Endpoint. This sould probably send some api docs?"}); }); -// router.use("/operations", operations); -// router.use("/conversions", conversions); router.use("/workflow", workflow); +router.use("/", dynamicOperations); export default router; \ No newline at end of file diff --git a/server-node/src/routes/api/conversions-controller.ts b/server-node/src/routes/api/conversions-controller.ts deleted file mode 100644 index 8deb61440..000000000 --- a/server-node/src/routes/api/conversions-controller.ts +++ /dev/null @@ -1,27 +0,0 @@ - -import { respondWithPdfFile, response_mustHaveExactlyOneFile, response_dependencyNotConfigured } from '../../utils/endpoint-utils'; -import { fileToPdf, isLibreOfficeInstalled } from '../../utils/libre-office-utils'; - -import express, { Request, Response } from 'express'; -const router = express.Router(); -import multer from 'multer'; -const upload = multer(); -import Joi from 'joi'; - -router.post('/file-to-pdf', upload.single("file"), async function(req: Request, res: Response) { - if (!req.file) { - response_mustHaveExactlyOneFile(res); - return; - } - - const isInstalled = await isLibreOfficeInstalled(); - if (isInstalled) { - const outputFile = await fileToPdf(req.file.buffer, req.file.originalname); - respondWithPdfFile(res, outputFile); - return; - } - - response_dependencyNotConfigured(res, "LibreOffice"); -}); - -export default router; diff --git a/server-node/src/routes/api/dynamic-operations-controller.ts b/server-node/src/routes/api/dynamic-operations-controller.ts new file mode 100644 index 000000000..ff124328b --- /dev/null +++ b/server-node/src/routes/api/dynamic-operations-controller.ts @@ -0,0 +1,50 @@ +import express, { Request, Response } from 'express'; +const router = express.Router(); +import multer from 'multer'; +const upload = multer(); +import { getOperatorByName } from '@stirling-pdf/shared-operations/src/workflow/getOperatorByName'; +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'; + +router.post('/:func', upload.array("file"), async function(req: Request, res: Response) { + handleEndpoint(req, res); +}); + +router.post('/:dir/:func', upload.array("file"), async function(req: Request, res: Response) { + handleEndpoint(req, res); +}); + +function handleEndpoint(req: Request, res: Response) { + if(!req.files || req.files.length == 0) { + res.status(400).json({error: "no input file(s) were provided"}) + return; + } + + let pdfFiles: PdfFile[] = []; + if (Array.isArray(req.files)) + pdfFiles = PdfFile.fromMulterFiles(req.files); + else { + pdfFiles = PdfFile.fromMulterFiles(Object.values(req.files).flatMap(va => va)); + } + + const operator: typeof 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"); + }) + } + else { + res.status(400).json(validationResults); + } + } + else { + res.status(400).json({error: `the operator of type ${req.params.func} does not exist`}) + } +} + +export default router; diff --git a/server-node/src/routes/api/operations-controller.ts b/server-node/src/routes/api/operations-controller.ts deleted file mode 100644 index 7a0ae2b89..000000000 --- a/server-node/src/routes/api/operations-controller.ts +++ /dev/null @@ -1,157 +0,0 @@ - -import { respondWithPdfFile, respondWithPdfFiles, response_mustHaveExactlyOneFile } from '../../utils/endpoint-utils'; -import { PdfFile, /*PdfFileSchema*/ } from '@stirling-pdf/shared-operations/src/wrappers/PdfFile' -//import { ScalePageSchema } from '@stirling-pdf/shared-operations/src/functions/scalePage' - -import express, { Request, Response, RequestHandler } from 'express'; -const router = express.Router(); -import multer from 'multer'; -const upload = multer(); -import Joi from 'joi'; - -function registerEndpoint(endpoint: string, - nameToAppend: string, - fileHandler: RequestHandler, - operator: any - ): void { - router.post(endpoint, fileHandler, async function(req: Request, res: Response) { - const body = req.body; - if (req.file) { - body.file = PdfFile.fromMulterFile(req.file); - } - if (req.files) { - if (Array.isArray(req.files)) - body.files = PdfFile.fromMulterFiles(req.files); - else { - const flattenedFiles = Object.values(req.files).flatMap(va => va); - body.files = PdfFile.fromMulterFiles(flattenedFiles); - } - } - - console.log(req.body) - const { error, value } = operator.spec.toJoiSchema().validate(req.body); - if (error) { - res.status(400).send(error.details); - return; - } - - const processed = await operator.exec(value) - - if (body.files && Array.isArray(processed)) { // MIMO - respondWithPdfFiles(res, processed, nameToAppend); - } else if (body.file && Array.isArray(processed)) { // SIMO - respondWithPdfFiles(res, processed, body.file.filename + nameToAppend); - } else if (body.files && !Array.isArray(processed)) { // MISO - respondWithPdfFile(res, processed); - } else if (body.file && !Array.isArray(processed)) { // SISO - respondWithPdfFile(res, processed); - } - }); -} - - -///////////////////// -// Page Operations // -///////////////////// -/*registerEndpoint("/merge-pdfs", "", upload.any(), Operations.mergePDFs, Joi.object({ - files: Joi.array().items(PdfFileSchema).required(), -}).required()); - -registerEndpoint("/split-pdf", "_split", upload.single("file"), Operations.splitPdfByIndex, Joi.object({ - file: PdfFileSchema.required(), - pageIndexes: Joi.string().required(), -}).required()); - -registerEndpoint("/rearrange-pages", "", upload.single("file"), Operations.arrangePages, Joi.object({ - file: PdfFileSchema.required(), - arrangementConfig: Joi.string().required(), -}).required()); - -registerEndpoint("/rotate-pdf", "", upload.single("file"), Operations.rotatePages, Joi.object({ - file: PdfFileSchema.required(), - rotation: Joi.alternatives().try(Joi.number(), Joi.array().items(Joi.number())).required(), -}).required()); - -registerEndpoint("/remove-pages", "", upload.single("file"), Operations.removePages, Joi.object({ - file: PdfFileSchema.required(), - pageSelector: Joi.string().required(), -}).required()); -*/ -// registerEndpoint("/impose", "", upload.single("file"), Operations.Impose); -/* -registerEndpoint("/scale-pages", "", upload.single("file"), Operations.scalePage, ScalePageSchema.required()); - -//Auto Split Pages -//Adjust Colours/Contrast -//Crop - -registerEndpoint("/extract-pages", "", upload.single("file"), Operations.extractPages, Joi.object({ - file: PdfFileSchema.required(), - pageIndexes: Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.number())).required(), -}).required()); - -//PDF to Single large Page - - -///////////////////// -// Convert // -///////////////////// -//Image to PDF -//Convert file to PDF -//URL to PDF -//HTML to PDF -//Markdown to PDF -//PDF to Image -//PDF to Word -//PDF to Presentation -//PDF to Text/RTF -//PDF to HTML -//PDF to PDF/A - - -///////////////////// -// Security // -///////////////////// -//Add Password -//Remove Password -//Change Permissions -//Add Watermark -//Sign with Certificate -//Sanitize -//Auto Redact - -///////////////////// -// Miscellaneous // -///////////////////// -//OCR -//Add image -//Compress -//Extract Images - -registerEndpoint("/update-metadata", "", upload.single("file"), Operations.updateMetadata, Joi.object({ - file: PdfFileSchema.required(), - deleteAll: Joi.string(), - author: Joi.string(), - creationDate: Joi.string(), - creator: Joi.string(), - keywords: Joi.string(), - modificationDate: Joi.string(), - producer: Joi.string(), - subject: Joi.string(), - title: Joi.string(), - trapped: Joi.string(), - allRequestParams: Joi.object().pattern(Joi.string(), Joi.string()), -}).required()); - -//Detect/Split Scanned photos -//Sign -//Flatten -//Repair -//Remove Blank Pages -//Compare/Diff -//Add Page Numbers -//Auto Rename -//Get info -//Show JS -*/ -export default router; \ No newline at end of file diff --git a/shared-operations/src/functions/impose.ts b/shared-operations/src/functions/impose.ts index f34545274..605d96c31 100644 --- a/shared-operations/src/functions/impose.ts +++ b/shared-operations/src/functions/impose.ts @@ -58,7 +58,7 @@ export class Impose extends Operator { // TODO: This should be ported to SaudF's RecordValidator if(this.actionValues.nup) { - if(![2, 3, 4, 8, 9, 12, 16].includes(this.actionValues.nup)) { + if(![2, 3, 4, 8, 9, 12, 16].includes(parseInt(this.actionValues.nup))) { return { valid: false, reason: "NUp accepted values are 2, 3, 4, 8, 9, 12, 16 - see: https://pdfcpu.io/generate/nup.html#n-up-value"} } } diff --git a/shared-operations/src/workflow/traverseOperations.ts b/shared-operations/src/workflow/traverseOperations.ts index 366791f6c..fc4faed46 100644 --- a/shared-operations/src/workflow/traverseOperations.ts +++ b/shared-operations/src/workflow/traverseOperations.ts @@ -52,8 +52,8 @@ export async function traverseOperations(operations: Action[], input: PdfFile[], default: const operator = getOperatorByName(action.type); if(operator) { - let opteration = new operator(action); - input = await opteration.run(input, progressCallback); + let operation = new operator(action); + input = await operation.run(input, progressCallback); await nextOperation(action.actions, input, progressCallback); } else