diff --git a/.gitignore b/.gitignore index 7c3856c..13323df 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ node_modules/ sas/ tmp/ build/ -certificates/ \ No newline at end of file +certificates/ diff --git a/code.lst b/code.lst new file mode 100644 index 0000000..afd66d7 --- /dev/null +++ b/code.lst @@ -0,0 +1,10 @@ + The SAS System Friday, 15 October 2021 11:20:00 1 + + + -------- + 0 + The SAS System Friday, 15 October 2021 11:20:00 2 + + + -------- + 41140 diff --git a/package-lock.json b/package-lock.json index 6c31521..7f6be90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1518,12 +1518,6 @@ "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "dev": true }, - "@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, "@types/express": { "version": "4.17.12", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", @@ -1693,6 +1687,15 @@ "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", "dev": true }, + "@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/node": { "version": "15.12.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", @@ -2690,15 +2693,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, "cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", diff --git a/package.json b/package.json index be13750..b55e24d 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "devDependencies": { "@types/express": "^4.17.12", "@types/jest": "^26.0.24", + "@types/multer": "^1.4.7", "@types/node": "^15.12.2", "@types/supertest": "^2.0.11", "jest": "^27.0.6", diff --git a/src/controllers/Execution.ts b/src/controllers/Execution.ts index af379c1..5eb4383 100644 --- a/src/controllers/Execution.ts +++ b/src/controllers/Execution.ts @@ -60,7 +60,7 @@ ${program}` } } - let code = path.join(session.path, 'code.sas') + const code = path.join(session.path, 'code.sas') if (!(await fileExists(code))) { await createFile(code, program) } @@ -82,10 +82,6 @@ ${program}` if (await fileExists(log)) log = await readFile(log) else log = '' - // if (stderr) { - // return Promise.reject({ error: stderr, log: log }) - // } - if (await fileExists(webout)) webout = await readFile(webout) else webout = '' diff --git a/src/controllers/FileUploadController.ts b/src/controllers/FileUploadController.ts new file mode 100644 index 0000000..0bd015c --- /dev/null +++ b/src/controllers/FileUploadController.ts @@ -0,0 +1,36 @@ +import { uuidv4 } from '@sasjs/utils' +import { getSessionController } from '.' +const multer = require('multer') + +export class FileUploadController { + private storage = multer.diskStorage({ + destination: function (req: any, file: any, cb: any) { + //Sending the intercepted files to the sessions subfolder + cb(null, req.sasSession.path) + }, + filename: function (req: any, file: any, cb: any) { + //req_file prefix + unique hash added to sas request files + cb(null, `req_file_${uuidv4().replace(/-/gm, '')}`) + } + }) + + private upload = multer({ storage: this.storage }) + + //It will intercept request and generate uniqe uuid to be used as a subfolder name + //that will store the files uploaded + public preuploadMiddleware = async (req: any, res: any, next: any) => { + let session + + const sessionController = getSessionController() + session = await sessionController.getSession() + session.inUse = true + + req.sasSession = session + + next() + } + + public getMulterUploadObject() { + return this.upload + } +} \ No newline at end of file diff --git a/src/controllers/Session.ts b/src/controllers/Session.ts index 57a4850..3e9af19 100644 --- a/src/controllers/Session.ts +++ b/src/controllers/Session.ts @@ -70,7 +70,7 @@ export class SessionController { this.scheduleSessionDestroy(session) - this.executionController.execute('', autoExec, session).catch((err) => {}) + this.executionController.execute('', autoExec, session).catch(() => {}) this.sessions.push(session) diff --git a/src/controllers/index.ts b/src/controllers/index.ts index 2990104..60c5d59 100644 --- a/src/controllers/index.ts +++ b/src/controllers/index.ts @@ -1,3 +1,4 @@ export * from './deploy' export * from './Session' export * from './Execution' +export * from './FileUploadController' \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts index 60f280f..0f921bf 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -2,39 +2,12 @@ import express from 'express' import { createFileTree, getSessionController, getTreeExample } from '../controllers' import { ExecutionResult, isRequestQuery, isFileTree } from '../types' import path from 'path' -import { getTmpFilesFolderPath, getTmpFolderPath, makeFilesNamesMap } from '../utils' -import { ExecutionController } from '../controllers' -import { uuidv4 } from '@sasjs/utils' +import { addExtensionIfNotFound, getTmpFilesFolderPath, getTmpFolderPath, makeFilesNamesMap } from '../utils' +import { ExecutionController, FileUploadController } from '../controllers' -const multer = require('multer') const router = express.Router() -const storage = multer.diskStorage({ - destination: function (req: any, file: any, cb: any) { - //Sending the intercepted files to the sessions subfolder - cb(null, req.sasSession.path) - }, - filename: function (req: any, file: any, cb: any) { - //req_file prefix + unique hash added to sas request files - cb(null, `req_file_${uuidv4().replace(/-/gm, '')}`) - } -}) - -const upload = multer({ storage: storage }) - -//It will intercept request and generate uniqe uuid to be used as a subfolder name -//that will store the files uploaded -const preuploadMiddleware = async (req: any, res: any, next: any) => { - let session - - const sessionController = getSessionController() - session = await sessionController.getSession() - session.inUse = true - - req.sasSession = session - - next() -} +const fileUploadController = new FileUploadController() router.get('/', async (_, res) => { res.status(200).send('Welcome to @sasjs/server API') @@ -102,14 +75,14 @@ router.get('/SASjsExecutor/do', async (req, res) => { } }) -router.post('/SASjsExecutor/do', preuploadMiddleware, upload.any(), async (req: any, res: any) => { +router.post('/SASjsExecutor/do', fileUploadController.preuploadMiddleware, fileUploadController.getMulterUploadObject().any(), async (req: any, res: any) => { if (isRequestQuery(req.query)) { let sasCodePath = path .join(getTmpFilesFolderPath(), req.query._program) .replace(new RegExp('/', 'g'), path.sep) // If no extension provided, add .sas extension - sasCodePath += !sasCodePath.includes('.') ? '.sas' : '' + sasCodePath += addExtensionIfNotFound(sasCodePath, 'sas') let filesNamesMap = null diff --git a/src/types/Upload.ts b/src/types/Upload.ts new file mode 100644 index 0000000..d025a4e --- /dev/null +++ b/src/types/Upload.ts @@ -0,0 +1,10 @@ +export interface MulterFile { + fieldname: string + originalname: string + encoding: string + mimetype: string + destination: string + filename: string + path: string + size: number +} \ No newline at end of file diff --git a/src/utils/file.ts b/src/utils/file.ts index fe09816..3dfe57f 100644 --- a/src/utils/file.ts +++ b/src/utils/file.ts @@ -24,3 +24,7 @@ export const generateUniqueFileName = (fileName: string, extension = '') => new Date().getTime(), extension ].join('') + +export const addExtensionIfNotFound = (value: string, extension: string) => { + return !value.includes('.') ? `.${extension}` : '' +} \ No newline at end of file diff --git a/src/utils/upload.ts b/src/utils/upload.ts index ce9e8a0..b033494 100644 --- a/src/utils/upload.ts +++ b/src/utils/upload.ts @@ -1,16 +1,18 @@ import path from 'path' import fs from 'fs' import { getTmpSessionsFolderPath } from '.' +import { MulterFile } from '../types/Upload' +import { listFilesInFolder } from '@sasjs/utils' /** - * It will create a object that maps hashed file names to the original names + * It will create an object that maps hashed file names to the original names * @param files array of files to be mapped * @returns object */ -export const makeFilesNamesMap = (files: any) => { +export const makeFilesNamesMap = (files: MulterFile[]) => { if (!files) return null - const filesNamesMap: any = {} + const filesNamesMap: {[key: string]: string} = {} for (let file of files) { filesNamesMap[file.filename] = file.fieldname @@ -20,7 +22,7 @@ export const makeFilesNamesMap = (files: any) => { } /** - * Generates the sas code that reference uploaded files in the concurrent request + * Generates the sas code that references uploaded files in the concurrent request * @param filesNamesMap object that maps hashed file names and original file names * @param sasUploadFolder name of the folder that is created for the purpose of files in concurrent request * @returns generated sas code @@ -29,8 +31,6 @@ export const makeFilesNamesMap = (files: any) => { filesNamesMap: any, sasSessionFolder: string ): string => { - const uploadFilesDirPath = sasSessionFolder - let uploadSasCode = '' let fileCount = 0 let uploadedFilesMap: { @@ -40,7 +40,8 @@ export const makeFilesNamesMap = (files: any) => { count: number }[] = [] - fs.readdirSync(uploadFilesDirPath).forEach((fileName) => { + + fs.readdirSync(sasSessionFolder).forEach((fileName) => { let fileCountString = fileCount < 100 ? '0' + fileCount : fileCount fileCountString = fileCount < 10 ? '00' + fileCount : fileCount @@ -49,7 +50,7 @@ export const makeFilesNamesMap = (files: any) => { uploadedFilesMap.push({ fileref: `_sjs${fileCountString}`, - filepath: `${uploadFilesDirPath}/${fileName}`, + filepath: `${sasSessionFolder}/${fileName}`, filename: filesNamesMap[fileName], count: fileCount })