diff --git a/src/SASViyaApiClient.ts b/src/SASViyaApiClient.ts index 75fecb0..5b5d860 100644 --- a/src/SASViyaApiClient.ts +++ b/src/SASViyaApiClient.ts @@ -29,6 +29,7 @@ import { executeOnComputeApi } from './api/viya/executeOnComputeApi' import { getAccessTokenForViya } from './auth/getAccessTokenForViya' import { refreshTokensForViya } from './auth/refreshTokensForViya' import { FileContentUpdate } from './types/FileContentUpdate' +import { FileResource } from './types/FileResource' interface JobExecutionResult { result?: { result: object } @@ -324,7 +325,7 @@ export class SASViyaApiClient { fileName: string, accessToken?: string ) { - const { fileUri } = await this.getFileUri( + const fileUri = await this.getFileUri( folderPath, fileName, accessToken @@ -354,7 +355,7 @@ export class SASViyaApiClient { content: string, accessToken?: string ) { - const { fileUri, etag } = await this.getFileUri( + const fileUri = await this.getFileUri( folderPath, fileName, accessToken @@ -365,6 +366,18 @@ export class SASViyaApiClient { ) }) + // Fetch the file resource details to get the Etag and content type + const { result: originalFileResource, etag } = + await this.requestClient.get( + `${this.serverUrl}${fileUri}`, + accessToken + ) + + if (!originalFileResource || !etag) + throw new Error( + `File ${fileName} does not have an ETag, or request failed.` + ) + return await this.requestClient .put( `${this.serverUrl}${fileUri}/content`, @@ -372,7 +385,7 @@ export class SASViyaApiClient { accessToken, { 'If-Match': etag, - 'Content-Type': 'text/plain' + 'Content-Type': originalFileResource.contentType } ) .then((res) => res.result) @@ -1024,10 +1037,7 @@ export class SASViyaApiClient { folderPath: string, fileName: string, accessToken?: string - ): Promise<{ - fileUri: string - etag: string - }> { + ): Promise { const folderMembers = await this.listFolder(folderPath, accessToken, 1000, { returnDetails: true }).catch((err) => { @@ -1044,21 +1054,7 @@ export class SASViyaApiClient { if (!fileUri) throw new Error(`File ${fileName} not found in folder: ${folderPath}`) - // Fetch the file details to get the resource ETag - const { etag } = await this.requestClient.get( - `${this.serverUrl}${fileUri}`, - accessToken - ) - - if (!etag) - throw new Error( - `File ${fileName} does not have an ETag, or request failed.` - ) - - return { - fileUri, - etag: etag || '' - } + return fileUri } private async getRecycleBinUri(accessToken?: string) { diff --git a/src/SASjs.ts b/src/SASjs.ts index 71db4c8..33f05d1 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -411,6 +411,13 @@ export default class SASjs { ) } + /** + * Fetches the file content for a file in the specified folder. + * + * @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2 + * @param fileName - the name of the file in the `folderPath` + * @param accessToken - an access token for authorizing the request + */ public async getFileContent( folderPath: string, fileName: string, @@ -425,6 +432,14 @@ export default class SASjs { ) } + /** + * Updates the file content for a file in the specified folder. + * + * @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2 + * @param fileName - the name of the file in the `folderPath` + * @param content - the new content to be written to the file + * @param accessToken - an access token for authorizing the request + */ public async updateFileContent( folderPath: string, fileName: string, diff --git a/src/types/FileResource.ts b/src/types/FileResource.ts new file mode 100644 index 0000000..5b1bd63 --- /dev/null +++ b/src/types/FileResource.ts @@ -0,0 +1,33 @@ +export interface FileResource { + creationTimeStamp: string + modifiedTimeStamp: string + createdBy: string + modifiedBy: string + id: string + properties: Properties + contentDisposition: string + contentType: string + encoding: string + links: Link[] + name: string + size: number + searchable: boolean + fileStatus: string + fileVersion: number + typeDefName: string + version: number + virusDetected: boolean + urlDetected: boolean + quarantine: boolean +} + +export interface Link { + method: string + rel: string + href: string + uri: string + type?: string + responseType?: string +} + +export interface Properties {}