mirror of
https://github.com/sasjs/server.git
synced 2026-01-09 23:40:06 +00:00
Merge pull request #77 from sasjs/issue-65
fix: macros are available Sessions with SASAUTOS
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ sas/
|
|||||||
tmp/
|
tmp/
|
||||||
build/
|
build/
|
||||||
sasjsbuild/
|
sasjsbuild/
|
||||||
|
sasjscore/
|
||||||
certificates/
|
certificates/
|
||||||
executables/
|
executables/
|
||||||
.env
|
.env
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "Api of SASjs server",
|
"description": "Api of SASjs server",
|
||||||
"main": "./src/server.ts",
|
"main": "./src/server.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"initial": "npm run swagger && npm run compileSysInit",
|
"initial": "npm run swagger && npm run compileSysInit && npm run copySASjsCore",
|
||||||
"prestart": "npm run initial",
|
"prestart": "npm run initial",
|
||||||
"prebuild": "npm run initial",
|
"prebuild": "npm run initial",
|
||||||
"start": "nodemon ./src/server.ts",
|
"start": "nodemon ./src/server.ts",
|
||||||
@@ -16,11 +16,13 @@
|
|||||||
"lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
|
"lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
|
||||||
"package:lib": "npm run build && cp ./package.json build && cp README.md build && cd build && npm version \"5.0.0\" && npm pack",
|
"package:lib": "npm run build && cp ./package.json build && cp README.md build && cd build && npm version \"5.0.0\" && npm pack",
|
||||||
"exe": "npm run build && npm run exe:copy && pkg .",
|
"exe": "npm run build && npm run exe:copy && pkg .",
|
||||||
"exe:copy": "npm run public:copy && npm run sasjsbuild:copy && npm run web:copy",
|
"exe:copy": "npm run public:copy && npm run sasjsbuild:copy && npm run sasjscore:copy && npm run web:copy",
|
||||||
"public:copy": "cp -r ./public/ ./build/public/",
|
"public:copy": "cp -r ./public/ ./build/public/",
|
||||||
"sasjsbuild:copy": "cp -r ./sasjsbuild/ ./build/sasjsbuild/",
|
"sasjsbuild:copy": "cp -r ./sasjsbuild/ ./build/sasjsbuild/",
|
||||||
|
"sasjscore:copy": "cp -r ./sasjscore/ ./build/sasjscore/",
|
||||||
"web:copy": "rimraf web && mkdir web && cp -r ../web/build/ ./web/build/",
|
"web:copy": "rimraf web && mkdir web && cp -r ../web/build/ ./web/build/",
|
||||||
"compileSysInit": "ts-node ./scripts/compileSysInit.ts"
|
"compileSysInit": "ts-node ./scripts/compileSysInit.ts",
|
||||||
|
"copySASjsCore": "ts-node ./scripts/copySASjsCore.ts"
|
||||||
},
|
},
|
||||||
"bin": "./build/src/server.js",
|
"bin": "./build/src/server.js",
|
||||||
"pkg": {
|
"pkg": {
|
||||||
|
|||||||
@@ -223,18 +223,6 @@ components:
|
|||||||
- fileTree
|
- fileTree
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
GetFileResponse:
|
|
||||||
properties:
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
fileContent:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- status
|
|
||||||
type: object
|
|
||||||
additionalProperties: false
|
|
||||||
UpdateFileResponse:
|
UpdateFileResponse:
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
@@ -610,24 +598,8 @@ paths:
|
|||||||
get:
|
get:
|
||||||
operationId: GetFile
|
operationId: GetFile
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'204':
|
||||||
description: Ok
|
description: 'No content'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/GetFileResponse'
|
|
||||||
examples:
|
|
||||||
'Example 1':
|
|
||||||
value: {status: success, fileContent: 'Contents of the File'}
|
|
||||||
'400':
|
|
||||||
description: 'Unable to get File'
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/GetFileResponse'
|
|
||||||
examples:
|
|
||||||
'Example 1':
|
|
||||||
value: {status: failure, message: 'File request failed.'}
|
|
||||||
summary: 'Get file from SASjs Drive'
|
summary: 'Get file from SASjs Drive'
|
||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ const compiledSystemInit = async (systemInit: string) =>
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const createSysInitFile = async () => {
|
const createSysInitFile = async () => {
|
||||||
console.log('macroCorePath', macroCorePath)
|
|
||||||
const systemInitContent = await readFile(
|
const systemInitContent = await readFile(
|
||||||
path.join(__dirname, 'systemInit.sas')
|
path.join(__dirname, 'systemInit.sas')
|
||||||
)
|
)
|
||||||
|
|||||||
25
api/scripts/copySASjsCore.ts
Normal file
25
api/scripts/copySASjsCore.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import { asyncForEach, copy, createFolder, deleteFolder } from '@sasjs/utils'
|
||||||
|
|
||||||
|
import { apiRoot, sasJSCoreMacros } from '../src/utils'
|
||||||
|
|
||||||
|
const macroCorePath = path.join(apiRoot, 'node_modules', '@sasjs', 'core')
|
||||||
|
|
||||||
|
export const copySASjsCore = async () => {
|
||||||
|
await deleteFolder(sasJSCoreMacros)
|
||||||
|
await createFolder(sasJSCoreMacros)
|
||||||
|
|
||||||
|
console.log('Copying SASjs Core Macros...')
|
||||||
|
|
||||||
|
const foldersToCopy = ['base', 'ddl', 'fcmp', 'lua', 'server']
|
||||||
|
|
||||||
|
await asyncForEach(foldersToCopy, async (coreSubFolder) => {
|
||||||
|
const coreSubFolderPath = path.join(macroCorePath, coreSubFolder)
|
||||||
|
|
||||||
|
await copy(coreSubFolderPath, sasJSCoreMacros)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('Macros available at: ', sasJSCoreMacros)
|
||||||
|
}
|
||||||
|
|
||||||
|
copySASjsCore()
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { Express } from 'express'
|
import express, { Express } from 'express'
|
||||||
import {
|
import {
|
||||||
Security,
|
Security,
|
||||||
|
Request,
|
||||||
Route,
|
Route,
|
||||||
Tags,
|
Tags,
|
||||||
Example,
|
Example,
|
||||||
@@ -14,14 +15,7 @@ import {
|
|||||||
UploadedFile,
|
UploadedFile,
|
||||||
FormField
|
FormField
|
||||||
} from 'tsoa'
|
} from 'tsoa'
|
||||||
import {
|
import { fileExists, createFile, moveFile, createFolder } from '@sasjs/utils'
|
||||||
fileExists,
|
|
||||||
readFile,
|
|
||||||
createFile,
|
|
||||||
moveFile,
|
|
||||||
createFolder,
|
|
||||||
deleteFile
|
|
||||||
} from '@sasjs/utils'
|
|
||||||
import { createFileTree, ExecutionController, getTreeExample } from './internal'
|
import { createFileTree, ExecutionController, getTreeExample } from './internal'
|
||||||
|
|
||||||
import { FileTree, isFileTree, TreeNode } from '../types'
|
import { FileTree, isFileTree, TreeNode } from '../types'
|
||||||
@@ -103,17 +97,12 @@ export class DriveController {
|
|||||||
* @query filePath Location of SAS program
|
* @query filePath Location of SAS program
|
||||||
* @example filePath "/Public/somefolder/some.file"
|
* @example filePath "/Public/somefolder/some.file"
|
||||||
*/
|
*/
|
||||||
@Example<GetFileResponse>({
|
|
||||||
status: 'success',
|
|
||||||
fileContent: 'Contents of the File'
|
|
||||||
})
|
|
||||||
@Response<GetFileResponse>(400, 'Unable to get File', {
|
|
||||||
status: 'failure',
|
|
||||||
message: 'File request failed.'
|
|
||||||
})
|
|
||||||
@Get('/file')
|
@Get('/file')
|
||||||
public async getFile(@Query() filePath: string): Promise<GetFileResponse> {
|
public async getFile(
|
||||||
return getFile(filePath)
|
@Request() request: express.Request,
|
||||||
|
@Query() filePath: string
|
||||||
|
) {
|
||||||
|
return getFile(request, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,24 +179,22 @@ const deploy = async (data: DeployPayload) => {
|
|||||||
return successDeployResponse
|
return successDeployResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
const getFile = async (filePath: string): Promise<GetFileResponse> => {
|
const getFile = async (req: express.Request, filePath: string) => {
|
||||||
try {
|
const driveFilesPath = getTmpFilesFolderPath()
|
||||||
const filePathFull = path
|
|
||||||
.join(getTmpFilesFolderPath(), filePath)
|
|
||||||
.replace(new RegExp('/', 'g'), path.sep)
|
|
||||||
|
|
||||||
await validateFilePath(filePathFull)
|
const filePathFull = path
|
||||||
const fileContent = await readFile(filePathFull)
|
.join(getTmpFilesFolderPath(), filePath)
|
||||||
|
.replace(new RegExp('/', 'g'), path.sep)
|
||||||
|
|
||||||
return { status: 'success', fileContent: fileContent }
|
if (!filePathFull.includes(driveFilesPath)) {
|
||||||
} catch (err: any) {
|
throw new Error('Cannot get file outside drive.')
|
||||||
throw {
|
|
||||||
code: 400,
|
|
||||||
status: 'failure',
|
|
||||||
message: 'File request failed.',
|
|
||||||
error: typeof err === 'object' ? err.toString() : err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(await fileExists(filePathFull))) {
|
||||||
|
throw new Error('File does not exist.')
|
||||||
|
}
|
||||||
|
|
||||||
|
req.res?.download(filePathFull)
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveFile = async (
|
const saveFile = async (
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import {
|
|||||||
extractHeaders,
|
extractHeaders,
|
||||||
generateFileUploadSasCode,
|
generateFileUploadSasCode,
|
||||||
getTmpFilesFolderPath,
|
getTmpFilesFolderPath,
|
||||||
HTTPHeaders
|
HTTPHeaders,
|
||||||
|
sasJSCoreMacros
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
|
|
||||||
export interface ExecutionVars {
|
export interface ExecutionVars {
|
||||||
@@ -104,6 +105,8 @@ export class ExecutionController {
|
|||||||
`
|
`
|
||||||
|
|
||||||
program = `
|
program = `
|
||||||
|
options insert=(SASAUTOS="${sasJSCoreMacros}");
|
||||||
|
|
||||||
/* runtime vars */
|
/* runtime vars */
|
||||||
${varStatments}
|
${varStatments}
|
||||||
filename _webout "${weboutPath}" mod;
|
filename _webout "${weboutPath}" mod;
|
||||||
|
|||||||
@@ -67,7 +67,10 @@ export class SessionController {
|
|||||||
|
|
||||||
// the autoexec file is executed on SAS startup
|
// the autoexec file is executed on SAS startup
|
||||||
const autoExecPath = path.join(sessionFolder, 'autoexec.sas')
|
const autoExecPath = path.join(sessionFolder, 'autoexec.sas')
|
||||||
const contentForAutoExec = `/* compiled systemInit */\n${compiledSystemInitContent}\n/* autoexec */\n${autoExecContent}`
|
const contentForAutoExec = `/* compiled systemInit */
|
||||||
|
${compiledSystemInitContent}
|
||||||
|
/* autoexec */
|
||||||
|
${autoExecContent}`
|
||||||
await createFile(autoExecPath, contentForAutoExec)
|
await createFile(autoExecPath, contentForAutoExec)
|
||||||
|
|
||||||
// create empty code.sas as SAS will not start without a SYSIN
|
// create empty code.sas as SAS will not start without a SYSIN
|
||||||
|
|||||||
@@ -32,14 +32,9 @@ driveRouter.get('/file', async (req, res) => {
|
|||||||
if (error) return res.status(400).send(error.details[0].message)
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await controller.getFile(query.filePath)
|
await controller.getFile(req, query.filePath)
|
||||||
res.send(response)
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const statusCode = err.code
|
res.status(403).send(err.toString())
|
||||||
|
|
||||||
delete err.code
|
|
||||||
|
|
||||||
res.status(statusCode).send(err)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export const sysInitCompiledPath = path.join(
|
|||||||
'systemInitCompiled.sas'
|
'systemInitCompiled.sas'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const sasJSCoreMacros = path.join(apiRoot, 'sasjscore')
|
||||||
|
|
||||||
export const getWebBuildFolderPath = () =>
|
export const getWebBuildFolderPath = () =>
|
||||||
path.join(codebaseRoot, 'web', 'build')
|
path.join(codebaseRoot, 'web', 'build')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user