Skip to content

Commit 0305bee

Browse files
committed
feat: update filehasbeendeleted
1 parent c748a8f commit 0305bee

File tree

7 files changed

+164
-1
lines changed

7 files changed

+164
-1
lines changed

docs/useCases.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,30 @@ If restrict is false then enableAccessRequest and termsOfAccess are ignored
15711571
If restrict is true and enableAccessRequest is false then termsOfAccess is required.
15721572
The enableAccessRequest and termsOfAccess are applied to the Draft version of the Dataset and affect all of the restricted files in said Draft version.
15731573

1574+
#### File Has Been Deleted
1575+
1576+
Check if the file has been deleted, return a boolean.
1577+
1578+
##### Example call:
1579+
1580+
```typescript
1581+
import { fileHasBeenDeleted } from '@iqss/dataverse-client-javascript'
1582+
1583+
/* ... */
1584+
1585+
const fileId = 12345
1586+
1587+
await fileHasBeenDeleted.execute(fileId).then((deleted: boolean) => {
1588+
/* ... */
1589+
})
1590+
1591+
/* ... */
1592+
```
1593+
1594+
_See [use case](../src/files/domain/useCases/FileHasBeenDeleted.ts) implementation_.
1595+
1596+
The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers.
1597+
15741598
## Metadata Blocks
15751599

15761600
### Metadata Blocks read use cases

src/files/domain/repositories/IFilesRepository.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,6 @@ export interface IFilesRepository {
8484
categories: string[],
8585
replace?: boolean
8686
): Promise<void>
87+
88+
fileHasBeenDeleted(fileId: number | string): Promise<boolean>
8789
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { IFilesRepository } from '../repositories/IFilesRepository'
2+
import { UseCase } from '../../../core/domain/useCases/UseCase'
3+
4+
export class FileHasBeenDeleted implements UseCase<boolean> {
5+
constructor(private readonly filesRepository: IFilesRepository) {}
6+
7+
/**
8+
* Returns a boolean, indicating whether the file has been deleted or not.
9+
*
10+
* @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
11+
* @returns {Promise<boolean>} - A boolean indicating whether the file has been deleted or not.
12+
*/
13+
async execute(fileId: number | string): Promise<boolean> {
14+
return await this.filesRepository.fileHasBeenDeleted(fileId)
15+
}
16+
}

src/files/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { RestrictFile } from './domain/useCases/RestrictFile'
1717
import { UpdateFileMetadata } from './domain/useCases/UpdateFileMetadata'
1818
import { UpdateFileTabularTags } from './domain/useCases/UpdateFileTabularTags'
1919
import { UpdateFileCategories } from './domain/useCases/UpdateFileCategories'
20+
import { FileHasBeenDeleted } from './domain/useCases/FileHasBeenDeleted'
2021

2122
const filesRepository = new FilesRepository()
2223
const directUploadClient = new DirectUploadClient(filesRepository)
@@ -38,6 +39,7 @@ const restrictFile = new RestrictFile(filesRepository)
3839
const updateFileMetadata = new UpdateFileMetadata(filesRepository)
3940
const updateFileTabularTags = new UpdateFileTabularTags(filesRepository)
4041
const updateFileCategories = new UpdateFileCategories(filesRepository)
42+
const fileHasBeenDeleted = new FileHasBeenDeleted(filesRepository)
4143

4244
export {
4345
getDatasetFiles,
@@ -56,7 +58,8 @@ export {
5658
updateFileMetadata,
5759
updateFileTabularTags,
5860
updateFileCategories,
59-
replaceFile
61+
replaceFile,
62+
fileHasBeenDeleted
6063
}
6164

6265
export { FileModel as File, FileEmbargo, FileChecksum } from './domain/models/FileModel'

src/files/infra/repositories/FilesRepository.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,4 +415,12 @@ export class FilesRepository extends ApiRepository implements IFilesRepository {
415415
throw error
416416
})
417417
}
418+
419+
public async fileHasBeenDeleted(fileId: number | string): Promise<boolean> {
420+
return this.doGet(this.buildApiEndpoint(this.filesResourceName, 'hasBeenDeleted', fileId), true)
421+
.then((response) => response.data.data)
422+
.catch((error) => {
423+
throw error
424+
})
425+
}
418426
}

test/integration/files/FilesRepository.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,83 @@ describe('FilesRepository', () => {
840840
})
841841
})
842842

