Skip to content

Commit 2c4ca04

Browse files
authored
Merge pull request #415 from vera/feat/set-default-contributor
Add use case for setting default contributor
2 parents 4e14240 + 41f5337 commit 2c4ca04

11 files changed

Lines changed: 214 additions & 1 deletion

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel
1717
- Datasets: Added `exportDatasetMetadata` use case, repository method, and `ExportedDatasetMetadata` response type to support exporting dataset metadata by numeric id or persistent id through Dataverse endpoint `GET /datasets/export`.
1818
- Collections: Added `allowedDatasetTypes` field to the [Collection](./src/collections/domain/models/Collection.ts) model. This field is optional and only populated the feature is enabled on the installation and configured on the collection.
1919
- Collections: Added theme information when retrieving a collection using `getCollection`.
20+
- Collections: Added `setDefaultContributorRole` use case.
2021

2122
### Changed
2223

‎docs/useCases.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ The different use cases currently available in the package are classified below,
2929
- [Update Collection Featured Items](#update-collection-featured-items)
3030
- [Delete Collection Featured Items](#delete-collection-featured-items)
3131
- [Delete a Collection Featured Item](#delete-a-collection-featured-item)
32+
- [Set Default Contributor Role](#set-default-contributor-role)
3233
- [Templates](#Templates)
3334
- [Templates read use cases](#templates-read-use-cases)
3435
- [Get a Template](#get-a-template)
@@ -732,6 +733,27 @@ deleteCollectionFeaturedItem.execute(featuredItemId)
732733

733734
_See [use case](../src/collections/domain/useCases/DeleteCollectionFeaturedItem.ts)_ definition.
734735

736+
#### Set Default Contributor Role
737+
738+
Sets the default contributor role of a collection, given a collection identifier and a role alias.
739+
740+
##### Example call:
741+
742+
```typescript
743+
import { setDefaultContributorRole } from '@iqss/dataverse-client-javascript'
744+
745+
/* ... */
746+
747+
const collectionIdOrAlias = 12345
748+
const roleAlias = 'curator'
749+
750+
setDefaultContributorRole.execute(collectionIdOrAlias, roleAlias)
751+
752+
/* ... */
753+
```
754+
755+
_See [use case](../src/collections/domain/useCases/SetDefaultContributorRole.ts)_ definition.
756+
735757
## Templates
736758

737759
### Templates Read Use Cases

‎src/collections/domain/repositories/ICollectionsRepository.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { CollectionSummary } from '../models/CollectionSummary'
1414
import { AllowedStorageDrivers } from '../models/AllowedStorageDrivers'
1515
import { StorageDriver } from '../../../core/domain/models/StorageDriver'
1616
import { LinkingObjectType } from '../useCases/GetCollectionsForLinking'
17+
import { RoleAlias } from '../../../roles/domain/models/RoleAlias'
1718

1819
export interface ICollectionsRepository {
1920
getCollection(collectionIdOrAlias: number | string): Promise<Collection>
@@ -39,6 +40,10 @@ export interface ICollectionsRepository {
3940
getCollectionUserPermissions(
4041
collectionIdOrAlias: number | string
4142
): Promise<CollectionUserPermissions>
43+
setDefaultContributorRole(
44+
collectionIdOrAlias: number | string,
45+
roleAlias: RoleAlias | string
46+
): Promise<void>
4247
getCollectionItems(
4348
collectionId?: string,
4449
limit?: number,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
3+
import { ROOT_COLLECTION_ID } from '../models/Collection'
4+
import { RoleAlias } from '../../../roles/domain/models/RoleAlias'
5+
6+
export class SetDefaultContributorRole implements UseCase<void> {
7+
private collectionsRepository: ICollectionsRepository
8+
9+
constructor(collectionsRepository: ICollectionsRepository) {
10+
this.collectionsRepository = collectionsRepository
11+
}
12+
13+
/**
14+
* Sets the default Role that is assigned to contributors in the given collection.
15+
*
16+
* @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)
17+
* If this parameter is not set, the default value is: ':root'
18+
* @param {RoleAlias | string} [roleAlias] - The alias of the role to be assigned
19+
* @returns {Promise<void>}
20+
*/
21+
async execute(
22+
collectionIdOrAlias: number | string = ROOT_COLLECTION_ID,
23+
roleAlias: RoleAlias | string
24+
): Promise<void> {
25+
return await this.collectionsRepository.setDefaultContributorRole(
26+
collectionIdOrAlias,
27+
roleAlias
28+
)
29+
}
30+
}

‎src/collections/index.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLin
2020
import { SetCollectionStorageDriver } from './domain/useCases/SetCollectionStorageDriver'
2121
import { DeleteCollectionStorageDriver } from './domain/useCases/DeleteCollectionStorageDriver'
2222
import { GetAllowedCollectionStorageDrivers } from './domain/useCases/GetAllowedCollectionStorageDrivers'
23+
import { SetDefaultContributorRole } from './domain/useCases/SetDefaultContributorRole'
2324

2425
const collectionsRepository = new CollectionsRepository()
2526

@@ -46,6 +47,7 @@ const deleteCollectionStorageDriver = new DeleteCollectionStorageDriver(collecti
4647
const getAllowedCollectionStorageDrivers = new GetAllowedCollectionStorageDrivers(
4748
collectionsRepository
4849
)
50+
const setDefaultContributorRole = new SetDefaultContributorRole(collectionsRepository)
4951

5052
export {
5153
getCollection,
@@ -68,7 +70,8 @@ export {
6870
getCollectionsForLinking,
6971
setCollectionStorageDriver,
7072
deleteCollectionStorageDriver,
71-
getAllowedCollectionStorageDrivers
73+
getAllowedCollectionStorageDrivers,
74+
setDefaultContributorRole
7275
}
7376
export { Collection, CollectionInputLevel, CollectionTheme } from './domain/models/Collection'
7477
export { CollectionFacet } from './domain/models/CollectionFacet'

‎src/collections/infra/repositories/CollectionsRepository.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { CollectionSummary } from '../../domain/models/CollectionSummary'
4242
import { AllowedStorageDrivers } from '../../domain/models/AllowedStorageDrivers'
4343
import { StorageDriver } from '../../../core/domain/models/StorageDriver'
4444
import { LinkingObjectType } from '../../domain/useCases/GetCollectionsForLinking'
45+
import { RoleAlias } from '../../../roles/domain/models/RoleAlias'
4546

4647
export interface NewCollectionRequestPayload {
4748
alias: string
@@ -225,6 +226,20 @@ export class CollectionsRepository extends ApiRepository implements ICollections
225226
})
226227
}
227228

229+
public async setDefaultContributorRole(
230+
collectionIdOrAlias: number | string,
231+
roleAlias: RoleAlias | string
232+
): Promise<void> {
233+
return this.doPut(
234+
`/${this.collectionsResourceName}/${collectionIdOrAlias}/defaultContributorRole/${roleAlias}`,
235+
{}
236+
)
237+
.then(() => undefined)
238+
.catch((error) => {
239+
throw error
240+
})
241+
}
242+
228243
public async getCollectionItems(
229244
collectionId?: string,
230245
limit?: number,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Aliases of built-in roles
2+
export enum RoleAlias {
3+
ADMIN = 'admin',
4+
FILE_DOWNLOADER = 'fileDownloader',
5+
FULL_CONTRIBUTOR = 'fullContributor',
6+
DV_CONTRIBUTOR = 'dvContributor',
7+
DS_CONTRIBUTOR = 'dsContributor',
8+
EDITOR = 'contributor',
9+
MANAGER = 'manager',
10+
CURATOR = 'curator',
11+
MEMBER = 'member'
12+
}

‎src/roles/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ const getUserSelectableRoles = new GetUserSelectableRoles(rolesRepository)
88
export { getUserSelectableRoles }
99

1010
export { Role } from './domain/models/Role'
11+
export { RoleAlias } from './domain/models/RoleAlias'
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { SetDefaultContributorRole } from '../../../src/collections/domain/useCases/SetDefaultContributorRole'
2+
import { CollectionsRepository } from '../../../src/collections/infra/repositories/CollectionsRepository'
3+
import { ApiConfig } from '../../../src'
4+
import { TestConstants } from '../../testHelpers/TestConstants'
5+
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
6+
import {
7+
createCollectionViaApi,
8+
deleteCollectionViaApi
9+
} from '../../testHelpers/collections/collectionHelper'
10+
import { RoleAlias } from '../../../src/roles/domain/models/RoleAlias'
11+
import { WriteError } from '../../../src/core/domain/repositories/WriteError'
12+
13+
describe('SetDefaultContributorRole', () => {
14+
const collectionsRepository = new CollectionsRepository()
15+
const useCase = new SetDefaultContributorRole(collectionsRepository)
16+
const testCollectionAlias = 'setDefaultContributorRoleTestCollection'
17+
18+
beforeAll(async () => {
19+
ApiConfig.init(
20+
TestConstants.TEST_API_URL,
21+
DataverseApiAuthMechanism.API_KEY,
22+
process.env.TEST_API_KEY
23+
)
24+
await createCollectionViaApi(testCollectionAlias)
25+
})
26+
27+
afterAll(async () => {
28+
await deleteCollectionViaApi(testCollectionAlias)
29+
})
30+
31+
test('should successfully set the default contributor role', async () => {
32+
const roleAlias = RoleAlias.CURATOR
33+
34+
await expect(useCase.execute(testCollectionAlias, roleAlias)).resolves.toBeUndefined()
35+
})
36+
37+
test('should successfully set the default contributor role for the root collection', async () => {
38+
const roleAlias = RoleAlias.CURATOR
39+
40+
await expect(useCase.execute(undefined, roleAlias)).resolves.toBeUndefined()
41+
})
42+
43+
test('should throw an error when the collection does not exist', async () => {
44+
const nonExistentCollection = 'nonExistentCollection'
45+
const roleAlias = RoleAlias.CURATOR
46+
47+
await expect(useCase.execute(nonExistentCollection, roleAlias)).rejects.toThrow(WriteError)
48+
})
49+
50+
test('should throw an error when the role alias does not exist', async () => {
51+
const nonExistentRoleAlias = 'invalidRoleAlias'
52+
53+
await expect(useCase.execute(testCollectionAlias, nonExistentRoleAlias)).rejects.toThrow(
54+
WriteError
55+
)
56+
})
57+
})

‎test/unit/collections/CollectionsRepository.test.ts‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
OrderType,
4949
SortType
5050
} from '../../../src/collections/domain/models/CollectionSearchCriteria'
51+
import { RoleAlias } from '../../../src/roles/domain/models/RoleAlias'
5152

5253
describe('CollectionsRepository', () => {
5354
const sut: CollectionsRepository = new CollectionsRepository()
@@ -97,6 +98,14 @@ describe('CollectionsRepository', () => {
9798
data: createCollectionPayload()
9899
}
99100
}
101+
const testSetDefaultContributorRoleResponse = {
102+
data: {
103+
status: 'OK',
104+
data: {
105+
message: 'Default contributor role has been set'
106+
}
107+
}
108+
}
100109
const testCollectionModel = createCollectionModel()
101110

102111
beforeEach(() => {
@@ -893,4 +902,32 @@ describe('CollectionsRepository', () => {
893902
})
894903
})
895904
})
905+
906+
describe('setDefaultContributorRole', () => {
907+
const testRoleAlias = RoleAlias.CURATOR
908+
909+
test('should call the API', async () => {
910+
jest.spyOn(axios, 'put').mockResolvedValue(testSetDefaultContributorRoleResponse)
911+
const expectedApiEndpoint = `${TestConstants.TEST_API_URL}/dataverses/test-collection/defaultContributorRole/${testRoleAlias}`
912+
913+
await sut.setDefaultContributorRole('test-collection', testRoleAlias)
914+
915+
expect(axios.put).toHaveBeenCalledWith(
916+
expectedApiEndpoint,
917+
'{}',
918+
TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_API_KEY
919+
)
920+
})
921+
922+
test('should return error result on error response', async () => {
923+
jest.spyOn(axios, 'put').mockRejectedValue(TestConstants.TEST_ERROR_RESPONSE)
924+
let error = undefined as unknown as WriteError
925+
926+
await sut
927+
.setDefaultContributorRole('test-collection', testRoleAlias)
928+
.catch((e) => (error = e))
929+
930+
expect(error).toBeInstanceOf(Error)
931+
})
932+
})
896933
})

0 commit comments

Comments
 (0)