mirror of
https://github.com/sasjs/server.git
synced 2026-01-05 22:00:05 +00:00
fix: code/execute controller logic to handle different runtimes
This commit is contained in:
@@ -12,10 +12,15 @@ import {
|
||||
|
||||
interface ExecuteSASCodePayload {
|
||||
/**
|
||||
* Code of SAS program
|
||||
* @example "* SAS Code HERE;"
|
||||
* Code of program
|
||||
* @example "* Code HERE;"
|
||||
*/
|
||||
code: string
|
||||
/**
|
||||
* runtime for program
|
||||
* @example "js"
|
||||
*/
|
||||
runTime: RunTimeType
|
||||
}
|
||||
|
||||
@Security('bearerAuth')
|
||||
@@ -37,7 +42,7 @@ export class CodeController {
|
||||
|
||||
const executeSASCode = async (
|
||||
req: express.Request,
|
||||
{ code }: ExecuteSASCodePayload
|
||||
{ code, runTime }: ExecuteSASCodePayload
|
||||
) => {
|
||||
const { user } = req
|
||||
const userAutoExec =
|
||||
@@ -53,7 +58,7 @@ const executeSASCode = async (
|
||||
vars: { ...req.query, _debug: 131 },
|
||||
otherArgs: { userAutoExec },
|
||||
returnJson: true,
|
||||
runTime: RunTimeType.SAS
|
||||
runTime: runTime
|
||||
})) as ExecuteReturnJson
|
||||
|
||||
return {
|
||||
|
||||
@@ -5,6 +5,7 @@ export interface InfoResponse {
|
||||
cors: string
|
||||
whiteList: string[]
|
||||
protocol: string
|
||||
runTimes: string[]
|
||||
}
|
||||
|
||||
@Route('SASjsApi/info')
|
||||
@@ -18,7 +19,8 @@ export class InfoController {
|
||||
mode: 'desktop',
|
||||
cors: 'enable',
|
||||
whiteList: ['http://example.com', 'http://example2.com'],
|
||||
protocol: 'http'
|
||||
protocol: 'http',
|
||||
runTimes: ['sas', 'js']
|
||||
})
|
||||
@Get('/')
|
||||
public info(): InfoResponse {
|
||||
@@ -29,7 +31,8 @@ export class InfoController {
|
||||
(process.env.MODE === 'server' ? 'disable' : 'enable'),
|
||||
whiteList:
|
||||
process.env.WHITELIST?.split(' ')?.filter((url) => !!url) ?? [],
|
||||
protocol: process.env.PROTOCOL ?? 'http'
|
||||
protocol: process.env.PROTOCOL ?? 'http',
|
||||
runTimes: process.runTimes
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -274,6 +274,7 @@ const createJSProgram = async (
|
||||
)
|
||||
|
||||
const preProgramVarStatments = `
|
||||
let _webout = '';
|
||||
const weboutPath = '${weboutPath}';
|
||||
const _sasjs_tokenfile = '${tokenFile}';
|
||||
const _sasjs_username = '${preProgramVariables?.username}';
|
||||
@@ -296,10 +297,12 @@ ${preProgramVarStatments}
|
||||
/* actual job code */
|
||||
${program}
|
||||
|
||||
/* write webout file*/
|
||||
fs.writeFile(weboutPath, _webout, function (err) {
|
||||
if (err) throw err;
|
||||
})
|
||||
/* write webout file only if webout exists*/
|
||||
if (_webout) {
|
||||
fs.writeFile(weboutPath, _webout, function (err) {
|
||||
if (err) throw err;
|
||||
})
|
||||
}
|
||||
`
|
||||
// if no files are uploaded filesNamesMap will be undefined
|
||||
if (otherArgs?.filesNamesMap) {
|
||||
|
||||
@@ -51,26 +51,15 @@ export interface ExecuteReturnJsonResponse {
|
||||
@Tags('STP')
|
||||
export class STPController {
|
||||
/**
|
||||
* Trigger a SAS program using it's location in the _program URL parameter.
|
||||
* Enable debugging using the _debug URL parameter. Setting _debug=131 will
|
||||
* cause the log to be streamed in the output.
|
||||
* Trigger a SAS or JS program using the _program URL parameter.
|
||||
*
|
||||
* Additional URL parameters are turned into SAS macro variables.
|
||||
* Accepts URL parameters and file uploads. For more details, see docs:
|
||||
*
|
||||
* Any files provided in the request body are placed into the SAS session with
|
||||
* corresponding _WEBIN_XXX variables created.
|
||||
* https://server.sasjs.io/storedprograms
|
||||
*
|
||||
* The response headers can be adjusted using the mfs_httpheader() macro. Any
|
||||
* file type can be returned, including binary files such as zip or xls.
|
||||
*
|
||||
* If _debug is >= 131, response headers will contain Content-Type: 'text/plain'
|
||||
*
|
||||
* This behaviour differs for POST requests, in which case the response is
|
||||
* always JSON.
|
||||
*
|
||||
* @summary Execute Stored Program, return raw _webout content.
|
||||
* @param _program Location of SAS program
|
||||
* @example _program "/Public/somefolder/some.file"
|
||||
* @summary Execute a Stored Program, returns raw _webout content.
|
||||
* @param _program Location of SAS or JS code
|
||||
* @example _program "/Projects/myApp/some/program"
|
||||
*/
|
||||
@Get('/execute')
|
||||
public async executeReturnRaw(
|
||||
@@ -81,29 +70,22 @@ export class STPController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a SAS program using it's location in the _program URL parameter.
|
||||
* Enable debugging using the _debug URL parameter. In any case, the log is
|
||||
* always returned in the log object.
|
||||
* Trigger a SAS or JS program using the _program URL parameter.
|
||||
*
|
||||
* Additional URL parameters are turned into SAS macro variables.
|
||||
* Accepts URL parameters and file uploads. For more details, see docs:
|
||||
*
|
||||
* Any files provided in the request body are placed into the SAS session with
|
||||
* corresponding _WEBIN_XXX variables created.
|
||||
* https://server.sasjs.io/storedprograms
|
||||
*
|
||||
* The response will be a JSON object with the following root attributes: log,
|
||||
* webout, headers.
|
||||
* The response will be a JSON object with the following root attributes:
|
||||
* log, webout, headers.
|
||||
*
|
||||
* The webout will be a nested JSON object ONLY if the response-header
|
||||
* The webout attribute will be nested JSON ONLY if the response-header
|
||||
* contains a content-type of application/json AND it is valid JSON.
|
||||
* Otherwise it will be a stringified version of the webout content.
|
||||
*
|
||||
* Response headers from the mfs_httpheader macro are simply listed in the
|
||||
* headers object, for POST requests they have no effect on the actual
|
||||
* response header.
|
||||
*
|
||||
* @summary Execute Stored Program, return JSON
|
||||
* @param _program Location of SAS program
|
||||
* @example _program "/Public/somefolder/some.file"
|
||||
* @summary Execute a Stored Program, return a JSON object
|
||||
* @param _program Location of SAS or JS code
|
||||
* @example _program "/Projects/myApp/some/program"
|
||||
*/
|
||||
@Example<ExecuteReturnJsonResponse>({
|
||||
status: 'success',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import express from 'express'
|
||||
import { runSASValidation } from '../../utils'
|
||||
import { runCodeValidation } from '../../utils'
|
||||
import { CodeController } from '../../controllers/'
|
||||
|
||||
const runRouter = express.Router()
|
||||
@@ -7,7 +7,7 @@ const runRouter = express.Router()
|
||||
const controller = new CodeController()
|
||||
|
||||
runRouter.post('/execute', async (req, res) => {
|
||||
const { error, value: body } = runSASValidation(req.body)
|
||||
const { error, value: body } = runCodeValidation(req.body)
|
||||
if (error) return res.status(400).send(error.details[0].message)
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Joi from 'joi'
|
||||
import { RunTimeType } from '.'
|
||||
|
||||
const usernameSchema = Joi.string().lowercase().alphanum().min(3).max(16)
|
||||
const passwordSchema = Joi.string().min(6).max(1024)
|
||||
@@ -114,9 +115,10 @@ export const folderParamValidation = (data: any): Joi.ValidationResult =>
|
||||
_folderPath: Joi.string()
|
||||
}).validate(data)
|
||||
|
||||
export const runSASValidation = (data: any): Joi.ValidationResult =>
|
||||
export const runCodeValidation = (data: any): Joi.ValidationResult =>
|
||||
Joi.object({
|
||||
code: Joi.string().required()
|
||||
code: Joi.string().required(),
|
||||
runTime: Joi.string().valid(...Object.values(RunTimeType))
|
||||
}).validate(data)
|
||||
|
||||
export const executeProgramRawValidation = (data: any): Joi.ValidationResult =>
|
||||
|
||||
Reference in New Issue
Block a user