From 7c5adeabb5e99b5b7c6848bbcfc9a0c5181cdfcf Mon Sep 17 00:00:00 2001 From: sabhas Date: Fri, 19 Nov 2021 00:35:02 +0500 Subject: [PATCH 1/5] feat: parse response in webJobExecutor when server type is sasjs server --- src/job-execution/WebJobExecutor.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/job-execution/WebJobExecutor.ts b/src/job-execution/WebJobExecutor.ts index db054cc2..7be52f1d 100644 --- a/src/job-execution/WebJobExecutor.ts +++ b/src/job-execution/WebJobExecutor.ts @@ -113,6 +113,7 @@ export class WebJobExecutor extends BaseJobExecutor { const stringifiedData = JSON.stringify(data) if ( config.serverType === ServerType.Sas9 || + config.serverType === ServerType.Sasjs || stringifiedData.length > 500000 || stringifiedData.includes(';') ) { @@ -144,10 +145,23 @@ export class WebJobExecutor extends BaseJobExecutor { const requestPromise = new Promise((resolve, reject) => { this.requestClient!.post(apiUrl, formData, undefined) .then(async (res: any) => { - this.requestClient!.appendRequest(res, sasJob, config.debug) - let jsonResponse = res.result + if (this.serverType === ServerType.Sasjs && config.debug) { + this.requestClient!.appendRequest( + jsonResponse, + sasJob, + config.debug + ) + jsonResponse = JSON.parse(parseWeboutResponse(jsonResponse._webout)) + } else { + this.requestClient!.appendRequest(res, sasJob, config.debug) + } + + if (this.serverType === ServerType.Sasjs && !config.debug) { + jsonResponse = JSON.parse(jsonResponse._webout) + } + if (config.debug) { switch (this.serverType) { case ServerType.SasViya: From 81d959c7c1033255ce14e3011e3f91a903e387b7 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Thu, 18 Nov 2021 19:56:12 +0000 Subject: [PATCH 2/5] fix: parsing _webout from response regardless of debug status --- src/job-execution/WebJobExecutor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/job-execution/WebJobExecutor.ts b/src/job-execution/WebJobExecutor.ts index 7be52f1d..24229705 100644 --- a/src/job-execution/WebJobExecutor.ts +++ b/src/job-execution/WebJobExecutor.ts @@ -158,7 +158,7 @@ export class WebJobExecutor extends BaseJobExecutor { this.requestClient!.appendRequest(res, sasJob, config.debug) } - if (this.serverType === ServerType.Sasjs && !config.debug) { + if (this.serverType === ServerType.Sasjs) { jsonResponse = JSON.parse(jsonResponse._webout) } From 712d1549c7833c739142696072c9ee4fe0f3ae70 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sun, 5 Dec 2021 18:31:36 +0500 Subject: [PATCH 3/5] feat(server): added sasjs server support --- src/SASjs.ts | 13 ++++++++----- src/auth/AuthManager.ts | 28 ++++++++++++++++++---------- src/job-execution/WebJobExecutor.ts | 28 ++++++++++++++-------------- src/types/SASjsConfig.ts | 5 +++++ src/utils/getValidJson.ts | 2 +- src/utils/parseWeboutResponse.ts | 2 +- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/SASjs.ts b/src/SASjs.ts index 5c78bee0..76632e4d 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -33,6 +33,7 @@ import { LoginOptions, LoginResult } from './types/Login' const defaultConfig: SASjsConfig = { serverUrl: '', + pathSASJS: '/SASjsApi/stp/execute', pathSAS9: '/SASStoredProcess/do', pathSASViya: '/SASJobExecution', appLoc: '/Public/seedapp', @@ -529,8 +530,8 @@ export default class SASjs { * Checks whether a session is active, or login is required. * @returns - a promise which resolves with an object containing two values - a boolean `isLoggedIn`, and a string `userName`. */ - public async checkSession() { - return this.authManager!.checkSession() + public async checkSession(accessToken?: string) { + return this.authManager!.checkSession(accessToken) } /** @@ -564,8 +565,8 @@ export default class SASjs { /** * Logs out of the configured SAS server. */ - public logOut() { - return this.authManager!.logOut() + public logOut(accessToken?: string) { + return this.authManager!.logOut(accessToken) } /** @@ -975,7 +976,9 @@ export default class SASjs { this.jobsPath = this.sasjsConfig.serverType === ServerType.SasViya ? this.sasjsConfig.pathSASViya - : this.sasjsConfig.pathSAS9 + : this.sasjsConfig.serverType === ServerType.Sas9 + ? this.sasjsConfig.pathSAS9 + : this.sasjsConfig.pathSASJS this.authManager = new AuthManager( this.sasjsConfig.serverUrl, diff --git a/src/auth/AuthManager.ts b/src/auth/AuthManager.ts index 3932bff0..3c180886 100644 --- a/src/auth/AuthManager.ts +++ b/src/auth/AuthManager.ts @@ -21,7 +21,9 @@ export class AuthManager { this.logoutUrl = this.serverType === ServerType.Sas9 ? '/SASLogon/logout?' - : '/SASLogon/logout.do?' + : this.serverType === ServerType.SasViya + ? '/SASLogon/logout.do?' + : '/SASjsApi/auth/logout' } /** @@ -185,15 +187,15 @@ export class AuthManager { * - a string `userName` and * - a form `loginForm` if not loggedin. */ - public async checkSession(): Promise<{ + public async checkSession(accessToken?: string): Promise<{ isLoggedIn: boolean userName: string loginForm?: any }> { - const { isLoggedIn, userName } = await this.fetchUserName() + const { isLoggedIn, userName } = await this.fetchUserName(accessToken) let loginForm = null - if (!isLoggedIn) { + if (!isLoggedIn && this.serverType !== ServerType.Sasjs) { //We will logout to make sure cookies are removed and login form is presented //Residue can happen in case of session expiration await this.logOut() @@ -218,19 +220,19 @@ export class AuthManager { return await this.getLoginForm(formResponse) } - private async fetchUserName(): Promise<{ + private async fetchUserName(accessToken?: string): Promise<{ isLoggedIn: boolean userName: string }> { - //For VIYA we will send request on API endpoint. Which is faster then pinging SASJobExecution. - //For SAS9 we will send request on SASStoredProcess const url = this.serverType === ServerType.SasViya ? `${this.serverUrl}/identities/users/@currentUser` - : `${this.serverUrl}/SASStoredProcess` + : this.serverType === ServerType.Sas9 + ? `${this.serverUrl}/SASStoredProcess` + : `${this.serverUrl}/SASjsApi/session` const { result: loginResponse } = await this.requestClient - .get(url, undefined, 'text/plain') + .get(url, accessToken, 'text/plain') .catch((err: any) => { return { result: 'authErr' } }) @@ -257,6 +259,9 @@ export class AuthManager { .map((name: string) => name.slice(0, 3).toLowerCase()) .join('') + case ServerType.Sasjs: + return response?.username + default: console.error('Server Type not found in extractUserName function') return '' @@ -307,7 +312,10 @@ export class AuthManager { /** * Logs out of the configured SAS server. */ - public logOut() { + public logOut(accessToken?: string) { + if (this.serverType === ServerType.Sasjs) { + return this.requestClient.post(this.logoutUrl, undefined, accessToken) + } this.requestClient.clearCsrfTokens() return this.requestClient.get(this.logoutUrl, undefined).then(() => true) } diff --git a/src/job-execution/WebJobExecutor.ts b/src/job-execution/WebJobExecutor.ts index 24229705..de6a23b6 100644 --- a/src/job-execution/WebJobExecutor.ts +++ b/src/job-execution/WebJobExecutor.ts @@ -15,7 +15,8 @@ import { SASViyaApiClient } from '../SASViyaApiClient' import { isRelativePath, parseSasViyaDebugResponse, - appendExtraResponseAttributes + appendExtraResponseAttributes, + getValidJson } from '../utils' import { BaseJobExecutor } from './JobExecutor' import { parseWeboutResponse } from '../utils/parseWeboutResponse' @@ -143,23 +144,22 @@ export class WebJobExecutor extends BaseJobExecutor { } const requestPromise = new Promise((resolve, reject) => { - this.requestClient!.post(apiUrl, formData, undefined) + this.requestClient!.post(apiUrl, formData, authConfig?.access_token) .then(async (res: any) => { - let jsonResponse = res.result + const resObj = + this.serverType === ServerType.Sasjs + ? { + result: res.result._webout, + log: res.result.log + } + : res + this.requestClient!.appendRequest(resObj, sasJob, config.debug) - if (this.serverType === ServerType.Sasjs && config.debug) { - this.requestClient!.appendRequest( - jsonResponse, - sasJob, - config.debug - ) - jsonResponse = JSON.parse(parseWeboutResponse(jsonResponse._webout)) - } else { - this.requestClient!.appendRequest(res, sasJob, config.debug) - } + let jsonResponse = res.result if (this.serverType === ServerType.Sasjs) { - jsonResponse = JSON.parse(jsonResponse._webout) + const webout = parseWeboutResponse(res.result._webout, apiUrl) + jsonResponse = getValidJson(webout) } if (config.debug) { diff --git a/src/types/SASjsConfig.ts b/src/types/SASjsConfig.ts index af262045..a40db2f8 100644 --- a/src/types/SASjsConfig.ts +++ b/src/types/SASjsConfig.ts @@ -12,6 +12,11 @@ export class SASjsConfig { * streamed. */ serverUrl: string = '' + /** + * The location of the STP Process Web Application. By default the adapter + * will use '/SASjsApi/stp/execute' on SAS JS. + */ + pathSASJS: string = '' /** * The location of the Stored Process Web Application. By default the adapter * will use '/SASStoredProcess/do' on SAS 9. diff --git a/src/utils/getValidJson.ts b/src/utils/getValidJson.ts index 8d8670b6..ccf903e5 100644 --- a/src/utils/getValidJson.ts +++ b/src/utils/getValidJson.ts @@ -4,7 +4,7 @@ import { JsonParseArrayError, InvalidJsonError } from '../types/errors' * if string passed then parse the string to json else if throw error for all other types unless it is not a valid json object. * @param str - string to check. */ -export const getValidJson = (str: string | object) => { +export const getValidJson = (str: string | object): object => { try { if (str === null || str === undefined) throw new InvalidJsonError() diff --git a/src/utils/parseWeboutResponse.ts b/src/utils/parseWeboutResponse.ts index 30d91b6e..716cc314 100644 --- a/src/utils/parseWeboutResponse.ts +++ b/src/utils/parseWeboutResponse.ts @@ -1,6 +1,6 @@ import { WeboutResponseError } from '../types/errors' -export const parseWeboutResponse = (response: string, url?: string) => { +export const parseWeboutResponse = (response: string, url?: string): string => { let sasResponse = '' if (response.includes('>>weboutBEGIN<<')) { From 182de51f9be98fcf44d37284312ed07032501f3d Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sun, 5 Dec 2021 19:27:07 +0500 Subject: [PATCH 4/5] chore: added comments --- src/SASjs.ts | 2 ++ src/auth/AuthManager.ts | 3 +++ src/job-execution/WebJobExecutor.ts | 1 + 3 files changed, 6 insertions(+) diff --git a/src/SASjs.ts b/src/SASjs.ts index 76632e4d..e6db53d7 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -528,6 +528,7 @@ export default class SASjs { /** * Checks whether a session is active, or login is required. + * @param accessToken - an optional access token is required for SASjs server type. * @returns - a promise which resolves with an object containing two values - a boolean `isLoggedIn`, and a string `userName`. */ public async checkSession(accessToken?: string) { @@ -564,6 +565,7 @@ export default class SASjs { /** * Logs out of the configured SAS server. + * @param accessToken - an optional access token is required for SASjs server type. */ public logOut(accessToken?: string) { return this.authManager!.logOut(accessToken) diff --git a/src/auth/AuthManager.ts b/src/auth/AuthManager.ts index 3c180886..a0bddcc9 100644 --- a/src/auth/AuthManager.ts +++ b/src/auth/AuthManager.ts @@ -182,6 +182,7 @@ export class AuthManager { /** * Checks whether a session is active, or login is required. + * @param accessToken - an optional access token is required for SASjs server type. * @returns - a promise which resolves with an object containing three values * - a boolean `isLoggedIn` * - a string `userName` and @@ -231,6 +232,7 @@ export class AuthManager { ? `${this.serverUrl}/SASStoredProcess` : `${this.serverUrl}/SASjsApi/session` + // Access token is required for server type `SASjs` const { result: loginResponse } = await this.requestClient .get(url, accessToken, 'text/plain') .catch((err: any) => { @@ -311,6 +313,7 @@ export class AuthManager { /** * Logs out of the configured SAS server. + * @param accessToken - an optional access token is required for SASjs server type. */ public logOut(accessToken?: string) { if (this.serverType === ServerType.Sasjs) { diff --git a/src/job-execution/WebJobExecutor.ts b/src/job-execution/WebJobExecutor.ts index de6a23b6..9f91ab35 100644 --- a/src/job-execution/WebJobExecutor.ts +++ b/src/job-execution/WebJobExecutor.ts @@ -144,6 +144,7 @@ export class WebJobExecutor extends BaseJobExecutor { } const requestPromise = new Promise((resolve, reject) => { + // Access token is required for server type `SASjs` this.requestClient!.post(apiUrl, formData, authConfig?.access_token) .then(async (res: any) => { const resObj = From 3a4a4c3460693b8f57063fcbd8af4b12f18073e8 Mon Sep 17 00:00:00 2001 From: Mihajlo Date: Mon, 6 Dec 2021 17:44:08 +0100 Subject: [PATCH 5/5] chore: sasjs path optional --- src/SASjs.ts | 2 +- src/types/SASjsConfig.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SASjs.ts b/src/SASjs.ts index e6db53d7..68946127 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -980,7 +980,7 @@ export default class SASjs { ? this.sasjsConfig.pathSASViya : this.sasjsConfig.serverType === ServerType.Sas9 ? this.sasjsConfig.pathSAS9 - : this.sasjsConfig.pathSASJS + : this.sasjsConfig.pathSASJS || '' this.authManager = new AuthManager( this.sasjsConfig.serverUrl, diff --git a/src/types/SASjsConfig.ts b/src/types/SASjsConfig.ts index a40db2f8..8aab6784 100644 --- a/src/types/SASjsConfig.ts +++ b/src/types/SASjsConfig.ts @@ -16,7 +16,7 @@ export class SASjsConfig { * The location of the STP Process Web Application. By default the adapter * will use '/SASjsApi/stp/execute' on SAS JS. */ - pathSASJS: string = '' + pathSASJS?: string = '' /** * The location of the Stored Process Web Application. By default the adapter * will use '/SASStoredProcess/do' on SAS 9.