diff --git a/docs/useCases.md b/docs/useCases.md index 44b25e02..773c9122 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -37,6 +37,7 @@ The different use cases currently available in the package are classified below, - [List All Datasets](#list-all-datasets) - [Get Dataset Versions Summaries](#get-dataset-versions-summaries) - [Get Dataset Linked Collections](#get-dataset-linked-collections) + - [Get Dataset Available Categories](#get-dataset-available-categories) - [Datasets write use cases](#datasets-write-use-cases) - [Create a Dataset](#create-a-dataset) - [Update a Dataset](#update-a-dataset) @@ -64,6 +65,8 @@ The different use cases currently available in the package are classified below, - [Replace a File](#replace-a-file) - [Restrict or Unrestrict a File](#restrict-or-unrestrict-a-file) - [Update File Metadata](#update-file-metadata) + - [Update File Categories](#update-file-categories) + - [Update File Tabular Tags](#update-file-tabular-tags) - [Metadata Blocks](#metadata-blocks) - [Metadata Blocks read use cases](#metadata-blocks-read-use-cases) - [Get All Facetable Metadata Fields](#get-all-facetable-metadata-fields) @@ -1080,6 +1083,28 @@ The `includeMDC` parameter is optional. - If MDC isn't enabled, the download count will return a total count, without `MDCStartDate`. - If MDC is enabled but the `includeMDC` is false, the count will be limited to the time before `MDCStartDate` +#### Get Dataset Available Categories + +Returns a list of available file categories that may be applied to the files of a given dataset. + +###### Example call: + +```typescript +import { getDatasetAvailableCategories } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const datasetId = 1 + +getDatasetAvailableCategories.execute(datasetId).then((categories: String[]) => { + /* ... */ +}) +``` + +_See [use case](../src/datasets/domain/useCases/GetDatasetAvailableCategories.ts) implementation_. + +The `datasetId` parameter is a number for numeric identifiers or string for persistent identifiers. + ## Files ### Files read use cases diff --git a/src/datasets/domain/repositories/IDatasetsRepository.ts b/src/datasets/domain/repositories/IDatasetsRepository.ts index 83390444..1b33eb14 100644 --- a/src/datasets/domain/repositories/IDatasetsRepository.ts +++ b/src/datasets/domain/repositories/IDatasetsRepository.ts @@ -67,6 +67,7 @@ export interface IDatasetsRepository { linkDataset(datasetId: number, collectionAlias: string): Promise unlinkDataset(datasetId: number, collectionAlias: string): Promise getDatasetLinkedCollections(datasetId: number | string): Promise + getDatasetAvailableCategories(datasetId: number | string): Promise getDatasetCitationInOtherFormats( datasetId: number | string, datasetVersionId: string, diff --git a/src/datasets/domain/useCases/GetDatasetAvailableCategories.ts b/src/datasets/domain/useCases/GetDatasetAvailableCategories.ts new file mode 100644 index 00000000..e51544d6 --- /dev/null +++ b/src/datasets/domain/useCases/GetDatasetAvailableCategories.ts @@ -0,0 +1,20 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { IDatasetsRepository } from '../repositories/IDatasetsRepository' + +export class GetDatasetAvailableCategories implements UseCase { + private readonly datasetsRepository: IDatasetsRepository + + constructor(datasetsRepository: IDatasetsRepository) { + this.datasetsRepository = datasetsRepository + } + + /** + * Retrieves the available file categories for a dataset. + * + * @param {number | string} [datasetId] - Persistent dataset identifier + * @returns {Promise} - List of available file categories + */ + async execute(datasetId: number | string): Promise { + return this.datasetsRepository.getDatasetAvailableCategories(datasetId) + } +} diff --git a/src/datasets/index.ts b/src/datasets/index.ts index 51e7a844..36b8c6b3 100644 --- a/src/datasets/index.ts +++ b/src/datasets/index.ts @@ -23,6 +23,7 @@ import { DeleteDatasetDraft } from './domain/useCases/DeleteDatasetDraft' import { LinkDataset } from './domain/useCases/LinkDataset' import { UnlinkDataset } from './domain/useCases/UnlinkDataset' import { GetDatasetLinkedCollections } from './domain/useCases/GetDatasetLinkedCollections' +import { GetDatasetAvailableCategories } from './domain/useCases/GetDatasetAvailableCategories' import { GetDatasetCitationInOtherFormats } from './domain/useCases/GetDatasetCitationInOtherFormats' const datasetsRepository = new DatasetsRepository() @@ -61,6 +62,7 @@ const deleteDatasetDraft = new DeleteDatasetDraft(datasetsRepository) const linkDataset = new LinkDataset(datasetsRepository) const unlinkDataset = new UnlinkDataset(datasetsRepository) const getDatasetLinkedCollections = new GetDatasetLinkedCollections(datasetsRepository) +const getDatasetAvailableCategories = new GetDatasetAvailableCategories(datasetsRepository) const getDatasetCitationInOtherFormats = new GetDatasetCitationInOtherFormats(datasetsRepository) export { @@ -83,6 +85,7 @@ export { linkDataset, unlinkDataset, getDatasetLinkedCollections, + getDatasetAvailableCategories, getDatasetCitationInOtherFormats } export { DatasetNotNumberedVersion } from './domain/models/DatasetNotNumberedVersion' diff --git a/src/datasets/infra/repositories/DatasetsRepository.ts b/src/datasets/infra/repositories/DatasetsRepository.ts index b3b0b91e..2040f763 100644 --- a/src/datasets/infra/repositories/DatasetsRepository.ts +++ b/src/datasets/infra/repositories/DatasetsRepository.ts @@ -346,4 +346,15 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi throw error }) } + + public async getDatasetAvailableCategories(datasetId: number | string): Promise { + return this.doGet( + this.buildApiEndpoint(this.datasetsResourceName, 'availableFileCategories', datasetId), + true + ) + .then((response) => response.data.data as string[]) + .catch((error) => { + throw error + }) + } } diff --git a/src/files/domain/useCases/UpdateFileCategories.ts b/src/files/domain/useCases/UpdateFileCategories.ts index ea568073..fc2e496d 100644 --- a/src/files/domain/useCases/UpdateFileCategories.ts +++ b/src/files/domain/useCases/UpdateFileCategories.ts @@ -10,7 +10,7 @@ export class UpdateFileCategories implements UseCase { /** * Updates the categories for a particular File. - * More detailed information about updating a file's categories behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#updating-file-metadata + * More detailed information about updating a file's categories behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#updating-file-metadata-categories * * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). * @param {string[]} [categories] - The categories to be added to the file. diff --git a/src/files/domain/useCases/UpdateFileTabularTags.ts b/src/files/domain/useCases/UpdateFileTabularTags.ts index 3b777a97..2f6eb543 100644 --- a/src/files/domain/useCases/UpdateFileTabularTags.ts +++ b/src/files/domain/useCases/UpdateFileTabularTags.ts @@ -10,7 +10,7 @@ export class UpdateFileTabularTags implements UseCase { /** * Updates the tabular tabular Tags for a particular File. - * More detailed information about updating a file's tabularTags behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#updating-file-metadata + * More detailed information about updating a file's tabularTags behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#updating-file-tabular-tags * * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). * @param {string[]} [tabularTags] - The tabular tags to be added to the file. diff --git a/test/functional/datasets/GetDatasetAvailableCategories.test.ts b/test/functional/datasets/GetDatasetAvailableCategories.test.ts new file mode 100644 index 00000000..39c8cef2 --- /dev/null +++ b/test/functional/datasets/GetDatasetAvailableCategories.test.ts @@ -0,0 +1,37 @@ +import { ApiConfig, createDataset, getDatasetAvailableCategories, ReadError } from '../../../src' +import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' +import { deleteUnpublishedDatasetViaApi } from '../../testHelpers/datasets/datasetHelper' +import { CreatedDatasetIdentifiers } from '../../../src/datasets/domain/models/CreatedDatasetIdentifiers' +import { TestConstants } from '../../testHelpers/TestConstants' + +describe('execute', () => { + let createdDatasetIdentifiers: CreatedDatasetIdentifiers + beforeEach(async () => { + ApiConfig.init( + TestConstants.TEST_API_URL, + DataverseApiAuthMechanism.API_KEY, + process.env.TEST_API_KEY + ) + createdDatasetIdentifiers = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO) + }) + + afterEach(async () => { + deleteUnpublishedDatasetViaApi(createdDatasetIdentifiers.numericId) + }) + + it('should return categories array when a dataset has files categories', async () => { + const defaultCategories = ['Code', 'Data', 'Documentation'] + const categoriesList = await getDatasetAvailableCategories.execute( + createdDatasetIdentifiers.numericId + ) + expect(categoriesList.sort()).toEqual(defaultCategories.sort()) + }) + + it('should return error when dataset does not exist', async () => { + const nonExistentDatasetId = 99999 + + await expect( + getDatasetAvailableCategories.execute(nonExistentDatasetId) + ).rejects.toBeInstanceOf(ReadError) + }) +}) diff --git a/test/integration/datasets/DatasetsRepository.test.ts b/test/integration/datasets/DatasetsRepository.test.ts index c0251eb5..7962b465 100644 --- a/test/integration/datasets/DatasetsRepository.test.ts +++ b/test/integration/datasets/DatasetsRepository.test.ts @@ -1609,4 +1609,44 @@ describe('DatasetsRepository', () => { await expect(sut.getDatasetLinkedCollections(nonExistentTestDatasetId)).rejects.toThrow() }) }) + + describe('getDatasetAvailableCategories', () => { + let testDatasetIds: CreatedDatasetIdentifiers + + beforeAll(async () => { + testDatasetIds = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO) + }) + + afterAll(async () => { + await deletePublishedDatasetViaApi(testDatasetIds.persistentId) + }) + + test('should get available categories', async () => { + const fileMetadata = { + description: 'test description', + directoryLabel: 'directoryLabel', + categories: ['category1', 'category2', 'Documentation', 'Data', 'Code'] + } + + await uploadFileViaApi(testDatasetIds.numericId, testTextFile1Name, fileMetadata) + + const actual = await sut.getDatasetAvailableCategories(testDatasetIds.numericId) + expect(actual.sort()).toEqual(fileMetadata.categories.sort()) + }) + + test('should get available categorie if dataset id is persistent id', async () => { + const fileMetadata = { + description: 'test description', + directoryLabel: 'directoryLabel', + categories: ['category1', 'category2', 'Documentation', 'Data', 'Code'] + } + + const actual = await sut.getDatasetAvailableCategories(testDatasetIds.persistentId) + expect(actual.sort()).toEqual(fileMetadata.categories.sort()) + }) + + test('should return error when dataset does not exist', async () => { + await expect(sut.getDatasetAvailableCategories(nonExistentTestDatasetId)).rejects.toThrow() + }) + }) })