From c861f70041553e01288c867e5037607736f5f9ab Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Wed, 10 Dec 2025 10:27:30 +0100 Subject: [PATCH 1/7] feat: add use case for assigning role on collection --- .../repositories/ICollectionsRepository.ts | 5 ++++ .../domain/useCases/AssignRoleOnCollection.ts | 28 +++++++++++++++++++ src/collections/index.ts | 5 +++- .../repositories/CollectionsRepository.ts | 15 ++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/collections/domain/useCases/AssignRoleOnCollection.ts diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index bc8960c8..492c05e8 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -25,6 +25,11 @@ export interface ICollectionsRepository { getCollectionUserPermissions( collectionIdOrAlias: number | string ): Promise + assignRoleOnCollection( + collectionIdOrAlias: number | string, + roleAssignee: string, + roleAlias: string + ): Promise getCollectionItems( collectionId?: string, limit?: number, diff --git a/src/collections/domain/useCases/AssignRoleOnCollection.ts b/src/collections/domain/useCases/AssignRoleOnCollection.ts new file mode 100644 index 00000000..e688677d --- /dev/null +++ b/src/collections/domain/useCases/AssignRoleOnCollection.ts @@ -0,0 +1,28 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { ICollectionsRepository } from '../repositories/ICollectionsRepository' +import { ROOT_COLLECTION_ID } from '../models/Collection' + +export class AssignRoleOnCollection implements UseCase { + private collectionsRepository: ICollectionsRepository + + constructor(collectionsRepository: ICollectionsRepository) { + this.collectionsRepository = collectionsRepository + } + + /** + * Assigns a new role to someone on the given Dataverse collection. + * + * @param {number | string} [collectionIdOrAlias = ':root'] - A generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId) + * If this parameter is not set, the default value is: ':root' + * @param {string} [roleAssignee] - To whom the role should be assigned + * @param {string} [roleAlias] - The alias of the role to be assigned + * @returns {Promise} + */ + async execute( + collectionIdOrAlias: number | string = ROOT_COLLECTION_ID, + roleAssignee: string, + roleAlias: string + ): Promise { + return await this.collectionsRepository.assignRoleOnCollection(collectionIdOrAlias, roleAssignee, roleAlias) + } +} diff --git a/src/collections/index.ts b/src/collections/index.ts index 59e2e50b..58dd3daa 100644 --- a/src/collections/index.ts +++ b/src/collections/index.ts @@ -16,6 +16,7 @@ import { LinkCollection } from './domain/useCases/LinkCollection' import { UnlinkCollection } from './domain/useCases/UnlinkCollection' import { GetCollectionLinks } from './domain/useCases/GetCollectionLinks' import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLinking' +import { AssignRoleOnCollection } from './domain/useCases/AssignRoleOnCollection' const collectionsRepository = new CollectionsRepository() @@ -36,6 +37,7 @@ const linkCollection = new LinkCollection(collectionsRepository) const unlinkCollection = new UnlinkCollection(collectionsRepository) const getCollectionLinks = new GetCollectionLinks(collectionsRepository) const getCollectionsForLinking = new GetCollectionsForLinking(collectionsRepository) +const assignRoleOnCollection = new AssignRoleOnCollection(collectionsRepository) export { getCollection, @@ -54,7 +56,8 @@ export { linkCollection, unlinkCollection, getCollectionLinks, - getCollectionsForLinking + getCollectionsForLinking, + assignRoleOnCollection } export { Collection, CollectionInputLevel } from './domain/models/Collection' export { CollectionFacet } from './domain/models/CollectionFacet' diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index e0e459b0..e57c73cc 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -167,6 +167,21 @@ export class CollectionsRepository extends ApiRepository implements ICollections }) } + public async assignRoleOnCollection( + collectionIdOrAlias: number | string, + roleAssignee: string, + roleAlias: string + ): Promise { + return this.doPost(`/${this.collectionsResourceName}/${collectionIdOrAlias}/assignments`, { + assignee: roleAssignee, + role: roleAlias + }) + .then(() => undefined) + .catch((error) => { + throw error + }) + } + public async getCollectionItems( collectionId?: string, limit?: number, From 5a410bce7c33c9dad26fecb559a4aa600a86c424 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Wed, 10 Dec 2025 10:40:56 +0100 Subject: [PATCH 2/7] feat: add use case for assigning role on dataset --- .../repositories/IDatasetsRepository.ts | 5 ++++ .../domain/useCases/AssignRoleOnDataset.ts | 26 +++++++++++++++++++ src/datasets/index.ts | 5 +++- .../infra/repositories/DatasetsRepository.ts | 15 +++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/datasets/domain/useCases/AssignRoleOnDataset.ts diff --git a/src/datasets/domain/repositories/IDatasetsRepository.ts b/src/datasets/domain/repositories/IDatasetsRepository.ts index 09859777..2d7268dc 100644 --- a/src/datasets/domain/repositories/IDatasetsRepository.ts +++ b/src/datasets/domain/repositories/IDatasetsRepository.ts @@ -102,4 +102,9 @@ export interface IDatasetsRepository { payload: DatasetLicenseUpdateRequest ): Promise getDatasetStorageDriver(datasetId: number | string): Promise + assignRoleOnDataset( + datasetId: number | string, + roleAssignee: string, + roleAlias: string + ): Promise } diff --git a/src/datasets/domain/useCases/AssignRoleOnDataset.ts b/src/datasets/domain/useCases/AssignRoleOnDataset.ts new file mode 100644 index 00000000..92d6e849 --- /dev/null +++ b/src/datasets/domain/useCases/AssignRoleOnDataset.ts @@ -0,0 +1,26 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { IDatasetsRepository } from '../repositories/IDatasetsRepository' + +export class AssignRoleOnDataset implements UseCase { + private datasetsRepository: IDatasetsRepository + + constructor(datasetsRepository: IDatasetsRepository) { + this.datasetsRepository = datasetsRepository + } + + /** + * Assigns a new role to someone on the given dataset. + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string} [roleAssignee] - To whom the role should be assigned + * @param {string} [roleAlias] - The alias of the role to be assigned + * @returns {Promise} + */ + async execute( + datasetId: number | string, + roleAssignee: string, + roleAlias: string + ): Promise { + return await this.datasetsRepository.assignRoleOnDataset(datasetId, roleAssignee, roleAlias) + } +} diff --git a/src/datasets/index.ts b/src/datasets/index.ts index 3c081fc6..45d7f58f 100644 --- a/src/datasets/index.ts +++ b/src/datasets/index.ts @@ -34,6 +34,7 @@ import { GetDatasetCitationInOtherFormats } from './domain/useCases/GetDatasetCi import { UpdateTermsOfAccess } from './domain/useCases/UpdateTermsOfAccess' import { UpdateDatasetLicense } from './domain/useCases/UpdateDatasetLicense' import { GetDatasetStorageDriver } from './domain/useCases/GetDatasetStorageDriver' +import { AssignRoleOnDataset } from './domain/useCases/AssignRoleOnDataset' const datasetsRepository = new DatasetsRepository() @@ -84,6 +85,7 @@ const getDatasetCitationInOtherFormats = new GetDatasetCitationInOtherFormats(da const updateTermsOfAccess = new UpdateTermsOfAccess(datasetsRepository) const updateDatasetLicense = new UpdateDatasetLicense(datasetsRepository) const getDatasetStorageDriver = new GetDatasetStorageDriver(datasetsRepository) +const assignRoleOnDataset = new AssignRoleOnDataset(datasetsRepository) export { getDataset, @@ -115,7 +117,8 @@ export { setAvailableLicensesForDatasetType, deleteDatasetType, updateDatasetLicense, - getDatasetStorageDriver + getDatasetStorageDriver, + assignRoleOnDataset } export { DatasetNotNumberedVersion } from './domain/models/DatasetNotNumberedVersion' export { DatasetUserPermissions } from './domain/models/DatasetUserPermissions' diff --git a/src/datasets/infra/repositories/DatasetsRepository.ts b/src/datasets/infra/repositories/DatasetsRepository.ts index c29db6c0..868fa042 100644 --- a/src/datasets/infra/repositories/DatasetsRepository.ts +++ b/src/datasets/infra/repositories/DatasetsRepository.ts @@ -511,4 +511,19 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi throw error }) } + + public async assignRoleOnDataset( + datasetId: number | string, + roleAssignee: string, + roleAlias: string + ): Promise { + return this.doPost(this.buildApiEndpoint(this.datasetsResourceName, 'assignments', datasetId), { + assignee: roleAssignee, + role: roleAlias + }) + .then(() => undefined) + .catch((error) => { + throw error + }) + } } From 15750362348bb7a3b982c5f048c1fca8f6186ffe Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Wed, 10 Dec 2025 10:56:42 +0100 Subject: [PATCH 3/7] feat: add use case for unassigning role on dataset --- .../repositories/IDatasetsRepository.ts | 4 ++++ .../domain/useCases/UnassignRoleOnDataset.ts | 24 +++++++++++++++++++ src/datasets/index.ts | 5 +++- .../infra/repositories/DatasetsRepository.ts | 11 +++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/datasets/domain/useCases/UnassignRoleOnDataset.ts diff --git a/src/datasets/domain/repositories/IDatasetsRepository.ts b/src/datasets/domain/repositories/IDatasetsRepository.ts index 2d7268dc..9aeced81 100644 --- a/src/datasets/domain/repositories/IDatasetsRepository.ts +++ b/src/datasets/domain/repositories/IDatasetsRepository.ts @@ -107,4 +107,8 @@ export interface IDatasetsRepository { roleAssignee: string, roleAlias: string ): Promise + unassignRoleOnDataset( + datasetId: number | string, + roleAssignmentId: number + ): Promise } diff --git a/src/datasets/domain/useCases/UnassignRoleOnDataset.ts b/src/datasets/domain/useCases/UnassignRoleOnDataset.ts new file mode 100644 index 00000000..32baf096 --- /dev/null +++ b/src/datasets/domain/useCases/UnassignRoleOnDataset.ts @@ -0,0 +1,24 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { IDatasetsRepository } from '../repositories/IDatasetsRepository' + +export class UnassignRoleOnDataset implements UseCase { + private datasetsRepository: IDatasetsRepository + + constructor(datasetsRepository: IDatasetsRepository) { + this.datasetsRepository = datasetsRepository + } + + /** + * Deletes the given role assignment on the given dataset. + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {number} [roleAssignmentId] - To numeric identifier of the role assignment + * @returns {Promise} + */ + async execute( + datasetId: number | string, + roleAssignmentId: number + ): Promise { + return await this.datasetsRepository.unassignRoleOnDataset(datasetId, roleAssignmentId) + } +} diff --git a/src/datasets/index.ts b/src/datasets/index.ts index 45d7f58f..dc35ead1 100644 --- a/src/datasets/index.ts +++ b/src/datasets/index.ts @@ -35,6 +35,7 @@ import { UpdateTermsOfAccess } from './domain/useCases/UpdateTermsOfAccess' import { UpdateDatasetLicense } from './domain/useCases/UpdateDatasetLicense' import { GetDatasetStorageDriver } from './domain/useCases/GetDatasetStorageDriver' import { AssignRoleOnDataset } from './domain/useCases/AssignRoleOnDataset' +import { UnassignRoleOnDataset } from './domain/useCases/UnassignRoleOnDataset' const datasetsRepository = new DatasetsRepository() @@ -86,6 +87,7 @@ const updateTermsOfAccess = new UpdateTermsOfAccess(datasetsRepository) const updateDatasetLicense = new UpdateDatasetLicense(datasetsRepository) const getDatasetStorageDriver = new GetDatasetStorageDriver(datasetsRepository) const assignRoleOnDataset = new AssignRoleOnDataset(datasetsRepository) +const unassignRoleOnDataset = new AssignRoleOnDataset(datasetsRepository) export { getDataset, @@ -118,7 +120,8 @@ export { deleteDatasetType, updateDatasetLicense, getDatasetStorageDriver, - assignRoleOnDataset + assignRoleOnDataset, + unassignRoleOnDataset } export { DatasetNotNumberedVersion } from './domain/models/DatasetNotNumberedVersion' export { DatasetUserPermissions } from './domain/models/DatasetUserPermissions' diff --git a/src/datasets/infra/repositories/DatasetsRepository.ts b/src/datasets/infra/repositories/DatasetsRepository.ts index 868fa042..49230662 100644 --- a/src/datasets/infra/repositories/DatasetsRepository.ts +++ b/src/datasets/infra/repositories/DatasetsRepository.ts @@ -526,4 +526,15 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi throw error }) } + + public async unassignRoleOnDataset( + datasetId: number | string, + roleAssignmentId: number + ): Promise { + return this.doDelete(this.buildApiEndpoint(this.datasetsResourceName, `assignments/${roleAssignmentId}`, datasetId)) + .then(() => undefined) + .catch((error) => { + throw error + }) + } } From e6eb3e5f8308f45f0028d52825fc327492f584d8 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Wed, 10 Dec 2025 10:56:52 +0100 Subject: [PATCH 4/7] feat: add use case for unassigning role on collection --- .../repositories/ICollectionsRepository.ts | 4 +++ .../useCases/UnassignRoleOnCollection.ts | 26 +++++++++++++++++++ src/collections/index.ts | 5 +++- .../repositories/CollectionsRepository.ts | 11 ++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/collections/domain/useCases/UnassignRoleOnCollection.ts diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index 492c05e8..f83f639c 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -30,6 +30,10 @@ export interface ICollectionsRepository { roleAssignee: string, roleAlias: string ): Promise + unassignRoleOnCollection( + collectionIdOrAlias: number | string, + roleAssignmentId: number + ): Promise getCollectionItems( collectionId?: string, limit?: number, diff --git a/src/collections/domain/useCases/UnassignRoleOnCollection.ts b/src/collections/domain/useCases/UnassignRoleOnCollection.ts new file mode 100644 index 00000000..9a752a78 --- /dev/null +++ b/src/collections/domain/useCases/UnassignRoleOnCollection.ts @@ -0,0 +1,26 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { ICollectionsRepository } from '../repositories/ICollectionsRepository' +import { ROOT_COLLECTION_ID } from '../models/Collection' + +export class UnassignRoleOnCollection implements UseCase { + private collectionsRepository: ICollectionsRepository + + constructor(collectionsRepository: ICollectionsRepository) { + this.collectionsRepository = collectionsRepository + } + + /** + * Deletes the given role assignment on the given Dataverse collection. + * + * @param {number | string} [collectionIdOrAlias = ':root'] - A generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId) + * If this parameter is not set, the default value is: ':root' + * @param {number} [roleAssignmentId] - To numeric identifier of the role assignment + * @returns {Promise} + */ + async execute( + collectionIdOrAlias: number | string = ROOT_COLLECTION_ID, + roleAssignmentId: number + ): Promise { + return await this.collectionsRepository.unassignRoleOnCollection(collectionIdOrAlias, roleAssignmentId) + } +} diff --git a/src/collections/index.ts b/src/collections/index.ts index 58dd3daa..589abe87 100644 --- a/src/collections/index.ts +++ b/src/collections/index.ts @@ -17,6 +17,7 @@ import { UnlinkCollection } from './domain/useCases/UnlinkCollection' import { GetCollectionLinks } from './domain/useCases/GetCollectionLinks' import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLinking' import { AssignRoleOnCollection } from './domain/useCases/AssignRoleOnCollection' +import { UnassignRoleOnCollection } from './domain/useCases/UnassignRoleOnCollection' const collectionsRepository = new CollectionsRepository() @@ -38,6 +39,7 @@ const unlinkCollection = new UnlinkCollection(collectionsRepository) const getCollectionLinks = new GetCollectionLinks(collectionsRepository) const getCollectionsForLinking = new GetCollectionsForLinking(collectionsRepository) const assignRoleOnCollection = new AssignRoleOnCollection(collectionsRepository) +const unassignRoleOnCollection = new UnassignRoleOnCollection(collectionsRepository) export { getCollection, @@ -57,7 +59,8 @@ export { unlinkCollection, getCollectionLinks, getCollectionsForLinking, - assignRoleOnCollection + assignRoleOnCollection, + unassignRoleOnCollection } export { Collection, CollectionInputLevel } from './domain/models/Collection' export { CollectionFacet } from './domain/models/CollectionFacet' diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index e57c73cc..373623d5 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -182,6 +182,17 @@ export class CollectionsRepository extends ApiRepository implements ICollections }) } + public async unassignRoleOnCollection( + collectionIdOrAlias: number | string, + roleAssignmentId: number + ): Promise { + return this.doDelete(`/${this.collectionsResourceName}/${collectionIdOrAlias}/assignments/${roleAssignmentId}`) + .then(() => undefined) + .catch((error) => { + throw error + }) + } + public async getCollectionItems( collectionId?: string, limit?: number, From 71e0047fa00a03dd24edc88d91984e3b7863526c Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Wed, 10 Dec 2025 11:02:39 +0100 Subject: [PATCH 5/7] fix: add use case for unassigning role on dataset --- src/datasets/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datasets/index.ts b/src/datasets/index.ts index dc35ead1..9ad0fc3c 100644 --- a/src/datasets/index.ts +++ b/src/datasets/index.ts @@ -87,7 +87,7 @@ const updateTermsOfAccess = new UpdateTermsOfAccess(datasetsRepository) const updateDatasetLicense = new UpdateDatasetLicense(datasetsRepository) const getDatasetStorageDriver = new GetDatasetStorageDriver(datasetsRepository) const assignRoleOnDataset = new AssignRoleOnDataset(datasetsRepository) -const unassignRoleOnDataset = new AssignRoleOnDataset(datasetsRepository) +const unassignRoleOnDataset = new UnassignRoleOnDataset(datasetsRepository) export { getDataset, From 196b7fa1b9c9bc5028820cd75a6c65cf6a30dda6 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Mon, 26 Jan 2026 17:05:31 +0100 Subject: [PATCH 6/7] test: add tests for (un)assigning roles on datasets and collections --- .../AssignRoleOnCollection.test.ts | 25 +++++++++++++++++++ .../UnassignRoleOnCollection.test.ts | 25 +++++++++++++++++++ .../unit/datasets/AssignRoleOnDataset.test.ts | 25 +++++++++++++++++++ .../datasets/UnassignRoleOnDataset.test.ts | 25 +++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 test/unit/collections/AssignRoleOnCollection.test.ts create mode 100644 test/unit/collections/UnassignRoleOnCollection.test.ts create mode 100644 test/unit/datasets/AssignRoleOnDataset.test.ts create mode 100644 test/unit/datasets/UnassignRoleOnDataset.test.ts diff --git a/test/unit/collections/AssignRoleOnCollection.test.ts b/test/unit/collections/AssignRoleOnCollection.test.ts new file mode 100644 index 00000000..255dc08d --- /dev/null +++ b/test/unit/collections/AssignRoleOnCollection.test.ts @@ -0,0 +1,25 @@ +import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository' +import { WriteError } from '../../../src' +import { AssignRoleOnCollection } from '../../../src/collections/domain/useCases/AssignRoleOnCollection' + +describe('execute', () => { + test('should assign role successfully on repository success', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.assignRoleOnCollection = jest.fn().mockResolvedValue(undefined) + + const testAssignRoleOnCollection = new AssignRoleOnCollection(collectionRepositoryStub) + + await expect(testAssignRoleOnCollection.execute(1, "@testUser", "curator")).resolves.toBeUndefined() + expect(collectionRepositoryStub.assignRoleOnCollection).toHaveBeenCalledWith(1, "@testUser", "curator") + }) + + test('should throw error on repository failure', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.assignRoleOnCollection = jest.fn().mockRejectedValue(new WriteError()) + + const testAssignRoleOnCollection = new AssignRoleOnCollection(collectionRepositoryStub) + + await expect(testAssignRoleOnCollection.execute(1, "@testUser", "curator")).rejects.toThrow(WriteError) + expect(collectionRepositoryStub.assignRoleOnCollection).toHaveBeenCalledWith(1, "@testUser", "curator") + }) +}) diff --git a/test/unit/collections/UnassignRoleOnCollection.test.ts b/test/unit/collections/UnassignRoleOnCollection.test.ts new file mode 100644 index 00000000..393f8fef --- /dev/null +++ b/test/unit/collections/UnassignRoleOnCollection.test.ts @@ -0,0 +1,25 @@ +import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository' +import { WriteError } from '../../../src' +import { UnassignRoleOnCollection } from '../../../src/collections/domain/useCases/UnassignRoleOnCollection' + +describe('execute', () => { + test('should unassign role successfully on repository success', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.unassignRoleOnCollection = jest.fn().mockResolvedValue(undefined) + + const testUnassignRoleOnCollection = new UnassignRoleOnCollection(collectionRepositoryStub) + + await expect(testUnassignRoleOnCollection.execute(1, 2)).resolves.toBeUndefined() + expect(collectionRepositoryStub.unassignRoleOnCollection).toHaveBeenCalledWith(1, 2) + }) + + test('should throw error on repository failure', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.unassignRoleOnCollection = jest.fn().mockRejectedValue(new WriteError()) + + const testUnassignRoleOnCollection = new UnassignRoleOnCollection(collectionRepositoryStub) + + await expect(testUnassignRoleOnCollection.execute(1, 2)).rejects.toThrow(WriteError) + expect(collectionRepositoryStub.unassignRoleOnCollection).toHaveBeenCalledWith(1, 2) + }) +}) diff --git a/test/unit/datasets/AssignRoleOnDataset.test.ts b/test/unit/datasets/AssignRoleOnDataset.test.ts new file mode 100644 index 00000000..bea50ab7 --- /dev/null +++ b/test/unit/datasets/AssignRoleOnDataset.test.ts @@ -0,0 +1,25 @@ +import { IDatasetsRepository } from '../../../src/datasets/domain/repositories/IDatasetsRepository' +import { WriteError } from '../../../src' +import { AssignRoleOnDataset } from '../../../src/datasets/domain/useCases/AssignRoleOnDataset' + +describe('execute', () => { + test('should assign role successfully on repository success', async () => { + const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository + datasetsRepositoryStub.assignRoleOnDataset = jest.fn().mockResolvedValue(undefined) + + const testAssignRoleOnDataset = new AssignRoleOnDataset(datasetsRepositoryStub) + + await expect(testAssignRoleOnDataset.execute(1, "@testUser", "curator")).resolves.toBeUndefined() + expect(datasetsRepositoryStub.assignRoleOnDataset).toHaveBeenCalledWith(1, "@testUser", "curator") + }) + + test('should throw error on repository failure', async () => { + const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository + datasetsRepositoryStub.assignRoleOnDataset = jest.fn().mockRejectedValue(new WriteError()) + + const testAssignRoleOnDataset = new AssignRoleOnDataset(datasetsRepositoryStub) + + await expect(testAssignRoleOnDataset.execute(1, "@testUser", "curator")).rejects.toThrow(WriteError) + expect(datasetsRepositoryStub.assignRoleOnDataset).toHaveBeenCalledWith(1, "@testUser", "curator") + }) +}) diff --git a/test/unit/datasets/UnassignRoleOnDataset.test.ts b/test/unit/datasets/UnassignRoleOnDataset.test.ts new file mode 100644 index 00000000..a168f6ab --- /dev/null +++ b/test/unit/datasets/UnassignRoleOnDataset.test.ts @@ -0,0 +1,25 @@ +import { IDatasetsRepository } from '../../../src/datasets/domain/repositories/IDatasetsRepository' +import { WriteError } from '../../../src' +import { UnassignRoleOnDataset } from '../../../src/datasets/domain/useCases/UnassignRoleOnDataset' + +describe('execute', () => { + test('should unassign role successfully on repository success', async () => { + const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository + datasetsRepositoryStub.unassignRoleOnDataset = jest.fn().mockResolvedValue(undefined) + + const testUnassignRoleOnDataset = new UnassignRoleOnDataset(datasetsRepositoryStub) + + await expect(testUnassignRoleOnDataset.execute(1, 2)).resolves.toBeUndefined() + expect(datasetsRepositoryStub.unassignRoleOnDataset).toHaveBeenCalledWith(1, 2) + }) + + test('should throw error on repository failure', async () => { + const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository + datasetsRepositoryStub.unassignRoleOnDataset = jest.fn().mockRejectedValue(new WriteError()) + + const testUnassignRoleOnDataset = new UnassignRoleOnDataset(datasetsRepositoryStub) + + await expect(testUnassignRoleOnDataset.execute(1, 2)).rejects.toThrow(WriteError) + expect(datasetsRepositoryStub.unassignRoleOnDataset).toHaveBeenCalledWith(1, 2) + }) +}) From 7c3afd265c9afaf361d70207c51dfbfa92f7b649 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Mon, 26 Jan 2026 17:14:54 +0100 Subject: [PATCH 7/7] docs: add docs for (un)assigning roles on datasets and collections --- docs/useCases.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/docs/useCases.md b/docs/useCases.md index f77a40e1..6ec7798a 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -25,6 +25,8 @@ The different use cases currently available in the package are classified below, - [Update Collection Featured Items](#update-collection-featured-items) - [Delete Collection Featured Items](#delete-collection-featured-items) - [Delete a Collection Featured Item](#delete-a-collection-featured-item) + - [Assign a Role on a Collection](#assign-a-role-on-a-collection) + - [Unassign a Role on a Collection](#unassign-a-role-on-a-collection) - [Templates](#Templates) - [Templates read use cases](#templates-read-use-cases) - [Get a Template](#get-a-template) @@ -63,6 +65,8 @@ The different use cases currently available in the package are classified below, - [Link Dataset Type with Metadata Blocks](#link-dataset-type-with-metadata-blocks) - [Set Available Licenses For Dataset Type](#set-available-licenses-for-dataset-type) - [Delete a Dataset Type](#delete-a-dataset-type) + - [Assign a Role on a Dataset](#assign-a-role-on-a-dataset) + - [Unassign a Role on a Dataset](#unassign-a-role-on-a-dataset) - [Files](#Files) - [Files read use cases](#files-read-use-cases) - [Get a File](#get-a-file) @@ -576,6 +580,49 @@ deleteCollectionFeaturedItem.execute(featuredItemId) _See [use case](../src/collections/domain/useCases/DeleteCollectionFeaturedItem.ts)_ definition. +#### Assign a Role on a Collection + +Assigns a role on a collection, given a collection identifier, a role assignee and a role alias. + +##### Example call: + +```typescript +import { assignRoleOnCollection } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const collectionIdOrAlias = 12345 +const roleAssignee = "@myUser" +const roleAlias = "curator" + +assignRoleOnCollection.execute(collectionIdOrAlias, roleAssignee, roleAlias) + +/* ... */ +``` + +_See [use case](../src/collections/domain/useCases/AssignRoleOnCollection.ts)_ definition. + +#### Unassign a Role on a Collection + +Unassigns a role on a collection, given a collection identifier and a role assignment identifier. + +##### Example call: + +```typescript +import { unassignRoleOnCollection } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const collectionIdOrAlias = 12345 +const roleAssignmentId = 67890 + +unassignRoleOnCollection.execute(collectionIdOrAlias, roleAssignmentId) + +/* ... */ +``` + +_See [use case](../src/collections/domain/useCases/UnassignRoleOnCollection.ts)_ definition. + ## Templates ### Templates Read Use Cases @@ -1516,6 +1563,49 @@ deleteDatasetType.execute(datasetTypeId).then(() => { _See [use case](../src/datasets/domain/useCases/DeleteDatasetType.ts) implementation_. +#### Assign a Role on a Dataset + +Assigns a role on a dataset, given a dataset identifier, a role assignee and a role alias. + +##### Example call: + +```typescript +import { assignRoleOnDataset } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const datasetId = 1 +const roleAssignee = "@myUser" +const roleAlias = "curator" + +assignRoleOnDataset.execute(datasetId, roleAssignee, roleAlias) + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/AssignRoleOnDataset.ts)_ definition. + +#### Unassign a Role on a Dataset + +Unassigns a role on a dataset, given a dataset identifier and a role assignment identifier. + +##### Example call: + +```typescript +import { unassignRoleOnDataset } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const datasetId = 1 +const roleAssignmentId = 67890 + +unassignRoleOnDataset.execute(datasetId, roleAssignmentId) + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/UnassignRoleOnDataset.ts)_ definition. + ## Files ### Files read use cases