diff --git a/src/SASViyaApiClient.ts b/src/SASViyaApiClient.ts index b560076..09b189a 100644 --- a/src/SASViyaApiClient.ts +++ b/src/SASViyaApiClient.ts @@ -34,6 +34,7 @@ export class SASViyaApiClient { this.contextName, this.setCsrfToken ) + private isForceDeploy: boolean = false /** * Returns a map containing the directory structure in the currently set root folder. @@ -365,7 +366,8 @@ export class SASViyaApiClient { folderName: string, parentFolderPath?: string, parentFolderUri?: string, - accessToken?: string + accessToken?: string, + isForced?: boolean ): Promise { if (!parentFolderPath && !parentFolderUri) { throw new Error('Parent folder path or uri is required') @@ -394,6 +396,44 @@ export class SASViyaApiClient { accessToken ) console.log(`Parent Folder "${newFolderName}" successfully created.`) + parentFolderUri = `/folders/folders/${parentFolder.id}` + } else if (isForced && accessToken && !this.isForceDeploy) { + this.isForceDeploy = true + const recycleBin = await this.getRecycleBin(accessToken) + const recycleBinUri = recycleBin?.id || '' + const oldFolderName = parentFolderPath?.split('/').pop() || '' + const parentFolderId = parentFolderUri?.split('/').pop() || '' + + await this.moveFolder( + parentFolderId, + recycleBinUri, + oldFolderName, + accessToken + ) + + const newParentFolderPath = parentFolderPath.substring( + 0, + parentFolderPath.lastIndexOf('/') + ) + const newFolderName = `${parentFolderPath.split('/').pop()}` + + if (newParentFolderPath === '') { + throw new Error('Root Folder should have been present on server') + } + + console.log( + `Creating Parent Folder:\n${newFolderName} in ${newParentFolderPath}` + ) + + const parentFolder = await this.createFolder( + newFolderName, + newParentFolderPath, + undefined, + accessToken + ) + + console.log(`Parent Folder "${newFolderName}" successfully created.`) + parentFolderUri = `/folders/folders/${parentFolder.id}` } } @@ -1085,6 +1125,60 @@ export class SASViyaApiClient { return `/folders/folders/${folder.id}` } + private async getRecycleBin(accessToken: string) { + const url = '/folders/folders/@myRecycleBin' + const requestInfo = { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + accessToken + } + } + + const { result: folder } = await this.request( + `${this.serverUrl}${url}`, + requestInfo + ).catch((err) => { + return { result: null } + }) + + if (!folder) return undefined + + return folder + } + + private async moveFolder( + from: string, + to: string, + folderName: string, + accessToken: string + ) { + const url = '/folders/folders/' + from + const requestInfo = { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + accessToken + }, + body: JSON.stringify({ + id: from, + name: folderName, + parentFolderUri: '/folders/folders/' + to + }) + } + + const { result: folder } = await this.request( + `${this.serverUrl}${url}`, + requestInfo + ).catch((err) => { + return { result: null } + }) + + if (!folder) return undefined + + return folder + } + setCsrfTokenLocal = (csrfToken: CsrfToken) => { this.csrfToken = csrfToken this.setCsrfToken(csrfToken) diff --git a/src/SASjs.ts b/src/SASjs.ts index 02eecc6..1dc4ace 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -139,7 +139,8 @@ export default class SASjs { parentFolderPath: string, parentFolderUri?: string, accessToken?: string, - sasApiClient?: SASViyaApiClient + sasApiClient?: SASViyaApiClient, + isForced?: boolean ) { if (this.sasjsConfig.serverType !== ServerType.SASViya) { throw new Error('This operation is only supported on SAS Viya servers.') @@ -155,7 +156,8 @@ export default class SASjs { folderName, parentFolderPath, parentFolderUri, - accessToken + accessToken, + isForced ) } @@ -489,7 +491,8 @@ export default class SASjs { serviceJson: any, appLoc?: string, serverUrl?: string, - accessToken?: string + accessToken?: string, + isForced = false ) { if (this.sasjsConfig.serverType !== ServerType.SASViya) { throw new Error('This operation is only supported on SAS Viya servers.') @@ -540,7 +543,8 @@ export default class SASjs { appLoc, members, accessToken, - sasApiClient + sasApiClient, + isForced ) } @@ -1247,7 +1251,8 @@ export default class SASjs { parentFolder: string, membersJson: any[], accessToken?: string, - sasApiClient?: SASViyaApiClient + sasApiClient?: SASViyaApiClient, + isForced?: boolean ) { await asyncForEach(membersJson, async (member: any) => { switch (member.type) { @@ -1257,7 +1262,8 @@ export default class SASjs { parentFolder, undefined, accessToken, - sasApiClient + sasApiClient, + isForced ) break case 'service': @@ -1278,7 +1284,8 @@ export default class SASjs { `${parentFolder}/${member.name}`, member.members, accessToken, - sasApiClient + sasApiClient, + isForced ) }) }