diff --git a/src/SASjs.ts b/src/SASjs.ts index e77d22f5..1b1359ee 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', @@ -527,10 +528,11 @@ 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() { - return this.authManager!.checkSession() + public async checkSession(accessToken?: string) { + return this.authManager!.checkSession(accessToken) } /** @@ -563,9 +565,10 @@ 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() { - return this.authManager!.logOut() + public logOut(accessToken?: string) { + return this.authManager!.logOut(accessToken) } /** @@ -975,7 +978,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..a0bddcc9 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' } /** @@ -180,20 +182,21 @@ 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 * - 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 +221,20 @@ 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` + // Access token is required for server type `SASjs` const { result: loginResponse } = await this.requestClient - .get(url, undefined, 'text/plain') + .get(url, accessToken, 'text/plain') .catch((err: any) => { return { result: 'authErr' } }) @@ -257,6 +261,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 '' @@ -306,8 +313,12 @@ export class AuthManager { /** * Logs out of the configured SAS server. + * @param accessToken - an optional access token is required for SASjs server type. */ - 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 db054cc2..9f91ab35 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' @@ -113,6 +114,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(';') ) { @@ -142,12 +144,25 @@ export class WebJobExecutor extends BaseJobExecutor { } const requestPromise = new Promise((resolve, reject) => { - this.requestClient!.post(apiUrl, formData, undefined) + // Access token is required for server type `SASjs` + this.requestClient!.post(apiUrl, formData, authConfig?.access_token) .then(async (res: any) => { - this.requestClient!.appendRequest(res, sasJob, config.debug) + const resObj = + this.serverType === ServerType.Sasjs + ? { + result: res.result._webout, + log: res.result.log + } + : res + this.requestClient!.appendRequest(resObj, sasJob, config.debug) let jsonResponse = res.result + if (this.serverType === ServerType.Sasjs) { + const webout = parseWeboutResponse(res.result._webout, apiUrl) + jsonResponse = getValidJson(webout) + } + if (config.debug) { switch (this.serverType) { case ServerType.SasViya: diff --git a/src/types/SASjsConfig.ts b/src/types/SASjsConfig.ts index af262045..8aab6784 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<<')) {