1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-06 12:10:04 +00:00

Compare commits

..

11 Commits

12 changed files with 152 additions and 105 deletions

View File

@@ -66,6 +66,7 @@ export class FileUploader {
return this.requestClient return this.requestClient
.post(uploadUrl, formData, undefined, 'application/json', headers) .post(uploadUrl, formData, undefined, 'application/json', headers)
.then(async (res) => { .then(async (res) => {
this.requestClient!.appendRequest(res, sasJob, this.sasjsConfig.debug)
if ( if (
this.sasjsConfig.serverType === ServerType.SasViya && this.sasjsConfig.serverType === ServerType.SasViya &&
this.sasjsConfig.debug this.sasjsConfig.debug

View File

@@ -51,6 +51,16 @@ export class SASViyaApiClient {
) )
private folderMap = new Map<string, Job[]>() private folderMap = new Map<string, Job[]>()
/**
* A helper method used to call appendRequest method of RequestClient
* @param response - response from sasjs request
* @param program - name of program
* @param debug - a boolean that indicates whether debug was enabled or not
*/
public appendRequest(response: any, program: string, debug: boolean) {
this.requestClient!.appendRequest(response, program, debug)
}
public get debug() { public get debug() {
return this._debug return this._debug
} }

View File

@@ -905,20 +905,18 @@ export default class SASjs {
}) })
} }
/**
* this method returns an array of SASjsRequest
* @returns SASjsRequest[]
*/
public getSasRequests() { public getSasRequests() {
const requests = [ const requests = [...this.requestClient!.getRequests()]
...this.webJobExecutor!.getRequests(),
...this.computeJobExecutor!.getRequests(),
...this.jesJobExecutor!.getRequests()
]
const sortedRequests = requests.sort(compareTimestamps) const sortedRequests = requests.sort(compareTimestamps)
return sortedRequests return sortedRequests
} }
public clearSasRequests() { public clearSasRequests() {
this.webJobExecutor!.clearRequests() this.requestClient!.clearRequests()
this.computeJobExecutor!.clearRequests()
this.jesJobExecutor!.clearRequests()
} }
private setupConfiguration() { private setupConfiguration() {
@@ -941,10 +939,17 @@ export default class SASjs {
this.sasjsConfig.serverUrl = this.sasjsConfig.serverUrl.slice(0, -1) this.sasjsConfig.serverUrl = this.sasjsConfig.serverUrl.slice(0, -1)
} }
this.requestClient = new RequestClient( if (!this.requestClient) {
this.sasjsConfig.serverUrl, this.requestClient = new RequestClient(
this.sasjsConfig.allowInsecureRequests this.sasjsConfig.serverUrl,
) this.sasjsConfig.allowInsecureRequests
)
} else {
this.requestClient.setConfig(
this.sasjsConfig.serverUrl,
this.sasjsConfig.allowInsecureRequests
)
}
this.jobsPath = this.jobsPath =
this.sasjsConfig.serverType === ServerType.SasViya this.sasjsConfig.serverType === ServerType.SasViya

View File

@@ -35,14 +35,12 @@ export class ComputeJobExecutor extends BaseJobExecutor {
expectWebout expectWebout
) )
.then((response) => { .then((response) => {
this.appendRequest(response, sasJob, config.debug) this.sasViyaApiClient.appendRequest(response, sasJob, config.debug)
resolve(response.result) resolve(response.result)
}) })
.catch(async (e: Error) => { .catch(async (e: Error) => {
if (e instanceof ComputeJobExecutionError) { if (e instanceof ComputeJobExecutionError) {
this.appendRequest(e, sasJob, config.debug) this.sasViyaApiClient.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }

View File

@@ -28,7 +28,7 @@ export class JesJobExecutor extends BaseJobExecutor {
this.sasViyaApiClient this.sasViyaApiClient
?.executeJob(sasJob, config.contextName, config.debug, data, authConfig) ?.executeJob(sasJob, config.contextName, config.debug, data, authConfig)
.then((response: any) => { .then((response: any) => {
this.appendRequest(response, sasJob, config.debug) this.sasViyaApiClient.appendRequest(response, sasJob, config.debug)
const responseObject = appendExtraResponseAttributes( const responseObject = appendExtraResponseAttributes(
response, response,
@@ -39,7 +39,7 @@ export class JesJobExecutor extends BaseJobExecutor {
}) })
.catch(async (e: Error) => { .catch(async (e: Error) => {
if (e instanceof JobExecutionError) { if (e instanceof JobExecutionError) {
this.appendRequest(e, sasJob, config.debug) this.sasViyaApiClient.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }

View File

@@ -15,8 +15,6 @@ export interface JobExecutor {
extraResponseAttributes?: ExtraResponseAttributes[] extraResponseAttributes?: ExtraResponseAttributes[]
) => Promise<any> ) => Promise<any>
resendWaitingRequests: () => Promise<void> resendWaitingRequests: () => Promise<void>
getRequests: () => SASjsRequest[]
clearRequests: () => void
} }
export abstract class BaseJobExecutor implements JobExecutor { export abstract class BaseJobExecutor implements JobExecutor {
@@ -46,54 +44,7 @@ export abstract class BaseJobExecutor implements JobExecutor {
return return
} }
getRequests = () => this.requests
clearRequests = () => {
this.requests = []
}
protected appendWaitingRequest(request: ExecuteFunction) { protected appendWaitingRequest(request: ExecuteFunction) {
this.waitingRequests.push(request) this.waitingRequests.push(request)
} }
protected appendRequest(response: any, program: string, debug: boolean) {
let sourceCode = ''
let generatedCode = ''
let sasWork = null
if (debug) {
if (response?.log) {
sourceCode = parseSourceCode(response.log)
generatedCode = parseGeneratedCode(response.log)
if (response?.result) {
sasWork = response.result.WORK
} else {
sasWork = response.log
}
} else if (response?.result) {
sourceCode = parseSourceCode(response.result)
generatedCode = parseGeneratedCode(response.result)
sasWork = response.result.WORK
}
}
const stringifiedResult =
typeof response?.result === 'string'
? response?.result
: JSON.stringify(response?.result, null, 2)
this.requests.push({
logFile: response?.log || stringifiedResult || response,
serviceLink: program,
timestamp: new Date(),
sourceCode,
generatedCode,
SASWORK: sasWork
})
if (this.requests.length > 20) {
this.requests.splice(0, 1)
}
}
} }

View File

@@ -115,6 +115,8 @@ export class WebJobExecutor extends BaseJobExecutor {
const requestPromise = new Promise((resolve, reject) => { const requestPromise = new Promise((resolve, reject) => {
this.requestClient!.post(apiUrl, formData, undefined) this.requestClient!.post(apiUrl, formData, undefined)
.then(async (res: any) => { .then(async (res: any) => {
this.requestClient!.appendRequest(res, sasJob, config.debug)
let jsonResponse = res.result let jsonResponse = res.result
if (config.debug) { if (config.debug) {
@@ -135,8 +137,6 @@ export class WebJobExecutor extends BaseJobExecutor {
} }
} }
this.appendRequest(res, sasJob, config.debug)
const responseObject = appendExtraResponseAttributes( const responseObject = appendExtraResponseAttributes(
{ result: jsonResponse }, { result: jsonResponse },
extraResponseAttributes extraResponseAttributes
@@ -145,8 +145,7 @@ export class WebJobExecutor extends BaseJobExecutor {
}) })
.catch(async (e: Error) => { .catch(async (e: Error) => {
if (e instanceof JobExecutionError) { if (e instanceof JobExecutionError) {
this.appendRequest(e, sasJob, config.debug) this.requestClient!.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }

View File

@@ -8,10 +8,11 @@ import {
InternalServerError, InternalServerError,
JobExecutionError JobExecutionError
} from '../types/errors' } from '../types/errors'
import { SASjsRequest } from '../types'
import { parseWeboutResponse } from '../utils/parseWeboutResponse' import { parseWeboutResponse } from '../utils/parseWeboutResponse'
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import { SAS9AuthError } from '../types/errors/SAS9AuthError' import { SAS9AuthError } from '../types/errors/SAS9AuthError'
import { getValidJson } from '../utils' import { parseGeneratedCode, parseSourceCode } from '../utils'
export interface HttpClient { export interface HttpClient {
get<T>( get<T>(
@@ -47,27 +48,18 @@ export interface HttpClient {
} }
export class RequestClient implements HttpClient { export class RequestClient implements HttpClient {
private requests: SASjsRequest[] = []
protected csrfToken: CsrfToken = { headerName: '', value: '' } protected csrfToken: CsrfToken = { headerName: '', value: '' }
protected fileUploadCsrfToken: CsrfToken | undefined protected fileUploadCsrfToken: CsrfToken | undefined
protected httpClient: AxiosInstance protected httpClient!: AxiosInstance
constructor(protected baseUrl: string, allowInsecure = false) { constructor(protected baseUrl: string, allowInsecure = false) {
const https = require('https') this.createHttpClient(baseUrl, allowInsecure)
if (allowInsecure && https.Agent) { }
this.httpClient = axios.create({
baseURL: baseUrl,
httpsAgent: new https.Agent({
rejectUnauthorized: !allowInsecure
})
})
} else {
this.httpClient = axios.create({
baseURL: baseUrl
})
}
this.httpClient.defaults.validateStatus = (status) => public setConfig(baseUrl: string, allowInsecure = false) {
status >= 200 && status < 305 this.createHttpClient(baseUrl, allowInsecure)
} }
public getCsrfToken(type: 'general' | 'file' = 'general') { public getCsrfToken(type: 'general' | 'file' = 'general') {
@@ -83,6 +75,66 @@ export class RequestClient implements HttpClient {
return this.httpClient.defaults.baseURL || '' return this.httpClient.defaults.baseURL || ''
} }
/**
* this method returns all requests, an array of SASjsRequest type
* @returns SASjsRequest[]
*/
public getRequests = () => this.requests
/**
* this method clears the requests array, i.e set to empty
*/
public clearRequests = () => {
this.requests = []
}
/**
* this method appends the response from sasjs request to requests array
* @param response - response from sasjs request
* @param program - name of program
* @param debug - a boolean that indicates whether debug was enabled or not
*/
public appendRequest(response: any, program: string, debug: boolean) {
let sourceCode = ''
let generatedCode = ''
let sasWork = null
if (debug) {
if (response?.log) {
sourceCode = parseSourceCode(response.log)
generatedCode = parseGeneratedCode(response.log)
if (response?.result) {
sasWork = response.result.WORK
} else {
sasWork = response.log
}
} else if (response?.result) {
sourceCode = parseSourceCode(response.result)
generatedCode = parseGeneratedCode(response.result)
sasWork = response.result.WORK
}
}
const stringifiedResult =
typeof response?.result === 'string'
? response?.result
: JSON.stringify(response?.result, null, 2)
this.requests.push({
logFile: response?.log || stringifiedResult || response,
serviceLink: program,
timestamp: new Date(),
sourceCode,
generatedCode,
SASWORK: sasWork
})
if (this.requests.length > 20) {
this.requests.splice(0, 1)
}
}
public async get<T>( public async get<T>(
url: string, url: string,
accessToken: string | undefined, accessToken: string | undefined,
@@ -454,6 +506,25 @@ export class RequestClient implements HttpClient {
return responseToReturn return responseToReturn
} }
private createHttpClient(baseUrl: string, allowInsecure = false) {
const https = require('https')
if (allowInsecure && https.Agent) {
this.httpClient = axios.create({
baseURL: baseUrl,
httpsAgent: new https.Agent({
rejectUnauthorized: !allowInsecure
})
})
} else {
this.httpClient = axios.create({
baseURL: baseUrl
})
}
this.httpClient.defaults.validateStatus = (status) =>
status >= 200 && status < 305
}
} }
export const throwIfError = (response: AxiosResponse) => { export const throwIfError = (response: AxiosResponse) => {

View File

@@ -34,7 +34,8 @@ const prepareFilesAndParams = () => {
describe('FileUploader', () => { describe('FileUploader', () => {
const config: SASjsConfig = { const config: SASjsConfig = {
...new SASjsConfig(), ...new SASjsConfig(),
appLoc: '/sample/apploc' appLoc: '/sample/apploc',
debug: false
} }
const fileUploader = new FileUploader( const fileUploader = new FileUploader(

View File

@@ -33,4 +33,18 @@ describe('jsonValidator', () => {
} }
expect(test).toThrow(JsonParseArrayError) expect(test).toThrow(JsonParseArrayError)
}) })
it('should throw an error when null is passed', () => {
const test = () => {
getValidJson(null as any)
}
expect(test).toThrow(InvalidJsonError)
})
it('should throw an error when undefined is passed', () => {
const test = () => {
getValidJson(undefined as any)
}
expect(test).toThrow(InvalidJsonError)
})
}) })

View File

@@ -6,6 +6,8 @@ import { JsonParseArrayError, InvalidJsonError } from '../types/errors'
*/ */
export const getValidJson = (str: string | object) => { export const getValidJson = (str: string | object) => {
try { try {
if (str === null || str === undefined) throw new InvalidJsonError()
if (Array.isArray(str)) throw new JsonParseArrayError() if (Array.isArray(str)) throw new JsonParseArrayError()
if (typeof str === 'object') return str if (typeof str === 'object') return str

View File

@@ -3,7 +3,6 @@ enum domIDs {
overlay = 'sasjsAdapterLoginPromptBG', overlay = 'sasjsAdapterLoginPromptBG',
dialog = 'sasjsAdapterLoginPrompt' dialog = 'sasjsAdapterLoginPrompt'
} }
const cssPrefix = 'sasjs-adapter'
export const openLoginPrompt = (): Promise<boolean> => { export const openLoginPrompt = (): Promise<boolean> => {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
@@ -13,11 +12,11 @@ export const openLoginPrompt = (): Promise<boolean> => {
const loginPromptBG = document.createElement('div') const loginPromptBG = document.createElement('div')
loginPromptBG.id = domIDs.overlay loginPromptBG.id = domIDs.overlay
loginPromptBG.classList.add(`${cssPrefix}popUpBG`) loginPromptBG.classList.add('popUpBG')
const loginPrompt = document.createElement('div') const loginPrompt = document.createElement('div')
loginPrompt.id = domIDs.dialog loginPrompt.id = domIDs.dialog
loginPrompt.classList.add(`${cssPrefix}popUp`) loginPrompt.classList.add('popUp')
const title = document.createElement('h1') const title = document.createElement('h1')
title.innerText = 'Session Expired!' title.innerText = 'Session Expired!'
@@ -64,11 +63,7 @@ const closeLoginPrompt = () => {
} }
const cssContent = ` const cssContent = `
.${cssPrefix}popUpBG , .popUp {
.${cssPrefix}popUp {
z-index: 10000;
}
.${cssPrefix}popUp {
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -91,7 +86,7 @@ const cssContent = `
max-height: 300px; max-height: 300px;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
.${cssPrefix}popUp > h1 { .popUp > h1 {
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -106,7 +101,7 @@ const cssContent = `
border-width: 5px; border-width: 5px;
border-color: black; border-color: black;
} }
.${cssPrefix}popUp > div { .popUp > div {
width: 100%; width: 100%;
height: calc(100% -108px); height: calc(100% -108px);
margin: 0; margin: 0;
@@ -121,7 +116,7 @@ const cssContent = `
border-style: none none solid none; border-style: none none solid none;
overflow: auto; overflow: auto;
} }
.${cssPrefix}popUp > div > span { .popUp > div > span {
display: table-cell; display: table-cell;
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
@@ -133,13 +128,13 @@ const cssContent = `
vertical-align: middle; vertical-align: middle;
border-style: none; border-style: none;
} }
.${cssPrefix}popUp .cancel { .popUp .cancel {
float: left; float: left;
} }
.${cssPrefix}popUp .confirm { .popUp .confirm {
float: right; float: right;
} }
.${cssPrefix}popUp > button { .popUp > button {
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -153,10 +148,10 @@ const cssContent = `
height: 50px; height: 50px;
background: rgba(1, 1, 1, 0.2); background: rgba(1, 1, 1, 0.2);
} }
.${cssPrefix}popUp > button:hover { .popUp > button:hover {
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
} }
.${cssPrefix}popUpBG { .popUpBG {
display: block; display: block;
position: fixed; position: fixed;
top: 0; top: 0;