From 6d0df4d335510c1f221ddcf71dc94a86ad5e6724 Mon Sep 17 00:00:00 2001 From: Siddharth9890 Date: Tue, 1 Oct 2024 15:42:06 +0530 Subject: [PATCH] feat: refactored data assets, acl, auth methods and test --- scripts/generate-types.js | 7 +- src/common/types.ts | 7 +- src/helpers/helper.ts | 17 +- src/index.ts | 20 +- src/modules/auth/auth.ts | 24 ++- src/modules/data-asset/acl.ts | 99 ++++++++++ src/modules/data-asset/data-asset.ts | 284 ++++++++++----------------- test/acl.test.ts | 105 ++++++++++ test/auth.test.ts | 8 +- test/data-asset.test.ts | 127 +++--------- test/helper.test.ts | 10 +- 11 files changed, 400 insertions(+), 308 deletions(-) create mode 100644 src/modules/data-asset/acl.ts create mode 100644 test/acl.test.ts diff --git a/scripts/generate-types.js b/scripts/generate-types.js index 20d7419..760d1cb 100644 --- a/scripts/generate-types.js +++ b/scripts/generate-types.js @@ -65,10 +65,13 @@ import { WalletService } from '../services/wallet-service'; `export type Environment = 'dev' | 'prod';export type TokenManagementMode = 'jwt' | 'privateKey'; \n`, `export interface Config { - privateKey?: string; + jwt?:string environment: Environment; logging?: boolean; - walletType: WalletTypeEnum; + wallet?: { + privateKey: string; + walletType: WalletTypeEnum; + }; }\n\n`, `export interface WalletSignMessageType { signature: string; diff --git a/src/common/types.ts b/src/common/types.ts index e08d61d..bec1341 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -11,10 +11,13 @@ export type Environment = 'dev' | 'prod'; export type TokenManagementMode = 'jwt' | 'privateKey'; export interface Config { - privateKey?: string; environment: Environment; + jwt?: string; logging?: boolean; - walletType: WalletTypeEnum; + wallet?: { + privateKey: string; + walletType: WalletTypeEnum; + }; } export interface WalletSignMessageType { diff --git a/src/helpers/helper.ts b/src/helpers/helper.ts index d866853..d13eb04 100644 --- a/src/helpers/helper.ts +++ b/src/helpers/helper.ts @@ -34,14 +34,14 @@ export const parameterChecker = ( if (!environment) throw new Error('No url found!.Use either sandbox or production env'); - if (jwt) { + if (privateKey) { + mode = 'privateKey'; + value = privateKey; + } else if (jwt) { mode = 'jwt'; value = jwt; if (!checkJWTTokenExpiration(jwt)) throw new Error('The provided token is expired or invalid.'); - } else if (privateKey) { - mode = 'privateKey'; - value = privateKey; } else { throw new Error('Need jwt or private key'); } @@ -54,6 +54,13 @@ export const parameterChecker = ( let accessToken: string | undefined = undefined; +/** + * The function `checkJWTTokenExpiration` verifies if a JWT token is expired or not. + * @param {string} existinToken - The `existinToken` parameter is a string representing a JWT token + * that you want to check for expiration. + * @returns The function `checkJWTTokenExpiration` returns a boolean value. It returns `true` if the + * JWT token is valid and has not expired, and `false` if the token is invalid or has expired. + */ export const checkJWTTokenExpiration = (existinToken: string): boolean => { try { const decodedToken = jwt.decode(existinToken) as JWTData | null; @@ -79,7 +86,7 @@ export const issueJWT = async ( ) => { const auth = new Auth(client); - const message = await auth.generateSignMessage(); + const message = await auth.getMessage(); const signatureDetails = await wallet.signMessage(message); const jwt = await auth.login({ diff --git a/src/index.ts b/src/index.ts index 9c084ac..5ec3d04 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,6 @@ import { Account } from './modules/account/account'; export * from './common/types'; export { toRFC3339, checkJWTTokenExpiration } from './helpers/helper'; -export { GTWError } from './helpers/custom-error'; class SDKFactory { static createSDK({ @@ -66,16 +65,17 @@ export class Gateway { constructor(config: Config) { const validationService = new ValidationService(); - if (config.privateKey) + if (config.wallet) this.wallet = new WalletService({ - walletPrivateKey: config.privateKey, - walletType: config.walletType, + walletPrivateKey: config.wallet!.privateKey, + walletType: config.wallet!.walletType, }); this.client = SDKFactory.createSDK({ environment: config.environment, - privateKey: config.privateKey, + privateKey: config.wallet?.privateKey, logging: config.logging, wallet: this.wallet, + jwt: config.jwt, }); this.config = config; @@ -92,16 +92,18 @@ export class Gateway { public updateConfig(newConfig: Partial) { const validationService = new ValidationService(); this.config = { ...this.config, ...newConfig }; - if (this.config.privateKey) + + if (this.config.wallet) this.wallet = new WalletService({ - walletPrivateKey: this.config.privateKey, - walletType: this.config.walletType, + walletPrivateKey: this.config.wallet!.privateKey, + walletType: this.config.wallet!.walletType, }); this.client = SDKFactory.createSDK({ environment: this.config.environment, - privateKey: this.config.privateKey, + privateKey: this.config.wallet?.privateKey, logging: this.config.logging, wallet: this.wallet, + jwt: this.config.jwt, }); this.initializeModules(validationService); } diff --git a/src/modules/auth/auth.ts b/src/modules/auth/auth.ts index 7d3949f..f4568ea 100644 --- a/src/modules/auth/auth.ts +++ b/src/modules/auth/auth.ts @@ -13,7 +13,13 @@ export class Auth { this.cryptoService = new CryptoService(); } - public async generateSignMessage() { + /** + * This TypeScript function asynchronously fetches a message from a specified endpoint and returns + * the message data if successful, throwing an error if there is an issue. + * @returns The `getMessage` function is returning the `message` property from the `data` object + * fetched from the `/auth/message` endpoint. + */ + public async getMessage() { const { data, error, response } = await this.client.GET('/auth/message'); if (error) { @@ -23,7 +29,12 @@ export class Auth { return data.message; } - public async generateRefreshToken() { + /** + * This TypeScript function asynchronously retrieves a refresh token from a specified endpoint and + * returns the token if successful. + * @returns The `getRefreshToken` function is returning the `token` property from the `data` object. + */ + public async getRefreshToken() { const { data, error, response } = await this.client.GET( '/auth/refresh-token', ); @@ -35,6 +46,15 @@ export class Auth { return data.token; } + /** + * The login function verifies a message signature and wallet address, then sends a POST request to + * authenticate and returns a token. + * @param {AuthRequest} - The `login` function takes an object as a parameter with the following + * properties: + * @returns The `login` function is returning the `token` from the `data` object after successfully + * verifying the message signature and making a POST request to the `/auth` endpoint with the + * provided message, signature, and wallet address. + */ public async login({ message, signature, wallet_address }: AuthRequest) { await this.cryptoService.verifyMessage(signature, message, wallet_address); diff --git a/src/modules/data-asset/acl.ts b/src/modules/data-asset/acl.ts new file mode 100644 index 0000000..5b34fc3 --- /dev/null +++ b/src/modules/data-asset/acl.ts @@ -0,0 +1,99 @@ +import { MediaType } from 'openapi-typescript-helpers'; +import { paths } from '../../api'; +import { OpenAPIClient, ACLRequest, PublicACL } from '../../common/types'; +import { GTWError } from '../../helpers/custom-error'; +import { ValidationService } from '../../services/validator-service'; + +export class ACL { + private client: OpenAPIClient; + private validationService: ValidationService; + + constructor( + client: OpenAPIClient, + validationService: ValidationService, + ) { + this.client = client; + this.validationService = validationService; + } + + /** + * This TypeScript function updates the Access Control List (ACL) for a specific data asset + * identified by its ID. + * @param {number} id - The `id` parameter is a number that represents the identifier of a data asset + * for which the Access Control List (ACL) is being updated. + * @param {ACLRequest[]} aclList - The `aclList` parameter in the `update` function is an array of + * `ACLRequest` objects. These objects likely contain information related to access control lists + * (ACLs) for a specific data asset identified by the `id` parameter. The function sends a PATCH + * request to update the ACLs + * @returns The `update` method is returning a Promise that resolves to an array of `PublicACL` + * objects. + */ + public async update(id: number, aclList: ACLRequest[]): Promise { + const { data, error, response } = await this.client.PATCH( + '/data-assets/{id}/acl', + { + params: { path: { id } }, + body: aclList, + }, + ); + + if (error) { + throw new GTWError(error, response); + } + + return data; + } + + /** + * Note:- this method overwrites ACL list for data asset so be sure before using it! + * This TypeScript function adds ACL entries for a specific data asset identified by its ID. + * @param {number} id - The `id` parameter is a number that represents the identifier of a data asset + * to which the Access Control List (ACL) will be added. + * @param {ACLRequest[]} aclList - The `aclList` parameter in the `add` method is an array of + * `ACLRequest` objects. Each `ACLRequest` object likely contains information related to access + * control for a specific data asset identified by the `id` parameter. The `add` method sends a POST + * request to add the + * @returns The `add` method is returning a Promise that resolves to an array of `PublicACL` objects. + */ + public async add(id: number, aclList: ACLRequest[]): Promise { + const { data, error, response } = await this.client.POST( + '/data-assets/{id}/acl', + { + params: { path: { id } }, + body: aclList, + }, + ); + + if (error) { + throw new GTWError(error, response); + } + + return data; + } + + /** + * This TypeScript function deletes ACL entries for a specific data asset using a PATCH request. + * @param {number} id - The `id` parameter in the `delete` function is a number that represents the + * identifier of the data asset that you want to delete the ACL (Access Control List) for. + * @param {ACLRequest[]} aclList - The `aclList` parameter in the `delete` function is an array of + * `ACLRequest` objects. Each `ACLRequest` object likely contains information about access control + * permissions for a specific resource or data asset. The function uses this array to specify which + * access control entries should be deleted for the data + * @returns the message from the `data` object, which is accessed using `data.message`. + */ + public async delete(id: number, aclList: ACLRequest[]) { + const { data, error, response } = await this.client.PATCH( + '/data-assets/{id}/acl/delete', + { + params: { path: { id } }, + body: aclList, + }, + ); + + if (error) { + throw new GTWError(error, response); + } + + return data.message!; + } +} diff --git a/src/modules/data-asset/data-asset.ts b/src/modules/data-asset/data-asset.ts index 59e33f3..1d4bd82 100644 --- a/src/modules/data-asset/data-asset.ts +++ b/src/modules/data-asset/data-asset.ts @@ -11,29 +11,31 @@ import { ValidationService } from '../../services/validator-service'; import { paths } from '../../api'; import { GTWError } from '../../helpers/custom-error'; import { toRFC3339 } from '../../helpers/helper'; +import { ACL } from './acl'; export class DataAsset { private client: OpenAPIClient; private validationService: ValidationService; + public acl: ACL; constructor( client: OpenAPIClient, validationService: ValidationService, ) { this.client = client; + this.acl = new ACL(client, validationService); this.validationService = validationService; } /** - * The function creates a structured data asset by sending a POST request with the provided data - * asset body. - * @param {CreateDataAssetRequest} structuredDataAssetBody - The `claimDataAssetBody` parameter in the - * `createStructuredDataAsset` function is of type `CreateDataAssetRequest`. It is used as the body - * of the POST request to create a new data asset by sending it to the `/data-assets` endpoint. - * @returns The `createStructuredDataAsset` function is returning the `id` of the data asset that was - * created. + * The function creates a structured data asset by making a POST request to a specific endpoint and + * returns the ID of the created asset. + * @param {CreateDataAssetRequest} structuredDataAssetBody - The `structuredDataAssetBody` parameter + * in the `createStructured` function is of type `CreateDataAssetRequest`. This parameter likely + * contains the structured data asset information needed to create a new data asset. + * @returns The `id` of the created data asset is being returned. */ - public async createStructuredDataAsset( + public async createStructured( structuredDataAssetBody: CreateDataAssetRequest, ) { const { data, error, response } = await this.client.POST('/data-assets', { @@ -48,18 +50,25 @@ export class DataAsset { } /** - * The function `createNonStructuredDataAsset` asynchronously creates a data asset using a file buffer - * and file name. + * This TypeScript function creates a non-structured data asset with optional ACL and expiration date + * parameters. * @param {string} fileName - The `fileName` parameter is a string that represents the name of the - * file being uploaded as a data asset. - * @param {Buffer} fileBuffer - The `fileBuffer` parameter in the `createNonStructuredDataAsset` function - * is a `Buffer` object that contains the data of the file to be uploaded as a data asset. It is used - * to create a Blob object that represents the file data in the FormData object before sending it to - * the server - * @returns The `createNonStructuredDataAsset` function is returning the `id` of the data asset that was + * file being uploaded. + * @param {Buffer} fileBuffer - The `fileBuffer` parameter in the `createNonStructured` function is a + * Buffer containing the data of the file to be uploaded. It is used to read and store the contents + * of the file before sending it to the server. + * @param {ACLRequest} [aclList] - The `aclList` parameter in the `createNonStructured` function is + * an optional parameter that represents the Access Control List (ACL) for the file being created. It + * is of type `ACLRequest`, which likely contains information about the permissions and access rights + * associated with the file. If provided, the + * @param {Date} [expiration_date] - The `expiration_date` parameter in the `createNonStructured` + * function is an optional parameter that represents the date when the file should expire. If + * provided, it is converted to the RFC3339 format using the `toRFC3339` function before appending it + * to the form data. This allows you + * @returns The function `createNonStructured` is returning the `id` of the data asset that was * created. */ - public async createNonStructuredDataAsset( + public async createNonStructured( fileName: string, fileBuffer: Buffer, aclList?: ACLRequest, @@ -96,21 +105,18 @@ export class DataAsset { } /** - * This function retrieves data assets created by the user with pagination support. + * This TypeScript function retrieves data assets created by the user with pagination support. * @param {number} [page=1] - The `page` parameter is used to specify the page number of the results * you want to retrieve. It defaults to 1 if not provided. - * @param {number} [page_size=10] - The `page_size` parameter in the `getDataAssetsCreatedByMe` - * function specifies the number of data assets to be displayed per page when fetching data assets - * created by the user. By default, it is set to 10, meaning that the function will return a - * paginated list of 10 data assets - * @returns The `getDataAssetsCreatedByMe` function returns a paginated response containing public - * data assets created by the user. The response includes data of type `HelperPaginatedResponse` with - * an array of `PublicDataAsset` objects. + * @param {number} [page_size=10] - The `page_size` parameter in the `getCreatedByMe` function + * specifies the number of items to be displayed per page when fetching data assets that were created + * by the user. By default, it is set to 10, meaning that the function will return a paginated list + * of up to 10 + * @returns The `getCreatedByMe` function is returning a paginated response of public data assets + * that were created by the user. The response includes data of type `HelperPaginatedResponse` + * containing an array of `PublicDataAsset` objects. */ - public async getDataAssetsCreatedByMe( - page: number = 1, - page_size: number = 10, - ) { + public async getCreatedByMe(page: number = 1, page_size: number = 10) { const { data, response, error } = await this.client.GET( '/data-assets/created', { @@ -126,21 +132,17 @@ export class DataAsset { } /** - * This function retrieves received data assets with pagination parameters from the server. - * @param {number} [page=1] - The `page` parameter is used to specify the page number of the data - * assets you want to retrieve. By default, it is set to 1, meaning that the function will initially - * retrieve data assets from the first page. - * @param {number} [page_size=10] - The `page_size` parameter in the `getDataAssetsReceivedToMe` - * function specifies the number of data assets to be displayed per page when fetching received data - * assets. By default, it is set to 10, meaning that the function will return a list of 10 data - * assets per page unless specified - * @returns The function `getDataAssetsReceivedToMe` is returning data as a `HelperPaginatedResponse` - * containing an array of `PublicDataAsset` objects. + * This TypeScript function retrieves received data assets with pagination parameters. + * @param {number} [page=1] - The `page` parameter is used to specify the page number of the + * paginated data that you want to retrieve. It defaults to 1 if not provided. + * @param {number} [page_size=10] - The `page_size` parameter in the `getReceivedToMe` function + * specifies the number of items to be displayed per page when fetching received data assets. By + * default, it is set to 10, meaning that the function will return a maximum of 10 data assets per + * page unless specified otherwise. + * @returns The `getReceivedToMe` function is returning a `HelperPaginatedResponse` object containing + * an array of `PublicDataAsset` objects. */ - public async getDataAssetsReceivedToMe( - page: number = 1, - page_size: number = 10, - ) { + public async getReceivedToMe(page: number = 1, page_size: number = 10) { const { data, response, error } = await this.client.GET( '/data-assets/received', { @@ -156,17 +158,16 @@ export class DataAsset { } /** - * This TypeScript function retrieves a public data asset by its ID asynchronously. - * @param {number} id - The `id` parameter in the `getDataAssetById` function is a number that - * represents the unique identifier of the data asset you want to retrieve. This function is designed - * to fetch a specific data asset by its ID from the server. - * @returns The `getDataAssetById` function is returning a Promise that resolves to a - * `PublicDataAsset` object. The function makes an asynchronous GET request to fetch data for a - * specific data asset identified by the `id` parameter. If there is an error during the request, a - * `GTWError` is thrown with the error and response details. Otherwise, the function returns the - * fetched data. + * This TypeScript function retrieves detailed information about a public data asset using an API + * call. + * @param {number} id - The `id` parameter in the `getDetail` function is a number that represents + * the unique identifier of the data asset you want to retrieve details for. + * @returns The `getDetail` function is returning a Promise that resolves to a `PublicDataAsset` + * object. The function makes an asynchronous GET request to fetch details of a data asset with the + * specified `id`. If there is an error during the request, a `GTWError` is thrown with the error and + * response details. Otherwise, the function returns the fetched data. */ - public async getDataAssetById(id: number): Promise { + public async getDetail(id: number): Promise { const { data, error, response } = await this.client.GET( '/data-assets/{id}', { @@ -182,16 +183,17 @@ export class DataAsset { } /** - * This TypeScript function updates a claim-based data asset using a PUT request. - * @param {number} id - The `id` parameter is a number that represents the identifier of the data - * asset that you want to update. - * @param {CreateDataAssetRequest} structuredDataAssetBody - The `claimDataAssetBody` parameter in the - * `updateStructuredDataAsset` function is of type `CreateDataAssetRequest`. It contains the data - * necessary to update a data asset based on a claim. - * @returns The `updateStructuredDataAsset` function returns a Promise that resolves to a + * This TypeScript function updates a structured data asset by making a PUT request to a specific + * endpoint with the provided data. + * @param {number} id - The `id` parameter is a number that represents the identifier of the + * structured data asset that you want to update. + * @param {CreateDataAssetRequest} structuredDataAssetBody - The `structuredDataAssetBody` parameter + * in the `updateStructured` function is of type `CreateDataAssetRequest`. This parameter likely + * contains the structured data that will be used to update a data asset with the specified `id`. + * @returns The `updateStructured` function is returning a Promise that resolves to a * `PublicDataAsset` object. */ - public async updateStructuredDataAsset( + public async updateStructured( id: number, structuredDataAssetBody: CreateDataAssetRequest, ): Promise { @@ -210,7 +212,28 @@ export class DataAsset { return data; } - public async updateNonStructuredDataAsset( + /** + * This TypeScript function updates a non-structured data asset with optional ACL and expiration date + * parameters. + * @param {number} id - The `id` parameter in the `updateNonStructured` function is a number + * representing the identifier of the data asset that you want to update. + * @param {string} fileName - The `fileName` parameter in the `updateNonStructured` function is a + * string that represents the name of the file being updated. + * @param {Buffer} fileBuffer - The `fileBuffer` parameter in the `updateNonStructured` function is a + * Buffer containing the data of the file to be updated. It is used to read and manipulate the + * contents of the file before sending it to the server for updating. + * @param {ACLRequest} [aclList] - The `aclList` parameter in the `updateNonStructured` function is + * an optional parameter of type `ACLRequest`. It is used to specify the Access Control List (ACL) + * settings for the file being updated. If provided, the function will include the ACL information in + * the request payload when updating the + * @param {Date} [expiration_date] - The `expiration_date` parameter in the `updateNonStructured` + * function is an optional parameter that represents the date when the data asset will expire. If + * provided, it will be appended to the form data before making the PUT request to update the data + * asset. The `expiration_date` is expected to be + * @returns The `updateNonStructured` method is returning the `data` object after making a PUT + * request to update a non-structured data asset. + */ + public async updateNonStructured( id: number, fileName: string, fileBuffer: Buffer, @@ -252,13 +275,13 @@ export class DataAsset { } /** - * This function deletes a data asset by its ID using an HTTP DELETE request. - * @param {number} id - The `id` parameter in the `deleteDataAsset` function is a number that - * represents the unique identifier of the data asset that you want to delete. - * @returns The `deleteDataAsset` function is returning the message from the `data` object, which is - * accessed using `data.message`. + * This TypeScript function deletes a data asset by its ID using an HTTP DELETE request. + * @param {number} id - The `id` parameter in the `delete` function is a number that represents the + * unique identifier of the data asset that you want to delete. + * @returns The `delete` method is returning the message from the `data` object after making a DELETE + * request to the specified endpoint. */ - public async deleteDataAsset(id: number) { + public async delete(id: number) { const { data, error, response } = await this.client.DELETE( '/data-assets/{id}', { @@ -273,110 +296,19 @@ export class DataAsset { return data.message!; } - /** - * This function updates the Access Control List (ACL) for a specific data asset identified by its - * ID. - * @param {number} id - The `id` parameter is a number that represents the identifier of the data - * asset for which the Access Control List (ACL) is being updated. - * @param {ACLRequest[]} aclList - The `aclList` parameter in the `updateACL` function is an array of - * `ACLRequest` objects. Each `ACLRequest` object typically contains information about access control - * settings for a specific resource or data asset. These settings may include permissions, roles, - * users, or groups that are allowed or - * @returns the message from the `data` object, which is accessed using `data.message!`. - */ - public async updateACL( - id: number, - aclList: ACLRequest[], - ): Promise { - const { data, error, response } = await this.client.PATCH( - '/data-assets/{id}/acl', - { - params: { path: { id } }, - body: aclList, - }, - ); - - if (error) { - throw new GTWError(error, response); - } - - return data; - } - - /** - * Note:- this method overwrites ACL list for data asset so be sure before using it! - * This TypeScript function asynchronously updates the access control list (ACL) for a specific data - * asset identified by its ID. - * @param {number} id - The `id` parameter is a number that represents the identifier of a data asset - * for which the Access Control List (ACL) is being updated. - * @param {ACLRequest[]} aclList - The `aclList` parameter in the `overrideACL` function is an array - * of `ACLRequest` objects. Each `ACLRequest` object likely contains information about access control - * settings for a specific resource or data asset. The function sends this list of ACL requests to - * the server to update the access control - * @returns The `public async overrideACL` function returns a Promise that resolves to an array of - * `PublicACL` objects. - */ - public async overrideACL( - id: number, - aclList: ACLRequest[], - ): Promise { - const { data, error, response } = await this.client.POST( - '/data-assets/{id}/acl', - { - params: { path: { id } }, - body: aclList, - }, - ); - - if (error) { - throw new GTWError(error, response); - } - - return data; - } - - /** - * The function `deleteACL` asynchronously deletes ACL entries associated with a specific ID using a - * DELETE request. - * @param {number} id - The `id` parameter in the `deleteACL` function is a number that represents - * the identifier of the data asset for which the Access Control List (ACL) is being deleted. - * @param {ACLRequest[]} aclList - The `aclList` parameter in the `deleteACL` function is an array of - * `ACLRequest` objects. These objects likely contain information about access control permissions - * for the specified data asset identified by the `id` parameter. The function uses this list to - * update or delete the access control list associated with - * @returns The `deleteACL` function is returning the `data` object after making a DELETE request to - * the specified endpoint with the provided ACL list. - */ - public async deleteACL(id: number, aclList: ACLRequest[]) { - const { data, error, response } = await this.client.PATCH( - '/data-assets/{id}/acl/delete', - { - params: { path: { id } }, - body: aclList, - }, - ); - - if (error) { - throw new GTWError(error, response); - } - - return data.message!; - } - // todo: check for structured and check if data asset not found /** - * This function downloads a data asset file by its ID and returns the file as a Blob along with its - * filename. - * @param {number} id - The `id` parameter is a number that represents the unique identifier of the - * data asset that you want to download. - * @returns The `downloadDataAsset` function returns a Promise that resolves to an object with two - * properties: `file` which is a Blob containing the downloaded data asset file, and `fileName` which - * is a string representing the name of the data asset file. + * This TypeScript function downloads a file associated with a given ID and returns the file as a + * Blob along with its filename. + * @param {number} id - The `id` parameter is a number used to identify the specific data asset that + * needs to be downloaded. It is passed to the `download` method to retrieve the file associated with + * that particular ID. + * @returns The `download` function returns a Promise that resolves to an object with two properties: + * `file` which is a Blob containing the downloaded file data, and `fileName` which is a string + * representing the name of the file. */ - public async downloadDataAsset( - id: number, - ): Promise<{ file: Blob; fileName: string }> { - const { name } = await this.getDataAssetById(id); + public async download(id: number): Promise<{ file: Blob; fileName: string }> { + const { name } = await this.getDetail(id); const { data: file, @@ -395,16 +327,16 @@ export class DataAsset { } /** - * The function `shareDataAsset` asynchronously shares a data asset with specified wallet addresses - * and returns a Promise of PublicACL array. - * @param {number} id - The `id` parameter is a number that represents the identifier of the data - * asset that you want to share. + * The `share` function in TypeScript asynchronously shares a data asset with specified wallet + * addresses and returns a Promise of PublicACL array. + * @param {number} id - The `id` parameter is a number that represents the identifier of a data asset + * that you want to share. * @param {string[]} walletAddressList - The `walletAddressList` parameter is an array of strings - * that contains the wallet addresses to which the data asset with the specified `id` will be shared. - * @returns The `shareDataAsset` function returns a Promise that resolves to an array of `PublicACL` + * representing the wallet addresses to which the data asset with the specified `id` will be shared. + * @returns The `share` function is returning a Promise that resolves to an array of `PublicACL` * objects. */ - public async shareDataAsset( + public async share( id: number, walletAddressList: string[], ): Promise { diff --git a/test/acl.test.ts b/test/acl.test.ts new file mode 100644 index 0000000..03b0bbe --- /dev/null +++ b/test/acl.test.ts @@ -0,0 +1,105 @@ +import createClient from 'openapi-fetch'; + +import { ACL } from '../src/modules/data-asset/acl'; +import { ValidationService } from '../src/services/validator-service'; +import { + bodyStub, + errorMessage, + ID, + mockClient, + mockPatch, + mockPost, + paramsStub, + successMessage, +} from './stubs/common.stub'; +import { routes } from '../src/common/routes'; +import { GTWError } from '../src/helpers/custom-error'; +import { aclStub, aclListStub } from './stubs/data-asset.stub'; + +jest.mock('openapi-fetch'); + +let acl: ACL; +let validationService: ValidationService; + +beforeAll(() => { + (createClient as jest.Mock).mockReturnValue(mockClient); + + validationService = new ValidationService(); + acl = new ACL(mockClient, validationService); +}); + +afterAll(() => { + jest.resetAllMocks(); +}); + +describe('ACL TESTS', () => { + it('should update acl', async () => { + mockPatch.mockResolvedValue(successMessage({ data: aclStub() })); + + const aclList = await acl.update(ID, [aclListStub()]); + + expect(aclList).toBeDefined(); + expect(mockPatch).toHaveBeenCalledWith(routes.UpdateACLItemsToDataAsset, { + body: bodyStub({ body: [aclListStub()] }).body, + params: paramsStub({ params: { path: { id: 1 } } }).params, + }); + }); + + it('should throw GTWError for updating acl', async () => { + mockPatch.mockResolvedValue(errorMessage()); + + await expect(acl.update(ID, [aclListStub()])).rejects.toThrow(GTWError); + expect(mockPatch).toHaveBeenCalledWith(routes.UpdateACLItemsToDataAsset, { + body: bodyStub({ body: [aclListStub()] }).body, + params: paramsStub({ params: { path: { id: 1 } } }).params, + }); + }); + + it('should override acl', async () => { + mockPost.mockResolvedValue(successMessage({ data: aclStub() })); + + const aclList = await acl.add(ID, [aclListStub()]); + + expect(aclList).toBeDefined(); + expect(mockPost).toHaveBeenCalledWith(routes.AssignACLItemsToDataAsset, { + body: bodyStub({ body: [aclListStub()] }).body, + params: paramsStub({ params: { path: { id: 1 } } }).params, + }); + }); + + it('should throw GTWError for override acl', async () => { + mockPost.mockResolvedValue(errorMessage()); + + await expect(acl.add(ID, [aclListStub()])).rejects.toThrow(GTWError); + expect(mockPost).toHaveBeenCalledWith(routes.AssignACLItemsToDataAsset, { + body: bodyStub({ body: [aclListStub()] }).body, + params: paramsStub({ params: { path: { id: 1 } } }).params, + }); + }); + + it('should delete acl', async () => { + mockPatch.mockResolvedValue(successMessage()); + + const message = await acl.delete(ID, [aclListStub()]); + + expect(message).toBeDefined(); + expect(mockPatch).toHaveBeenCalledWith(routes.DeleteAssignedRoleByACL, { + params: paramsStub({ + params: { path: { id: 1 } }, + }).params, + body: bodyStub({ body: [aclListStub()] }).body, + }); + }); + + it('should throw GTWError for updating acl', async () => { + mockPatch.mockResolvedValue(errorMessage()); + + await expect(acl.delete(ID, [aclListStub()])).rejects.toThrow(GTWError); + expect(mockPatch).toHaveBeenCalledWith(routes.DeleteAssignedRoleByACL, { + params: paramsStub({ + params: { path: { id: 1 } }, + }).params, + body: bodyStub({ body: [aclListStub()] }).body, + }); + }); +}); diff --git a/test/auth.test.ts b/test/auth.test.ts index 59d88d8..7baf347 100644 --- a/test/auth.test.ts +++ b/test/auth.test.ts @@ -29,7 +29,7 @@ describe('Auth Unit Test', () => { test('should generate sign message', async () => { mockGet.mockResolvedValue(successMessage()); - const message = await auth.generateSignMessage(); + const message = await auth.getMessage(); expect(message).toBeDefined(); expect(mockGet).toHaveBeenCalledWith(routes.GenerateSignMessage); }); @@ -37,7 +37,7 @@ describe('Auth Unit Test', () => { it('should throw GTWError for generate sign message', async () => { mockGet.mockResolvedValue(errorMessage()); - await expect(auth.generateSignMessage()).rejects.toThrow(GTWError); + await expect(auth.getMessage()).rejects.toThrow(GTWError); expect(mockGet).toHaveBeenCalledWith('/auth/message'); expect(mockGet).toHaveBeenCalledWith(routes.GenerateSignMessage); }); @@ -45,7 +45,7 @@ describe('Auth Unit Test', () => { test('should generate refresh token', async () => { mockGet.mockResolvedValue(successMessage({ data: { token: 'test' } })); - const message = await auth.generateRefreshToken(); + const message = await auth.getRefreshToken(); expect(message).toBeDefined(); expect(mockGet).toHaveBeenCalledWith(routes.RefreshToken); @@ -54,7 +54,7 @@ describe('Auth Unit Test', () => { it('should throw GTWError for generate refresh token', async () => { mockGet.mockResolvedValue(errorMessage()); - await expect(auth.generateRefreshToken()).rejects.toThrow(GTWError); + await expect(auth.getRefreshToken()).rejects.toThrow(GTWError); expect(mockGet).toHaveBeenCalledWith(routes.RefreshToken); }); diff --git a/test/data-asset.test.ts b/test/data-asset.test.ts index c48ca27..084d923 100644 --- a/test/data-asset.test.ts +++ b/test/data-asset.test.ts @@ -46,7 +46,7 @@ describe('Data Assets Test', () => { it('should create claim based data asset', async () => { mockPost.mockResolvedValue(successMessage({ data: { id: ID } })); - const pdaId = await dataAsset.createClaimBasedDataAsset({ name: 'test' }); + const pdaId = await dataAsset.createStructured({ name: 'test' }); expect(pdaId).toBeDefined(); expect(mockPost).toHaveBeenCalledWith(routes.CreateANewDataAsset, { @@ -57,9 +57,9 @@ describe('Data Assets Test', () => { it('should throw GTWError for create claim based data asset', async () => { mockPost.mockResolvedValue(errorMessage()); - await expect( - dataAsset.createClaimBasedDataAsset({ name: 'test' }), - ).rejects.toThrow(GTWError); + await expect(dataAsset.createStructured({ name: 'test' })).rejects.toThrow( + GTWError, + ); expect(mockPost).toHaveBeenCalledWith(routes.CreateANewDataAsset, { body: { name: 'test' }, }); @@ -75,7 +75,7 @@ describe('Data Assets Test', () => { name: 'test-file', extension: 'text/plain', }); - const id = await dataAsset.createFileBasedDataAsset(fileName, fileBuffer); + const id = await dataAsset.createNonStructured(fileName, fileBuffer); expect(mockValidateFileName).toHaveBeenCalledWith(fileName); expect(mockPost).toHaveBeenCalledWith('/data-assets', { @@ -93,7 +93,7 @@ describe('Data Assets Test', () => { const fileBuffer = Buffer.from('test content'); await expect( - dataAsset.createFileBasedDataAsset(fileName, fileBuffer), + dataAsset.createNonStructured(fileName, fileBuffer), ).rejects.toThrow(GTWError); expect(mockValidateFileName).toHaveBeenCalledWith(fileName); @@ -110,7 +110,7 @@ describe('Data Assets Test', () => { }), ); - const data = await dataAsset.getDataAssetsCreatedByMe(); + const data = await dataAsset.getCreatedByMe(); expect(data).toBeDefined(); expect(data.data.length).toBeGreaterThan(0); @@ -123,9 +123,7 @@ describe('Data Assets Test', () => { it('should throw GTWError for data assets created by me', async () => { mockGet.mockResolvedValue(errorMessage()); - await expect(dataAsset.getDataAssetsCreatedByMe()).rejects.toThrow( - GTWError, - ); + await expect(dataAsset.getCreatedByMe()).rejects.toThrow(GTWError); expect(mockGet).toHaveBeenCalledWith( routes.GetCreatedDataAssets, @@ -140,7 +138,7 @@ describe('Data Assets Test', () => { }), ); - const data = await dataAsset.getDataAssetsReceivedToMe(); + const data = await dataAsset.getReceivedToMe(); expect(data).toBeDefined(); expect(data.data.length).toBeGreaterThan(0); @@ -153,9 +151,7 @@ describe('Data Assets Test', () => { it('should throw GTWError for data assets received by me', async () => { mockGet.mockResolvedValue(errorMessage()); - await expect(dataAsset.getDataAssetsReceivedToMe()).rejects.toThrow( - GTWError, - ); + await expect(dataAsset.getReceivedToMe()).rejects.toThrow(GTWError); expect(mockGet).toHaveBeenCalledWith( routes.GetReceivedDataAssets, @@ -170,7 +166,7 @@ describe('Data Assets Test', () => { }), ); - const data = await dataAsset.getDataAssetById(ID); + const data = await dataAsset.getDetail(ID); expect(data).toBeDefined(); expect(mockGet).toHaveBeenCalledWith( @@ -182,7 +178,7 @@ describe('Data Assets Test', () => { it('should throw GTWError for get data asset by id', async () => { mockGet.mockResolvedValue(errorMessage()); - await expect(dataAsset.getDataAssetById(ID)).rejects.toThrow(GTWError); + await expect(dataAsset.getDetail(ID)).rejects.toThrow(GTWError); expect(mockGet).toHaveBeenCalledWith( routes.GetDataAssetByID, @@ -195,10 +191,7 @@ describe('Data Assets Test', () => { mockPut.mockResolvedValue( successMessage({ data: { id: ID, name: 'Updated Data Asset' } }), ); - const result = await dataAsset.updateClaimBasedDataAsset( - ID, - claimDataAssetBody, - ); + const result = await dataAsset.updateStructured(ID, claimDataAssetBody); expect(mockPut).toHaveBeenCalledWith('/data-assets/{id}', { params: { path: { id: ID } }, @@ -215,7 +208,7 @@ describe('Data Assets Test', () => { mockPut.mockResolvedValueOnce(errorMessage()); await expect( - dataAsset.updateClaimBasedDataAsset(id, claimDataAssetBody), + dataAsset.updateStructured(id, claimDataAssetBody), ).rejects.toThrow(GTWError); expect(mockPut).toHaveBeenCalledWith('/data-assets/{id}', { @@ -229,7 +222,7 @@ describe('Data Assets Test', () => { const fileName = 'test.txt'; const fileBuffer = Buffer.from('test content'); - const result = await dataAsset.updateFileBasedDataAsset( + const result = await dataAsset.updateNonStructured( id, fileName, fileBuffer, @@ -254,7 +247,7 @@ describe('Data Assets Test', () => { mockPut.mockResolvedValueOnce(errorMessage()); await expect( - dataAsset.updateFileBasedDataAsset(id, fileName, fileBuffer), + dataAsset.updateNonStructured(id, fileName, fileBuffer), ).rejects.toThrow(GTWError); expect(mockValidateFileName).toHaveBeenCalledWith(fileName); @@ -269,7 +262,7 @@ describe('Data Assets Test', () => { it('should delete data asset by id', async () => { mockDelete.mockResolvedValue(successMessage()); - const deleteDataAsset = await dataAsset.deleteDataAsset(ID); + const deleteDataAsset = await dataAsset.delete(ID); expect(deleteDataAsset).toBeDefined(); expect(mockDelete).toHaveBeenCalledWith( @@ -281,93 +274,17 @@ describe('Data Assets Test', () => { it('should throw GTWError for delete data asset by id', async () => { mockDelete.mockResolvedValue(errorMessage()); - await expect(dataAsset.deleteDataAsset(ID)).rejects.toThrow(GTWError); + await expect(dataAsset.delete(ID)).rejects.toThrow(GTWError); expect(mockDelete).toHaveBeenCalledWith( routes.DeleteDataAssetByID, paramsStub({ params: { path: { id: 1 } } }), ); }); - it('should update acl', async () => { - mockPatch.mockResolvedValue(successMessage({ data: aclStub() })); - - const aclList = await dataAsset.updateACL(ID, [aclListStub()]); - - expect(aclList).toBeDefined(); - expect(mockPatch).toHaveBeenCalledWith(routes.UpdateACLItemsToDataAsset, { - body: bodyStub({ body: [aclListStub()] }).body, - params: paramsStub({ params: { path: { id: 1 } } }).params, - }); - }); - - it('should throw GTWError for updating acl', async () => { - mockPatch.mockResolvedValue(errorMessage()); - - await expect(dataAsset.updateACL(ID, [aclListStub()])).rejects.toThrow( - GTWError, - ); - expect(mockPatch).toHaveBeenCalledWith(routes.UpdateACLItemsToDataAsset, { - body: bodyStub({ body: [aclListStub()] }).body, - params: paramsStub({ params: { path: { id: 1 } } }).params, - }); - }); - - it('should override acl', async () => { - mockPost.mockResolvedValue(successMessage({ data: aclStub() })); - - const aclList = await dataAsset.overrideACL(ID, [aclListStub()]); - - expect(aclList).toBeDefined(); - expect(mockPost).toHaveBeenCalledWith(routes.AssignACLItemsToDataAsset, { - body: bodyStub({ body: [aclListStub()] }).body, - params: paramsStub({ params: { path: { id: 1 } } }).params, - }); - }); - - it('should throw GTWError for override acl', async () => { - mockPost.mockResolvedValue(errorMessage()); - - await expect(dataAsset.overrideACL(ID, [aclListStub()])).rejects.toThrow( - GTWError, - ); - expect(mockPost).toHaveBeenCalledWith(routes.AssignACLItemsToDataAsset, { - body: bodyStub({ body: [aclListStub()] }).body, - params: paramsStub({ params: { path: { id: 1 } } }).params, - }); - }); - - it('should delete acl', async () => { - mockPatch.mockResolvedValue(successMessage()); - - const message = await dataAsset.deleteACL(ID, [aclListStub()]); - - expect(message).toBeDefined(); - expect(mockPatch).toHaveBeenCalledWith(routes.DeleteAssignedRoleByACL, { - params: paramsStub({ - params: { path: { id: 1 } }, - }).params, - body: bodyStub({ body: [aclListStub()] }).body, - }); - }); - - it('should throw GTWError for updating acl', async () => { - mockPatch.mockResolvedValue(errorMessage()); - - await expect(dataAsset.deleteACL(ID, [aclListStub()])).rejects.toThrow( - GTWError, - ); - expect(mockPatch).toHaveBeenCalledWith(routes.DeleteAssignedRoleByACL, { - params: paramsStub({ - params: { path: { id: 1 } }, - }).params, - body: bodyStub({ body: [aclListStub()] }).body, - }); - }); - it('should share data asset', async () => { mockPost.mockResolvedValue(successMessage({ data: aclStub() })); - const aclList = await dataAsset.shareDataAsset(ID, ['']); + const aclList = await dataAsset.share(ID, ['']); expect(aclList).toBeDefined(); expect(mockPost).toHaveBeenCalled(); @@ -376,7 +293,7 @@ describe('Data Assets Test', () => { it('should throw GTWError for sharing data asset', async () => { mockPost.mockResolvedValue(errorMessage()); - await expect(dataAsset.shareDataAsset(ID, [''])).rejects.toThrow(GTWError); + await expect(dataAsset.share(ID, [''])).rejects.toThrow(GTWError); expect(mockPost).toHaveBeenCalled(); }); @@ -385,7 +302,7 @@ describe('Data Assets Test', () => { successMessage({ data: { fileName: 'test.txt', file: blobStub } }), ); - const file = await dataAsset.downloadDataAsset(ID); + const file = await dataAsset.download(ID); expect(file).toBeDefined(); expect(mockGet).toHaveBeenCalled(); @@ -394,7 +311,7 @@ describe('Data Assets Test', () => { it('should throw GTWError for downloading file based data asset', async () => { mockGet.mockResolvedValue(errorMessage()); - await expect(dataAsset.downloadDataAsset(ID)).rejects.toThrow(GTWError); + await expect(dataAsset.download(ID)).rejects.toThrow(GTWError); expect(mockGet).toHaveBeenCalled(); }); }); diff --git a/test/helper.test.ts b/test/helper.test.ts index 24f1297..93da189 100644 --- a/test/helper.test.ts +++ b/test/helper.test.ts @@ -52,12 +52,16 @@ describe('JWT Token Handling', () => { describe('Utils', () => { describe('parameterChecker', () => { it('should return dev URL for dev environment', () => { - expect(parameterChecker('dev')).toBe('https://dev.api.gateway.tech'); + expect(parameterChecker('dev', '', 'some-random-hex-key')).toStrictEqual({ + mode: 'privateKey', + url: 'https://dev.api.gateway.tech', + value: 'some-random-hex-key', + }); }); it('should throw error for invalid environment', () => { expect(() => parameterChecker('production' as any)).toThrow( - 'No valid url found!. Use sandbox or production url', + 'Need jwt or private key', ); }); @@ -109,7 +113,7 @@ describe('Utils', () => { it('should add authorization header for protected routes', async () => { const mockAuthInstance = { - generateSignMessage: jest.fn().mockResolvedValue('message'), + getMessage: jest.fn().mockResolvedValue('message'), login: jest.fn().mockResolvedValue('jwt_token'), }; (Auth as jest.MockedClass).mockImplementation(