Skip to content

Commit

Permalink
Merge pull request #586 from sasjs/handle-sasjs-server-response
Browse files Browse the repository at this point in the history
fix: handle sasjs server response
  • Loading branch information
allanbowe authored Dec 8, 2021
2 parents 5a478c8 + 3a4a4c3 commit b645d14
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 20 deletions.
15 changes: 10 additions & 5 deletions src/SASjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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)
}

/**
Expand Down Expand Up @@ -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)
}

/**
Expand Down Expand Up @@ -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,
Expand Down
31 changes: 21 additions & 10 deletions src/auth/AuthManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

/**
Expand Down Expand Up @@ -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()
Expand All @@ -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<string>(url, undefined, 'text/plain')
.get<string>(url, accessToken, 'text/plain')
.catch((err: any) => {
return { result: 'authErr' }
})
Expand All @@ -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 ''
Expand Down Expand Up @@ -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)
}
Expand Down
21 changes: 18 additions & 3 deletions src/job-execution/WebJobExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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(';')
) {
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions src/types/SASjsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/utils/getValidJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
2 changes: 1 addition & 1 deletion src/utils/parseWeboutResponse.ts
Original file line number Diff line number Diff line change
@@ -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<<')) {
Expand Down

1 comment on commit b645d14

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

Total coverage

Status Category Percentage Covered / Total
🔴 Statements 58.03% 1605/2766
🔴 Branches 39.16% 551/1407
🔴 Functions 45.63% 230/504
🟡 Lines 67.03% 2568/3831

Status of coverage: 🟢 - ok, 🟡 - slightly more than threshold, 🔴 - under the threshold

Report generated by 🧪jest coverage report action from b645d14

Please sign in to comment.