Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel
- 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`.
- 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.
- Collections: Added theme information when retrieving a collection using `getCollection`.
- Collections: Added `setDefaultContributorRole` use case.

### Changed

Expand Down
22 changes: 22 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ 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)
- [Set Default Contributor Role](#set-default-contributor-role)
- [Templates](#Templates)
- [Templates read use cases](#templates-read-use-cases)
- [Get a Template](#get-a-template)
Expand Down Expand Up @@ -732,6 +733,27 @@ deleteCollectionFeaturedItem.execute(featuredItemId)

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

#### Set Default Contributor Role

Sets the default contributor role of a collection, given a collection identifier and a role alias.

##### Example call:

```typescript
import { setDefaultContributorRole } from '@iqss/dataverse-client-javascript'

/* ... */

const collectionIdOrAlias = 12345
const roleAlias = 'curator'

setDefaultContributorRole.execute(collectionIdOrAlias, roleAlias)

Comment thread
vera marked this conversation as resolved.
/* ... */
```

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

## Templates

### Templates Read Use Cases
Expand Down
5 changes: 5 additions & 0 deletions src/collections/domain/repositories/ICollectionsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { CollectionSummary } from '../models/CollectionSummary'
import { AllowedStorageDrivers } from '../models/AllowedStorageDrivers'
import { StorageDriver } from '../../../core/domain/models/StorageDriver'
import { LinkingObjectType } from '../useCases/GetCollectionsForLinking'
import { RoleAlias } from '../../../roles/domain/models/RoleAlias'

export interface ICollectionsRepository {
getCollection(collectionIdOrAlias: number | string): Promise<Collection>
Expand All @@ -39,6 +40,10 @@ export interface ICollectionsRepository {
getCollectionUserPermissions(
collectionIdOrAlias: number | string
): Promise<CollectionUserPermissions>
setDefaultContributorRole(
collectionIdOrAlias: number | string,
roleAlias: RoleAlias | string
): Promise<void>
getCollectionItems(
collectionId?: string,
limit?: number,
Expand Down
30 changes: 30 additions & 0 deletions src/collections/domain/useCases/SetDefaultContributorRole.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
import { ROOT_COLLECTION_ID } from '../models/Collection'
import { RoleAlias } from '../../../roles/domain/models/RoleAlias'

export class SetDefaultContributorRole implements UseCase<void> {
private collectionsRepository: ICollectionsRepository

constructor(collectionsRepository: ICollectionsRepository) {
this.collectionsRepository = collectionsRepository
}

/**
* Sets the default Role that is assigned to contributors in the given 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 {RoleAlias | string} [roleAlias] - The alias of the role to be assigned
* @returns {Promise<void>}
*/
async execute(
collectionIdOrAlias: number | string = ROOT_COLLECTION_ID,
roleAlias: RoleAlias | string
): Promise<void> {
return await this.collectionsRepository.setDefaultContributorRole(
collectionIdOrAlias,
roleAlias
)
}
}
5 changes: 4 additions & 1 deletion src/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLin
import { SetCollectionStorageDriver } from './domain/useCases/SetCollectionStorageDriver'
import { DeleteCollectionStorageDriver } from './domain/useCases/DeleteCollectionStorageDriver'
import { GetAllowedCollectionStorageDrivers } from './domain/useCases/GetAllowedCollectionStorageDrivers'
import { SetDefaultContributorRole } from './domain/useCases/SetDefaultContributorRole'

const collectionsRepository = new CollectionsRepository()

Expand All @@ -46,6 +47,7 @@ const deleteCollectionStorageDriver = new DeleteCollectionStorageDriver(collecti
const getAllowedCollectionStorageDrivers = new GetAllowedCollectionStorageDrivers(
collectionsRepository
)
const setDefaultContributorRole = new SetDefaultContributorRole(collectionsRepository)

export {
getCollection,
Expand All @@ -68,7 +70,8 @@ export {
getCollectionsForLinking,
setCollectionStorageDriver,
deleteCollectionStorageDriver,
getAllowedCollectionStorageDrivers
getAllowedCollectionStorageDrivers,
setDefaultContributorRole
}
export { Collection, CollectionInputLevel, CollectionTheme } from './domain/models/Collection'
export { CollectionFacet } from './domain/models/CollectionFacet'
Expand Down
15 changes: 15 additions & 0 deletions src/collections/infra/repositories/CollectionsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { CollectionSummary } from '../../domain/models/CollectionSummary'
import { AllowedStorageDrivers } from '../../domain/models/AllowedStorageDrivers'
import { StorageDriver } from '../../../core/domain/models/StorageDriver'
import { LinkingObjectType } from '../../domain/useCases/GetCollectionsForLinking'
import { RoleAlias } from '../../../roles/domain/models/RoleAlias'

export interface NewCollectionRequestPayload {
alias: string
Expand Down Expand Up @@ -225,6 +226,20 @@ export class CollectionsRepository extends ApiRepository implements ICollections
})
}

public async setDefaultContributorRole(
collectionIdOrAlias: number | string,
roleAlias: RoleAlias | string
): Promise<void> {
return this.doPut(
`/${this.collectionsResourceName}/${collectionIdOrAlias}/defaultContributorRole/${roleAlias}`,
{}
)
.then(() => undefined)
.catch((error) => {
throw error
})
}
Comment thread
vera marked this conversation as resolved.

public async getCollectionItems(
collectionId?: string,
limit?: number,
Expand Down
12 changes: 12 additions & 0 deletions src/roles/domain/models/RoleAlias.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Aliases of built-in roles
export enum RoleAlias {
ADMIN = 'admin',
FILE_DOWNLOADER = 'fileDownloader',
FULL_CONTRIBUTOR = 'fullContributor',
DV_CONTRIBUTOR = 'dvContributor',
DS_CONTRIBUTOR = 'dsContributor',
EDITOR = 'contributor',
MANAGER = 'manager',
CURATOR = 'curator',
MEMBER = 'member'
}
1 change: 1 addition & 0 deletions src/roles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ const getUserSelectableRoles = new GetUserSelectableRoles(rolesRepository)
export { getUserSelectableRoles }

export { Role } from './domain/models/Role'
export { RoleAlias } from './domain/models/RoleAlias'
57 changes: 57 additions & 0 deletions test/integration/collections/SetDefaultContributorRole.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { SetDefaultContributorRole } from '../../../src/collections/domain/useCases/SetDefaultContributorRole'
import { CollectionsRepository } from '../../../src/collections/infra/repositories/CollectionsRepository'
import { ApiConfig } from '../../../src'
import { TestConstants } from '../../testHelpers/TestConstants'
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
import {
createCollectionViaApi,
deleteCollectionViaApi
} from '../../testHelpers/collections/collectionHelper'
import { RoleAlias } from '../../../src/roles/domain/models/RoleAlias'
import { WriteError } from '../../../src/core/domain/repositories/WriteError'

describe('SetDefaultContributorRole', () => {
const collectionsRepository = new CollectionsRepository()
const useCase = new SetDefaultContributorRole(collectionsRepository)
const testCollectionAlias = 'setDefaultContributorRoleTestCollection'

beforeAll(async () => {
ApiConfig.init(
TestConstants.TEST_API_URL,
DataverseApiAuthMechanism.API_KEY,
process.env.TEST_API_KEY
)
await createCollectionViaApi(testCollectionAlias)
})

afterAll(async () => {
await deleteCollectionViaApi(testCollectionAlias)
})

test('should successfully set the default contributor role', async () => {
const roleAlias = RoleAlias.CURATOR

await expect(useCase.execute(testCollectionAlias, roleAlias)).resolves.toBeUndefined()
})

test('should successfully set the default contributor role for the root collection', async () => {
const roleAlias = RoleAlias.CURATOR

await expect(useCase.execute(undefined, roleAlias)).resolves.toBeUndefined()
})

test('should throw an error when the collection does not exist', async () => {
const nonExistentCollection = 'nonExistentCollection'
const roleAlias = RoleAlias.CURATOR

await expect(useCase.execute(nonExistentCollection, roleAlias)).rejects.toThrow(WriteError)
})

test('should throw an error when the role alias does not exist', async () => {
const nonExistentRoleAlias = 'invalidRoleAlias'

await expect(useCase.execute(testCollectionAlias, nonExistentRoleAlias)).rejects.toThrow(
WriteError
)
})
})
37 changes: 37 additions & 0 deletions test/unit/collections/CollectionsRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
OrderType,
SortType
} from '../../../src/collections/domain/models/CollectionSearchCriteria'
import { RoleAlias } from '../../../src/roles/domain/models/RoleAlias'

describe('CollectionsRepository', () => {
const sut: CollectionsRepository = new CollectionsRepository()
Expand Down Expand Up @@ -97,6 +98,14 @@ describe('CollectionsRepository', () => {
data: createCollectionPayload()
}
}
const testSetDefaultContributorRoleResponse = {
data: {
status: 'OK',
data: {
message: 'Default contributor role has been set'
}
}
}
const testCollectionModel = createCollectionModel()

beforeEach(() => {
Expand Down Expand Up @@ -893,4 +902,32 @@ describe('CollectionsRepository', () => {
})
})
})

describe('setDefaultContributorRole', () => {
const testRoleAlias = RoleAlias.CURATOR

test('should call the API', async () => {
jest.spyOn(axios, 'put').mockResolvedValue(testSetDefaultContributorRoleResponse)
const expectedApiEndpoint = `${TestConstants.TEST_API_URL}/dataverses/test-collection/defaultContributorRole/${testRoleAlias}`

await sut.setDefaultContributorRole('test-collection', testRoleAlias)

expect(axios.put).toHaveBeenCalledWith(
expectedApiEndpoint,
'{}',
TestConstants.TEST_EXPECTED_AUTHENTICATED_REQUEST_CONFIG_API_KEY
)
})

test('should return error result on error response', async () => {
jest.spyOn(axios, 'put').mockRejectedValue(TestConstants.TEST_ERROR_RESPONSE)
let error = undefined as unknown as WriteError

await sut
.setDefaultContributorRole('test-collection', testRoleAlias)
.catch((e) => (error = e))

expect(error).toBeInstanceOf(Error)
})
})
})
30 changes: 30 additions & 0 deletions test/unit/collections/SetDefaultContributorRole.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository'
import { WriteError } from '../../../src'
import { SetDefaultContributorRole } from '../../../src/collections/domain/useCases/SetDefaultContributorRole'
import { RoleAlias } from '../../../src/roles/domain/models/RoleAlias'

describe('execute', () => {
test('should set default contributor role on repository success', async () => {
const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository
collectionRepositoryStub.setDefaultContributorRole = jest.fn().mockResolvedValue(undefined)
const testSetDefaultContributorRole = new SetDefaultContributorRole(collectionRepositoryStub)

await expect(
testSetDefaultContributorRole.execute(1, RoleAlias.CURATOR)
).resolves.toBeUndefined()
expect(collectionRepositoryStub.setDefaultContributorRole).toHaveBeenCalledWith(1, 'curator')
})

test('should return error result on repository error', async () => {
const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository
collectionRepositoryStub.setDefaultContributorRole = jest
.fn()
.mockRejectedValue(new WriteError())
const testSetDefaultContributorRole = new SetDefaultContributorRole(collectionRepositoryStub)

await expect(testSetDefaultContributorRole.execute(1, RoleAlias.CURATOR)).rejects.toThrow(
WriteError
)
expect(collectionRepositoryStub.setDefaultContributorRole).toHaveBeenCalledWith(1, 'curator')
})
})
Loading