From 1a5db4524db859b2a2cbac9ed91dc4c34b7e13e7 Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Thu, 15 Aug 2024 16:14:37 -0400 Subject: [PATCH 1/7] Add Publish Collection use case and functional test --- .../repositories/ICollectionsRepository.ts | 1 + .../domain/useCases/PublishCollection.ts | 20 ++++++++++ src/collections/index.ts | 10 ++++- .../repositories/CollectionsRepository.ts | 10 +++++ .../datasets/PublishCollection.test.ts | 39 +++++++++++++++++++ 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/collections/domain/useCases/PublishCollection.ts create mode 100644 test/functional/datasets/PublishCollection.test.ts diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index 776d94b4..dda1626c 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -9,6 +9,7 @@ export interface ICollectionsRepository { parentCollectionId: number | string ): Promise getCollectionFacets(collectionIdOrAlias: number | string): Promise + publishCollection(collectionId: number | string): Promise getCollectionUserPermissions( collectionIdOrAlias: number | string ): Promise diff --git a/src/collections/domain/useCases/PublishCollection.ts b/src/collections/domain/useCases/PublishCollection.ts new file mode 100644 index 00000000..2c3d870a --- /dev/null +++ b/src/collections/domain/useCases/PublishCollection.ts @@ -0,0 +1,20 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { ICollectionsRepository } from '../repositories/ICollectionsRepository' // Assuming Axios for HTTP requests + +export class PublishCollection implements UseCase { + private collectionsRepository: ICollectionsRepository + + constructor(collectionsRepository: ICollectionsRepository) { + this.collectionsRepository = collectionsRepository + } + + /** + * Publishes a collection, given its identifier and the type of version update type. + * + * @param {number | string} [collectionId] - The collection identifier, which can be a string (for collection alias), or a number (for numeric identifiers). + * @returns {Promise} - This method does not return anything upon successful completion. + */ + async execute(collectionId: number | string): Promise { + return await this.collectionsRepository.publishCollection(collectionId) + } +} diff --git a/src/collections/index.ts b/src/collections/index.ts index 1608b03f..0d706cf9 100644 --- a/src/collections/index.ts +++ b/src/collections/index.ts @@ -4,6 +4,7 @@ import { GetCollectionFacets } from './domain/useCases/GetCollectionFacets' import { GetCollectionUserPermissions } from './domain/useCases/GetCollectionUserPermissions' import { CollectionsRepository } from './infra/repositories/CollectionsRepository' +import { PublishCollection } from './domain/useCases/PublishCollection' const collectionsRepository = new CollectionsRepository() @@ -11,8 +12,15 @@ const getCollection = new GetCollection(collectionsRepository) const createCollection = new CreateCollection(collectionsRepository) const getCollectionFacets = new GetCollectionFacets(collectionsRepository) const getCollectionUserPermissions = new GetCollectionUserPermissions(collectionsRepository) +const publishCollection = new PublishCollection(collectionsRepository) -export { getCollection, createCollection, getCollectionFacets, getCollectionUserPermissions } +export { + getCollection, + createCollection, + getCollectionFacets, + getCollectionUserPermissions, + publishCollection +} export { Collection, CollectionInputLevel } from './domain/models/Collection' export { CollectionUserPermissions } from './domain/models/CollectionUserPermissions' export { CollectionDTO, CollectionInputLevelDTO } from './domain/dtos/CollectionDTO' diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index e7960161..f72b0293 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -88,6 +88,16 @@ export class CollectionsRepository extends ApiRepository implements ICollections throw error }) } + public async publishCollection(collectionId: string | number): Promise { + return this.doPost( + this.buildApiEndpoint(this.collectionsResourceName, `actions/:publish`, collectionId), + {} + ) + .then(() => undefined) + .catch((error) => { + throw error + }) + } public async getCollectionUserPermissions( collectionIdOrAlias: number | string diff --git a/test/functional/datasets/PublishCollection.test.ts b/test/functional/datasets/PublishCollection.test.ts new file mode 100644 index 00000000..eff802d6 --- /dev/null +++ b/test/functional/datasets/PublishCollection.test.ts @@ -0,0 +1,39 @@ +import { ApiConfig, createCollection, publishCollection, WriteError } from '../../../src' +import { TestConstants } from '../../testHelpers/TestConstants' +import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' +import { + createCollectionDTO, + deleteCollectionViaApi +} from '../../testHelpers/collections/collectionHelper' + +const testNewCollection = createCollectionDTO('test-publish-collection') + +describe('execute', () => { + beforeEach(async () => { + ApiConfig.init( + TestConstants.TEST_API_URL, + DataverseApiAuthMechanism.API_KEY, + process.env.TEST_API_KEY + ) + }) + + test('should successfully publish a collection', async () => { + const createdCollectiontIdentifier = await createCollection.execute(testNewCollection) + + const response = await publishCollection.execute(createdCollectiontIdentifier) + + expect(response).toBeUndefined() + await deleteCollectionViaApi(testNewCollection.alias) + }) + + test('should throw an error when trying to publish a collection that does not exist', async () => { + const nonExistentTestCollectionId = 4567 + const expectedError = new WriteError( + `[404] Can't find dataverse with identifier='${nonExistentTestCollectionId}'` + ) + + await expect(publishCollection.execute(nonExistentTestCollectionId)).rejects.toThrow( + expectedError + ) + }) +}) From ba8de45799633c4a5e28a403c142cf1aa02a9012 Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Mon, 26 Aug 2024 13:29:22 -0400 Subject: [PATCH 2/7] fix: use doGet() in PublishCollection implemementation --- .../infra/repositories/CollectionsRepository.ts | 4 ++-- test/functional/datasets/PublishCollection.test.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index f72b0293..308660a4 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -88,9 +88,9 @@ export class CollectionsRepository extends ApiRepository implements ICollections throw error }) } - public async publishCollection(collectionId: string | number): Promise { + public async publishCollection(collectionIdOrAlias: string | number): Promise { return this.doPost( - this.buildApiEndpoint(this.collectionsResourceName, `actions/:publish`, collectionId), + `/${this.collectionsResourceName}/${collectionIdOrAlias}/actions/:publish`, {} ) .then(() => undefined) diff --git a/test/functional/datasets/PublishCollection.test.ts b/test/functional/datasets/PublishCollection.test.ts index eff802d6..bbe8e8a4 100644 --- a/test/functional/datasets/PublishCollection.test.ts +++ b/test/functional/datasets/PublishCollection.test.ts @@ -17,7 +17,7 @@ describe('execute', () => { ) }) - test('should successfully publish a collection', async () => { + test('should successfully publish a collection with id', async () => { const createdCollectiontIdentifier = await createCollection.execute(testNewCollection) const response = await publishCollection.execute(createdCollectiontIdentifier) @@ -25,6 +25,14 @@ describe('execute', () => { expect(response).toBeUndefined() await deleteCollectionViaApi(testNewCollection.alias) }) + test('should successfully publish a collection with alias', async () => { + await createCollection.execute(testNewCollection) + + const response = await publishCollection.execute(testNewCollection.alias) + + expect(response).toBeUndefined() + await deleteCollectionViaApi(testNewCollection.alias) + }) test('should throw an error when trying to publish a collection that does not exist', async () => { const nonExistentTestCollectionId = 4567 From 0a0dcf28a8593708dd32b94bc8951115cd7ecec1 Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Mon, 26 Aug 2024 14:13:38 -0400 Subject: [PATCH 3/7] updated tests --- .../PublishCollection.test.ts | 0 .../collections/CollectionsRepository.test.ts | 17 ++++++++++++++ .../collections/PublishCollection.test.ts | 23 +++++++++++++++++++ 3 files changed, 40 insertions(+) rename test/functional/{datasets => collections}/PublishCollection.test.ts (100%) create mode 100644 test/unit/collections/PublishCollection.test.ts diff --git a/test/functional/datasets/PublishCollection.test.ts b/test/functional/collections/PublishCollection.test.ts similarity index 100% rename from test/functional/datasets/PublishCollection.test.ts rename to test/functional/collections/PublishCollection.test.ts diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index e13c4838..9df51038 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -94,6 +94,23 @@ describe('CollectionsRepository', () => { }) }) + describe('publishCollection', () => { + const testPublishCollectionAlias = 'publishCollection-test' + + afterAll(async () => { + await deleteCollectionViaApi(testPublishCollectionAlias) + }) + + test('should publish a collection', async () => { + const newCollectionDTO = createCollectionDTO(testPublishCollectionAlias) + const actualId = await sut.createCollection(newCollectionDTO) + await sut.publishCollection(actualId) + const createdCollection = await sut.getCollection(actualId) + + expect(createdCollection.isReleased).toBe(true) + expect(createdCollection.name).toBe(newCollectionDTO.name) + }) + }) describe('createCollection', () => { const testCreateCollectionAlias1 = 'createCollection-test-1' const testCreateCollectionAlias2 = 'createCollection-test-2' diff --git a/test/unit/collections/PublishCollection.test.ts b/test/unit/collections/PublishCollection.test.ts new file mode 100644 index 00000000..67d6ce43 --- /dev/null +++ b/test/unit/collections/PublishCollection.test.ts @@ -0,0 +1,23 @@ +import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository' +import { PublishCollection } from '../../../src/collections/domain/useCases/PublishCollection' +import { WriteError } from '../../../src' + +describe('execute', () => { + test('should return undefined on repository success', async () => { + const collectionsRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionsRepositoryStub.publishCollection = jest.fn().mockResolvedValue(undefined) + const sut = new PublishCollection(collectionsRepositoryStub) + + const actual = await sut.execute(1) + + expect(actual).toEqual(undefined) + }) + + test('should return error result on repository error', async () => { + const collectionsRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionsRepositoryStub.publishCollection = jest.fn().mockRejectedValue(new WriteError()) + const sut = new PublishCollection(collectionsRepositoryStub) + + await expect(sut.execute(1)).rejects.toThrow(WriteError) + }) +}) From c50b63eddf934fb4c17e82525da37a90faa66aae Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Mon, 26 Aug 2024 14:15:28 -0400 Subject: [PATCH 4/7] use consistent param name --- src/collections/domain/repositories/ICollectionsRepository.ts | 2 +- src/collections/domain/useCases/PublishCollection.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index dda1626c..65c73c7b 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -9,7 +9,7 @@ export interface ICollectionsRepository { parentCollectionId: number | string ): Promise getCollectionFacets(collectionIdOrAlias: number | string): Promise - publishCollection(collectionId: number | string): Promise + publishCollection(collectionIdOrAlias: number | string): Promise getCollectionUserPermissions( collectionIdOrAlias: number | string ): Promise diff --git a/src/collections/domain/useCases/PublishCollection.ts b/src/collections/domain/useCases/PublishCollection.ts index 2c3d870a..f3beaa5b 100644 --- a/src/collections/domain/useCases/PublishCollection.ts +++ b/src/collections/domain/useCases/PublishCollection.ts @@ -14,7 +14,7 @@ export class PublishCollection implements UseCase { * @param {number | string} [collectionId] - The collection identifier, which can be a string (for collection alias), or a number (for numeric identifiers). * @returns {Promise} - This method does not return anything upon successful completion. */ - async execute(collectionId: number | string): Promise { - return await this.collectionsRepository.publishCollection(collectionId) + async execute(collectionIdOrAlias: number | string): Promise { + return await this.collectionsRepository.publishCollection(collectionIdOrAlias) } } From 3cb8f196b808d4368e6c6ab974c3e1b772979a2b Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Mon, 26 Aug 2024 14:16:14 -0400 Subject: [PATCH 5/7] fix: function documentation --- src/collections/domain/useCases/PublishCollection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collections/domain/useCases/PublishCollection.ts b/src/collections/domain/useCases/PublishCollection.ts index f3beaa5b..9840b356 100644 --- a/src/collections/domain/useCases/PublishCollection.ts +++ b/src/collections/domain/useCases/PublishCollection.ts @@ -11,7 +11,7 @@ export class PublishCollection implements UseCase { /** * Publishes a collection, given its identifier and the type of version update type. * - * @param {number | string} [collectionId] - The collection identifier, which can be a string (for collection alias), or a number (for numeric identifiers). + * @param {number | string} [collectionIdOrAlias] - The collection identifier, which can be a string (for collection alias), or a number (for numeric identifiers). * @returns {Promise} - This method does not return anything upon successful completion. */ async execute(collectionIdOrAlias: number | string): Promise { From 7f18ee41fc6cbb6af0417c951a08226d9692db12 Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Mon, 26 Aug 2024 14:30:41 -0400 Subject: [PATCH 6/7] add use case documentation --- docs/useCases.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/useCases.md b/docs/useCases.md index 31003af8..57c56ead 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -15,6 +15,7 @@ The different use cases currently available in the package are classified below, - [Get User Permissions on a Collection](#get-user-permissions-on-a-collection) - [Collections write use cases](#collections-write-use-cases) - [Create a Collection](#create-a-collection) + - [Publish a Collection](#publish-a-collection) - [Datasets](#Datasets) - [Datasets read use cases](#datasets-read-use-cases) - [Get a Dataset](#get-a-dataset) @@ -191,6 +192,27 @@ The above example creates the new collection in the `root` collection since no c The use case returns a number, which is the identifier of the created collection. +#### Publish a Collection + +Publishes a Collection, given the collection identifier. + +##### Example call: + +```typescript +import { publishCollection } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const collectionIdOrAlias = 12345 + +publishCollection.execute(collectionIdOrAlias) + +/* ... */ +``` +The `collectionIdOrAlias` is a generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId). + +_See [use case](../src/collections/domain/useCases/PublishCollection.ts)_ definition. + ## Datasets ### Datasets Read Use Cases From 942ae755b831a0f34495410b1b25e781f1f99baf Mon Sep 17 00:00:00 2001 From: Ellen Kraffmiller Date: Mon, 9 Sep 2024 11:46:00 -0400 Subject: [PATCH 7/7] Update PublishCollection.ts fix Publish Collection use case documentation --- src/collections/domain/useCases/PublishCollection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collections/domain/useCases/PublishCollection.ts b/src/collections/domain/useCases/PublishCollection.ts index 9840b356..5eba7bce 100644 --- a/src/collections/domain/useCases/PublishCollection.ts +++ b/src/collections/domain/useCases/PublishCollection.ts @@ -9,7 +9,7 @@ export class PublishCollection implements UseCase { } /** - * Publishes a collection, given its identifier and the type of version update type. + * Publishes a collection, given its identifier. * * @param {number | string} [collectionIdOrAlias] - The collection identifier, which can be a string (for collection alias), or a number (for numeric identifiers). * @returns {Promise} - This method does not return anything upon successful completion.