843+
describe('fileHasBeenDeleted', () => {
844+
let deleFileTestDatasetIds: CreatedDatasetIdentifiers
845+
const testTextFile1Name = 'test-file-1.txt'
846+
let fileId: number
847+
848+
beforeAll(async () => {
849+
try {
850+
deleFileTestDatasetIds = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO)
851+
} catch (error) {
852+
throw new Error('Tests beforeEach(): Error while creating test dataset')
853+
}
854+
await uploadFileViaApi(deleFileTestDatasetIds.numericId, testTextFile1Name).catch(() => {
855+
throw new Error(`Tests beforeEach(): Error while uploading file ${testTextFile1Name}`)
856+
})
857+
858+
const datasetFiles = await sut.getDatasetFiles(
859+
deleFileTestDatasetIds.numericId,
860+
latestDatasetVersionId,
861+
false,
862+
FileOrderCriteria.NAME_AZ
863+
)
864+
865+
fileId = datasetFiles.files[0].id
866+
})
867+
868+
afterAll(async () => {
869+
await deletePublishedDatasetViaApi(deleFileTestDatasetIds.persistentId)
870+
})
871+
872+
test('should return False if a file has not been deleted', async () => {
873+
const hasBeenDeleted = await sut.fileHasBeenDeleted(fileId)
874+
expect(hasBeenDeleted).toBe(false)
875+
})
876+
877+
test('should return error if the dataset is unpublished and the file has been deleted', async () => {
878+
await sut.deleteFile(fileId)
879+
880+
const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`)
881+
882+
await expect(sut.fileHasBeenDeleted(nonExistentFiledId)).rejects.toThrow(expectedError)
883+
})
884+
885+
test('should return True when the dataset is published and the file has not been deleted', async () => {
886+
await uploadFileViaApi(deleFileTestDatasetIds.numericId, testTextFile1Name).catch(() => {
887+
throw new Error(`Tests beforeEach(): Error while uploading file ${testTextFile1Name}`)
888+
})
889+
890+
await publishDatasetViaApi(deleFileTestDatasetIds.numericId).catch(() => {
891+
throw new Error('Error while publishing test Dataset')
892+
})
893+
await waitForNoLocks(deleFileTestDatasetIds.numericId, 10)
894+
895+
const datasetFiles = await sut.getDatasetFiles(
896+
deleFileTestDatasetIds.numericId,
897+
latestDatasetVersionId,
898+
false,
899+
FileOrderCriteria.NAME_AZ
900+
)
901+
902+
fileId = datasetFiles.files[0].id
903+
904+
const hasBeenDeleted = await sut.fileHasBeenDeleted(fileId)
905+
expect(hasBeenDeleted).toBe(false)
906+
907+
await sut.deleteFile(fileId)
908+
909+
const actual = await sut.fileHasBeenDeleted(fileId)
910+
expect(actual).toBe(true)
911+
})
912+
913+
test('should return error when file does not exist', async () => {
914+
const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`)
915+
916+
await expect(sut.fileHasBeenDeleted(nonExistentFiledId)).rejects.toThrow(expectedError)
917+
})
918+
})
919+
843920
describe('restrictFile', () => {
844921
let restrictFileDatasetIds: CreatedDatasetIdentifiers
845922
const testTextFile1Name = 'test-file-1.txt'
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { IFilesRepository } from '../../../src/files/domain/repositories/IFilesRepository'
2+
import { FileHasBeenDeleted } from '../../../src/files/domain/useCases/FileHasBeenDeleted'
3+
import { ReadError } from '../../../src'
4+
5+
describe('execute', () => {
6+
test('should return true when file has been deleted', async () => {
7+
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
8+
filesRepositoryStub.fileHasBeenDeleted = jest.fn().mockResolvedValue(true)
9+
const sut = new FileHasBeenDeleted(filesRepositoryStub)
10+
11+
const result = await sut.execute(1)
12+
13+
expect(result).toBe(true)
14+
})
15+
16+
test('should return false when file has not been deleted', async () => {
17+
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
18+
filesRepositoryStub.fileHasBeenDeleted = jest.fn().mockResolvedValue(false)
19+
const sut = new FileHasBeenDeleted(filesRepositoryStub)
20+
21+
const result = await sut.execute(1)
22+
23+
expect(result).toBe(false)
24+
})
25+
26+
test('should return error result on repository error', async () => {
27+
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
28+
filesRepositoryStub.fileHasBeenDeleted = jest.fn().mockRejectedValue(new ReadError())
29+
const sut = new FileHasBeenDeleted(filesRepositoryStub)
30+
31+
await expect(sut.execute(1)).rejects.toThrow(ReadError)
32+
})
33+
})

0 commit comments

Comments
 (0)