From aa8d7b20e3ecafb8ca5a762d8464c6af46798575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Tue, 18 Feb 2025 17:07:13 -0300 Subject: [PATCH 01/10] feat: add use case --- .../domain/repositories/IFilesRepository.ts | 2 ++ src/files/domain/useCases/RestrictFile.ts | 17 +++++++++++++++++ src/files/index.ts | 5 ++++- src/files/infra/repositories/FilesRepository.ts | 8 ++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/files/domain/useCases/RestrictFile.ts diff --git a/src/files/domain/repositories/IFilesRepository.ts b/src/files/domain/repositories/IFilesRepository.ts index 8365374e..fa9e9fa1 100644 --- a/src/files/domain/repositories/IFilesRepository.ts +++ b/src/files/domain/repositories/IFilesRepository.ts @@ -61,4 +61,6 @@ export interface IFilesRepository { ): Promise deleteFile(fileId: number | string): Promise + + restrictFile(fileId: number | string): Promise } diff --git a/src/files/domain/useCases/RestrictFile.ts b/src/files/domain/useCases/RestrictFile.ts new file mode 100644 index 00000000..169891c0 --- /dev/null +++ b/src/files/domain/useCases/RestrictFile.ts @@ -0,0 +1,17 @@ +import { IFilesRepository } from '../repositories/IFilesRepository' +import { UseCase } from '../../../core/domain/useCases/UseCase' + +export class RestrictFile implements UseCase { + constructor(private readonly filesRepository: IFilesRepository) {} + + /** + * Restrict or unrestrict an existing file. + * More detailed information about the file restriction behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#restrict-files + * + * @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @returns {Promise} -This method does not return anything upon successful completion. + */ + async execute(fileId: number | string): Promise { + return await this.filesRepository.restrictFile(fileId) + } +} diff --git a/src/files/index.ts b/src/files/index.ts index 0d847852..3809b4cf 100644 --- a/src/files/index.ts +++ b/src/files/index.ts @@ -12,6 +12,7 @@ import { UploadFile } from './domain/useCases/UploadFile' import { DirectUploadClient } from './infra/clients/DirectUploadClient' import { AddUploadedFilesToDataset } from './domain/useCases/AddUploadedFilesToDataset' import { DeleteFile } from './domain/useCases/DeleteFile' +import { RestrictFile } from './domain/useCases/RestrictFile' const filesRepository = new FilesRepository() const directUploadClient = new DirectUploadClient(filesRepository) @@ -28,6 +29,7 @@ const getFileCitation = new GetFileCitation(filesRepository) const uploadFile = new UploadFile(directUploadClient) const addUploadedFilesToDataset = new AddUploadedFilesToDataset(filesRepository) const deleteFile = new DeleteFile(filesRepository) +const restrictFile = new RestrictFile(filesRepository) export { getDatasetFiles, @@ -41,7 +43,8 @@ export { getFileCitation, uploadFile, addUploadedFilesToDataset, - deleteFile + deleteFile, + restrictFile } export { FileModel as File, FileEmbargo, FileChecksum } from './domain/models/FileModel' diff --git a/src/files/infra/repositories/FilesRepository.ts b/src/files/infra/repositories/FilesRepository.ts index 9aebe720..33273f92 100644 --- a/src/files/infra/repositories/FilesRepository.ts +++ b/src/files/infra/repositories/FilesRepository.ts @@ -301,4 +301,12 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { throw error }) } + + public async restrictFile(fileId: number | string): Promise { + return this.doPut(this.buildApiEndpoint(this.filesResourceName, 'restrict', fileId), {}) + .then(() => undefined) + .catch((error) => { + throw error + }) + } } From 8faf1bacee0cf3f82aef033059ce57e98daf1a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Tue, 18 Feb 2025 17:07:26 -0300 Subject: [PATCH 02/10] docs: add use case docs --- docs/useCases.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/useCases.md b/docs/useCases.md index fa726a78..b22d1a1e 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -51,6 +51,7 @@ The different use cases currently available in the package are classified below, - [Files write use cases](#files-write-use-cases) - [File Uploading Use Cases](#file-uploading-use-cases) - [Delete a File](#delete-a-file) + - [Restrict or Unrestrict a File](#restrict-or-unrestrict-a-file) - [Metadata Blocks](#metadata-blocks) - [Metadata Blocks read use cases](#metadata-blocks-read-use-cases) - [Get All Facetable Metadata Fields](#get-all-facetable-metadata-fields) @@ -1264,6 +1265,28 @@ Note that the behavior of deleting files depends on if the dataset has ever been - If the dataset has published, the file is deleted from the draft (and future published versions). - If the dataset has published, the deleted file can still be downloaded because it was part of a published version. +#### Restrict or Unrestrict a File + +Restrict or unrestrict an existing file. + +##### Example call: + +```typescript +import { restrictFile } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const fileId = 12345 + +restrictFile.execute(fileId) + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/RestrictFile.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + ## Metadata Blocks ### Metadata Blocks read use cases From 70c04691219cea3d51fb9bf2587d4530790e5d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Tue, 18 Feb 2025 18:59:45 -0300 Subject: [PATCH 03/10] test: add unit --- test/unit/files/RestrictFile.test.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/unit/files/RestrictFile.test.ts diff --git a/test/unit/files/RestrictFile.test.ts b/test/unit/files/RestrictFile.test.ts new file mode 100644 index 00000000..15e054a3 --- /dev/null +++ b/test/unit/files/RestrictFile.test.ts @@ -0,0 +1,25 @@ +import { WriteError } from '../../../src' +import { IFilesRepository } from '../../../src/files/domain/repositories/IFilesRepository' +import { RestrictFile } from '../../../src/files/domain/useCases/RestrictFile' + +describe('execute', () => { + test('should return undefined when repository call is successful', async () => { + const filesRepositoryStub: IFilesRepository = {} as IFilesRepository + filesRepositoryStub.restrictFile = jest.fn().mockResolvedValue(undefined) + + const sut = new RestrictFile(filesRepositoryStub) + + const actual = await sut.execute(1) + + expect(actual).toEqual(undefined) + }) + + test('should return error result on repository error', async () => { + const filesRepositoryStub: IFilesRepository = {} as IFilesRepository + filesRepositoryStub.restrictFile = jest.fn().mockRejectedValue(new WriteError()) + + const sut = new RestrictFile(filesRepositoryStub) + + await expect(sut.execute(1)).rejects.toThrow(WriteError) + }) +}) From 48b9b6d89edb98c52a37ae78ef57dc1ad393767d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 19 Feb 2025 10:15:20 -0300 Subject: [PATCH 04/10] fix: add boolean parameter to restrict or unrestrict the file --- docs/useCases.md | 2 +- src/files/domain/repositories/IFilesRepository.ts | 2 +- src/files/domain/useCases/RestrictFile.ts | 5 +++-- src/files/infra/repositories/FilesRepository.ts | 7 +++++-- test/unit/files/RestrictFile.test.ts | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/useCases.md b/docs/useCases.md index b22d1a1e..6a5be49d 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -1278,7 +1278,7 @@ import { restrictFile } from '@iqss/dataverse-client-javascript' const fileId = 12345 -restrictFile.execute(fileId) +restrictFile.execute(fileId, true) /* ... */ ``` diff --git a/src/files/domain/repositories/IFilesRepository.ts b/src/files/domain/repositories/IFilesRepository.ts index fa9e9fa1..775cf18a 100644 --- a/src/files/domain/repositories/IFilesRepository.ts +++ b/src/files/domain/repositories/IFilesRepository.ts @@ -62,5 +62,5 @@ export interface IFilesRepository { deleteFile(fileId: number | string): Promise - restrictFile(fileId: number | string): Promise + restrictFile(fileId: number | string, restrict: boolean): Promise } diff --git a/src/files/domain/useCases/RestrictFile.ts b/src/files/domain/useCases/RestrictFile.ts index 169891c0..c01d66b7 100644 --- a/src/files/domain/useCases/RestrictFile.ts +++ b/src/files/domain/useCases/RestrictFile.ts @@ -9,9 +9,10 @@ export class RestrictFile implements UseCase { * More detailed information about the file restriction behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#restrict-files * * @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {boolean} [restrict] - A boolean value that indicates whether the file should be restricted or unrestricted. * @returns {Promise} -This method does not return anything upon successful completion. */ - async execute(fileId: number | string): Promise { - return await this.filesRepository.restrictFile(fileId) + async execute(fileId: number | string, restrict: boolean): Promise { + return await this.filesRepository.restrictFile(fileId, restrict) } } diff --git a/src/files/infra/repositories/FilesRepository.ts b/src/files/infra/repositories/FilesRepository.ts index 33273f92..99045bfc 100644 --- a/src/files/infra/repositories/FilesRepository.ts +++ b/src/files/infra/repositories/FilesRepository.ts @@ -302,8 +302,11 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { }) } - public async restrictFile(fileId: number | string): Promise { - return this.doPut(this.buildApiEndpoint(this.filesResourceName, 'restrict', fileId), {}) + public async restrictFile(fileId: number | string, restrict: boolean): Promise { + return this.doPut( + this.buildApiEndpoint(this.filesResourceName, 'restrict', fileId), + restrict ? 'true' : 'false' + ) .then(() => undefined) .catch((error) => { throw error diff --git a/test/unit/files/RestrictFile.test.ts b/test/unit/files/RestrictFile.test.ts index 15e054a3..b240809e 100644 --- a/test/unit/files/RestrictFile.test.ts +++ b/test/unit/files/RestrictFile.test.ts @@ -9,7 +9,7 @@ describe('execute', () => { const sut = new RestrictFile(filesRepositoryStub) - const actual = await sut.execute(1) + const actual = await sut.execute(1, true) expect(actual).toEqual(undefined) }) @@ -20,6 +20,6 @@ describe('execute', () => { const sut = new RestrictFile(filesRepositoryStub) - await expect(sut.execute(1)).rejects.toThrow(WriteError) + await expect(sut.execute(1, true)).rejects.toThrow(WriteError) }) }) From d8a28a3651d47eb42b0ca63d18b06b270b966206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 19 Feb 2025 15:39:03 -0300 Subject: [PATCH 05/10] refactor: only stringify objects types --- src/core/infra/repositories/ApiRepository.ts | 18 +++++++++++++----- test/unit/auth/AuthRepository.test.ts | 6 +++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/core/infra/repositories/ApiRepository.ts b/src/core/infra/repositories/ApiRepository.ts index 8ac423db..8b5496f9 100644 --- a/src/core/infra/repositories/ApiRepository.ts +++ b/src/core/infra/repositories/ApiRepository.ts @@ -20,7 +20,7 @@ export abstract class ApiRepository { public async doPost( apiEndpoint: string, - data: string | object, + data: string | object | boolean, queryParams: object = {}, contentType: string = ApiConstants.CONTENT_TYPE_APPLICATION_JSON ): Promise { @@ -29,7 +29,7 @@ export abstract class ApiRepository { public async doPut( apiEndpoint: string, - data: string | object, + data: string | object | boolean, queryParams: object = {}, contentType: string = ApiConstants.CONTENT_TYPE_APPLICATION_JSON ): Promise { @@ -70,12 +70,20 @@ export abstract class ApiRepository { private async doRequest( method: 'post' | 'put', apiEndpoint: string, - data: string | object, + data: string | object | boolean, queryParams: object = {}, contentType: string = ApiConstants.CONTENT_TYPE_APPLICATION_JSON ): Promise { - const requestData = - contentType == ApiConstants.CONTENT_TYPE_APPLICATION_JSON ? JSON.stringify(data) : data + let requestData = data + + if (contentType === ApiConstants.CONTENT_TYPE_APPLICATION_JSON) { + if (typeof data === 'object') { + requestData = JSON.stringify(data) + } else if (typeof data === 'boolean') { + requestData = data.toString() + } + } + const requestUrl = buildRequestUrl(apiEndpoint) const requestConfig = buildRequestConfig(true, queryParams, contentType) diff --git a/test/unit/auth/AuthRepository.test.ts b/test/unit/auth/AuthRepository.test.ts index e78aa9fc..97da3367 100644 --- a/test/unit/auth/AuthRepository.test.ts +++ b/test/unit/auth/AuthRepository.test.ts @@ -35,7 +35,7 @@ describe('logout', () => { expect(axios.post).toHaveBeenCalledWith( expectedApiEndpoint, - JSON.stringify(''), + '', TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_API_KEY ) @@ -46,7 +46,7 @@ describe('logout', () => { expect(axios.post).toHaveBeenCalledWith( expectedApiEndpoint, - JSON.stringify(''), + '', TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_SESSION_COOKIE ) }) @@ -59,7 +59,7 @@ describe('logout', () => { expect(axios.post).toHaveBeenCalledWith( `${TestConstants.TEST_API_URL}/logout`, - JSON.stringify(''), + '', TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_API_KEY ) expect(error).toBeInstanceOf(Error) From 42607cc2bf9198b5f72d95bffa5d5cb3d900277a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 19 Feb 2025 15:39:39 -0300 Subject: [PATCH 06/10] test: add integration cases --- .../infra/repositories/FilesRepository.ts | 5 +- .../integration/files/FilesRepository.test.ts | 135 ++++++++++++++++++ 2 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/files/infra/repositories/FilesRepository.ts b/src/files/infra/repositories/FilesRepository.ts index 99045bfc..76e4605b 100644 --- a/src/files/infra/repositories/FilesRepository.ts +++ b/src/files/infra/repositories/FilesRepository.ts @@ -303,10 +303,7 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { } public async restrictFile(fileId: number | string, restrict: boolean): Promise { - return this.doPut( - this.buildApiEndpoint(this.filesResourceName, 'restrict', fileId), - restrict ? 'true' : 'false' - ) + return this.doPut(this.buildApiEndpoint(this.filesResourceName, 'restrict', fileId), restrict) .then(() => undefined) .catch((error) => { throw error diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index 7aff8c49..91b5c36a 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -725,4 +725,139 @@ describe('FilesRepository', () => { await expect(sut.deleteFile(nonExistentFiledId)).rejects.toThrow(expectedError) }) }) + + describe('restrictFile', () => { + let restrictFileDatasetIds: CreatedDatasetIdentifiers + const testTextFile1Name = 'test-file-1.txt' + + const setFileToRestricted = async (fileId: number) => { + await sut.restrictFile(fileId, true) + } + + const setFileToUnrestricted = async (fileId: number) => { + await sut.restrictFile(fileId, false) + } + + beforeEach(async () => { + try { + restrictFileDatasetIds = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO) + } catch (error) { + throw new Error('Tests beforeEach(): Error while creating test dataset') + } + await uploadFileViaApi(restrictFileDatasetIds.numericId, testTextFile1Name).catch(() => { + throw new Error(`Tests beforeEach(): Error while uploading file ${testTextFile1Name}`) + }) + + await publishDatasetViaApi(restrictFileDatasetIds.numericId).catch(() => { + throw new Error('Error while publishing test Dataset') + }) + + await waitForNoLocks(restrictFileDatasetIds.numericId, 10) + }) + + afterEach(async () => { + await deletePublishedDatasetViaApi(restrictFileDatasetIds.persistentId) + }) + + test('should successfully restrict a file', async () => { + const datasetFiles = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + expect(datasetFiles.files[0].restricted).toEqual(false) + + await setFileToRestricted(datasetFiles.files[0].id) + + const datasetFilesAfterRestrict = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + expect(datasetFilesAfterRestrict.files[0].restricted).toEqual(true) + + // Unrestrict the file Just in case to avoid conflicts with other tests + await setFileToUnrestricted(datasetFiles.files[0].id) + }) + + test('should successfully unrestrict a file', async () => { + const datasetFiles = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + expect(datasetFiles.files[0].restricted).toEqual(false) + + await setFileToRestricted(datasetFiles.files[0].id) + + const datasetFilesAfterRestrict = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + expect(datasetFilesAfterRestrict.files[0].restricted).toEqual(true) + + await setFileToUnrestricted(datasetFiles.files[0].id) + + const datasetFilesAfterUnrestrict = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + expect(datasetFilesAfterUnrestrict.files[0].restricted).toEqual(false) + }) + + test('should return error when file was already restricted', async () => { + const datasetFiles = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + await setFileToRestricted(datasetFiles.files[0].id) + + const expectedError = new WriteError( + `[400] Problem trying to update restriction status on ${testTextFile1Name}: File ${testTextFile1Name} is already restricted` + ) + + await expect(setFileToRestricted(datasetFiles.files[0].id)).rejects.toThrow(expectedError) + + // Unrestrict the file Just in case to avoid conflicts with other tests + await setFileToUnrestricted(datasetFiles.files[0].id) + }) + + test('should return error when files was already unrestricted', async () => { + const datasetFiles = await sut.getDatasetFiles( + restrictFileDatasetIds.numericId, + DatasetNotNumberedVersion.LATEST, + false, + FileOrderCriteria.NAME_AZ + ) + + const expectedError = new WriteError( + `[400] Problem trying to update restriction status on ${testTextFile1Name}: File ${testTextFile1Name} is already unrestricted` + ) + + await expect(setFileToUnrestricted(datasetFiles.files[0].id)).rejects.toThrow(expectedError) + }) + + test('should return error when file does not exist', async () => { + const expectedError = new WriteError( + `[400] Could not find datafile with id ${nonExistentFiledId}` + ) + + await expect(setFileToRestricted(nonExistentFiledId)).rejects.toThrow(expectedError) + }) + }) }) From 464b1f158f9c4fdd095574fa089dc7025595a113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 19 Feb 2025 17:17:56 -0300 Subject: [PATCH 07/10] test: fix due to receiving items in different order --- test/functional/collections/GetCollectionItems.test.ts | 4 ++-- .../collections/CollectionsRepository.test.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/functional/collections/GetCollectionItems.test.ts b/test/functional/collections/GetCollectionItems.test.ts index 15e2814f..96832fef 100644 --- a/test/functional/collections/GetCollectionItems.test.ts +++ b/test/functional/collections/GetCollectionItems.test.ts @@ -61,8 +61,8 @@ describe('execute', () => { try { const actual = await getCollectionItems.execute(testCollectionAlias) - const actualFilePreview = actual.items[0] as FilePreview - const actualDatasetPreview = actual.items[1] as DatasetPreview + const actualFilePreview = actual.items[1] as FilePreview + const actualDatasetPreview = actual.items[0] as DatasetPreview expect(actualFilePreview.name).toBe('test-file-1.txt') expect(actualDatasetPreview.title).toBe('Dataset created using the createDataset use case') diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index b8f43967..3fb13607 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -339,8 +339,8 @@ describe('CollectionsRepository', () => { await new Promise((resolve) => setTimeout(resolve, 5000)) let actual = await sut.getCollectionItems(testCollectionAlias) - const actualFilePreview = actual.items[0] as FilePreview - const actualDatasetPreview = actual.items[1] as DatasetPreview + const actualFilePreview = actual.items[1] as FilePreview + const actualDatasetPreview = actual.items[0] as DatasetPreview const actualCollectionPreview = actual.items[2] as CollectionPreview const expectedFileMd5 = '68b22040025784da775f55cfcb6dee2e' @@ -473,7 +473,7 @@ describe('CollectionsRepository', () => { // Test limit and offset actual = await sut.getCollectionItems(testCollectionAlias, 1, 1) - expect((actual.items[0] as DatasetPreview).persistentId).toBe(testDatasetIds.persistentId) + expect((actual.items[0] as FilePreview).name).toBe(expectedFileName) expect(actual.items.length).toBe(1) expect(actual.totalItemCount).toBe(3) @@ -683,8 +683,8 @@ describe('CollectionsRepository', () => { ) expect(actual.items.length).toBe(3) expect(actual.totalItemCount).toBe(3) - expect((actual.items[0] as FilePreview).type).toBe(CollectionItemType.FILE) - expect((actual.items[1] as DatasetPreview).type).toBe(CollectionItemType.DATASET) + expect((actual.items[0] as DatasetPreview).type).toBe(CollectionItemType.DATASET) + expect((actual.items[1] as FilePreview).type).toBe(CollectionItemType.FILE) expect((actual.items[2] as CollectionPreview).type).toBe(CollectionItemType.COLLECTION) expect(actual.countPerObjectType.dataverses).toBe(1) expect(actual.countPerObjectType.datasets).toBe(1) From f28381590f71bf4934a9c937b87cd8fea4de9ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 19 Feb 2025 17:39:06 -0300 Subject: [PATCH 08/10] test: add functional --- test/functional/files/RestrictFile.test.ts | 108 +++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 test/functional/files/RestrictFile.test.ts diff --git a/test/functional/files/RestrictFile.test.ts b/test/functional/files/RestrictFile.test.ts new file mode 100644 index 00000000..39cd7d52 --- /dev/null +++ b/test/functional/files/RestrictFile.test.ts @@ -0,0 +1,108 @@ +import { + ApiConfig, + createDataset, + CreatedDatasetIdentifiers, + restrictFile, + getDatasetFiles, + WriteError +} from '../../../src' +import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' +import { + createCollectionViaApi, + deleteCollectionViaApi +} from '../../testHelpers/collections/collectionHelper' +import { deleteUnpublishedDatasetViaApi } from '../../testHelpers/datasets/datasetHelper' +import { uploadFileViaApi } from '../../testHelpers/files/filesHelper' +import { TestConstants } from '../../testHelpers/TestConstants' + +describe('execute', () => { + const testCollectionAlias = 'restrictFileFunctionalTest' + let testDatasetIds: CreatedDatasetIdentifiers + const testTextFile1Name = 'test-file-1.txt' + + beforeAll(async () => { + ApiConfig.init( + TestConstants.TEST_API_URL, + DataverseApiAuthMechanism.API_KEY, + process.env.TEST_API_KEY + ) + await createCollectionViaApi(testCollectionAlias) + + try { + testDatasetIds = await createDataset.execute( + TestConstants.TEST_NEW_DATASET_DTO, + testCollectionAlias + ) + } catch (error) { + throw new Error('Tests beforeAll(): Error while creating test dataset') + } + await uploadFileViaApi(testDatasetIds.numericId, testTextFile1Name).catch(() => { + throw new Error(`Tests beforeAll(): Error while uploading file ${testTextFile1Name}`) + }) + }) + + afterAll(async () => { + try { + await deleteUnpublishedDatasetViaApi(testDatasetIds.numericId) + } catch (error) { + throw new Error('Tests afterAll(): Error while deleting test dataset') + } + try { + await deleteCollectionViaApi(testCollectionAlias) + } catch (error) { + throw new Error('Tests afterAll(): Error while deleting test collection') + } + }) + + test('should successfully restrict a file', async () => { + try { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + + await restrictFile.execute(datasetFiles.files[0].id, true) + } catch (error) { + throw new Error('File should be deleted') + } finally { + const datasetFilesAfterRestriction = await getDatasetFiles.execute(testDatasetIds.numericId) + + expect(datasetFilesAfterRestriction.files[0].restricted).toEqual(true) + + // Unrestrict the file for the next test + await restrictFile.execute(datasetFilesAfterRestriction.files[0].id, false) + } + }) + + test('should succesfully unrestrict a file', async () => { + try { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + + await restrictFile.execute(datasetFiles.files[0].id, true) + + await restrictFile.execute(datasetFiles.files[0].id, false) + } catch (error) { + throw new Error('File should be deleted') + } finally { + const datasetFilesAfterRestriction = await getDatasetFiles.execute(testDatasetIds.numericId) + + expect(datasetFilesAfterRestriction.files[0].restricted).toEqual(false) + } + }) + + test('should throw an error when the file id does not exist', async () => { + expect.assertions(2) + let writeError: WriteError | undefined = undefined + const nonExistentFileId = 5 + + try { + await restrictFile.execute(nonExistentFileId, true) + throw new Error('Use case should throw an error') + } catch (error) { + writeError = error as WriteError + } finally { + expect(writeError).toBeInstanceOf(WriteError) + + expect(writeError?.message).toEqual( + `There was an error when writing the resource. Reason was: [400] Could not find datafile with id ${nonExistentFileId}` + ) + } + }) +}) From 3b3f380c7385a33dc316713a256375eabd2922fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Mon, 24 Feb 2025 09:01:30 -0300 Subject: [PATCH 09/10] fix: stringify same as toString in this case --- src/core/infra/repositories/ApiRepository.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/infra/repositories/ApiRepository.ts b/src/core/infra/repositories/ApiRepository.ts index 8b5496f9..7a70c17c 100644 --- a/src/core/infra/repositories/ApiRepository.ts +++ b/src/core/infra/repositories/ApiRepository.ts @@ -77,10 +77,8 @@ export abstract class ApiRepository { let requestData = data if (contentType === ApiConstants.CONTENT_TYPE_APPLICATION_JSON) { - if (typeof data === 'object') { + if (typeof data === 'object' || typeof data === 'boolean') { requestData = JSON.stringify(data) - } else if (typeof data === 'boolean') { - requestData = data.toString() } } From 8e979e12932c637471f24983985627e211d681ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Mon, 24 Feb 2025 09:01:48 -0300 Subject: [PATCH 10/10] fix: remove unneeded publish --- test/integration/files/FilesRepository.test.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index 91b5c36a..12ee137d 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -747,16 +747,10 @@ describe('FilesRepository', () => { await uploadFileViaApi(restrictFileDatasetIds.numericId, testTextFile1Name).catch(() => { throw new Error(`Tests beforeEach(): Error while uploading file ${testTextFile1Name}`) }) - - await publishDatasetViaApi(restrictFileDatasetIds.numericId).catch(() => { - throw new Error('Error while publishing test Dataset') - }) - - await waitForNoLocks(restrictFileDatasetIds.numericId, 10) }) afterEach(async () => { - await deletePublishedDatasetViaApi(restrictFileDatasetIds.persistentId) + await deleteUnpublishedDatasetViaApi(restrictFileDatasetIds.numericId) }) test('should successfully restrict a file', async () => {