Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
19 changes: 19 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The different use cases currently available in the package are classified below,
- [Get Dataset Versions Summaries](#get-dataset-versions-summaries)
- [Get Dataset Linked Collections](#get-dataset-linked-collections)
- [Get Dataset Available Categories](#get-dataset-available-categories)
- [Get Dataset Templates](#get-dataset-templates)
- [Datasets write use cases](#datasets-write-use-cases)
- [Create a Dataset](#create-a-dataset)
- [Update a Dataset](#update-a-dataset)
Expand Down Expand Up @@ -1110,6 +1111,24 @@ _See [use case](../src/datasets/domain/useCases/GetDatasetAvailableCategories.ts

The `datasetId` parameter is a number for numeric identifiers or string for persistent identifiers.

#### Get Dataset Templates

Returns a [DatasetTemplate](../src/datasets/domain/models/DatasetTemplate.ts) array containing the dataset templates of the requested collection, given the collection identifier or alias.

##### Example call:

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

const collectionIdOrAlias = 12345

getDatasetTemplates.execute(collectionIdOrAlias).then((datasetTemplates: DatasetTemplate[]) => {
/* ... */
})
```

_See [use case](../src/datasets/domain/useCases/GetDatasetTemplates.ts)_ definition.

## Files

### Files read use cases
Expand Down
22 changes: 22 additions & 0 deletions src/datasets/domain/models/DatasetTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { DatasetLicense, DatasetMetadataBlock, TermsOfUse } from './Dataset'

export interface DatasetTemplate {
id: number
name: string
collectionAlias: string
isDefault: boolean
usageCount: number
createTime: string
createDate: string
// 👇 From Edit Template Metadata
datasetMetadataBlocks: DatasetMetadataBlock[]
instructions: DatasetTemplateInstruction[]
// 👇 From Edit Template Terms
termsOfUse: TermsOfUse
license?: DatasetLicense // This license property is going to be present if not custom terms are added in the UI
}

export interface DatasetTemplateInstruction {
instructionField: string
instructionText: string
}
2 changes: 2 additions & 0 deletions src/datasets/domain/repositories/IDatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { DatasetVersionSummaryInfo } from '../models/DatasetVersionSummaryInfo'
import { DatasetLinkedCollection } from '../models/DatasetLinkedCollection'
import { CitationFormat } from '../models/CitationFormat'
import { FormattedCitation } from '../models/FormattedCitation'
import { DatasetTemplate } from '../models/DatasetTemplate'

export interface IDatasetsRepository {
getDataset(
Expand Down Expand Up @@ -74,4 +75,5 @@ export interface IDatasetsRepository {
format: CitationFormat,
includeDeaccessioned?: boolean
): Promise<FormattedCitation>
getDatasetTemplates(collectionIdOrAlias: number | string): Promise<DatasetTemplate[]>
}
25 changes: 25 additions & 0 deletions src/datasets/domain/useCases/GetDatasetTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ROOT_COLLECTION_ID } from '../../../collections/domain/models/Collection'
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { DatasetTemplate } from '../models/DatasetTemplate'
import { IDatasetsRepository } from '../repositories/IDatasetsRepository'

export class GetDatasetTemplates implements UseCase<DatasetTemplate[]> {
private datasetsRepository: IDatasetsRepository

constructor(datasetsRepository: IDatasetsRepository) {
this.datasetsRepository = datasetsRepository
}

/**
* Returns a DatasetTemplate array containing the dataset templates of the requested collection, given the collection identifier or alias.
*
* @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'
* @returns {Promise<DatasetTemplate[]>}
*/
async execute(
collectionIdOrAlias: number | string = ROOT_COLLECTION_ID
): Promise<DatasetTemplate[]> {
return await this.datasetsRepository.getDatasetTemplates(collectionIdOrAlias)
}
}
5 changes: 4 additions & 1 deletion src/datasets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { UnlinkDataset } from './domain/useCases/UnlinkDataset'
import { GetDatasetLinkedCollections } from './domain/useCases/GetDatasetLinkedCollections'
import { GetDatasetAvailableCategories } from './domain/useCases/GetDatasetAvailableCategories'
import { GetDatasetCitationInOtherFormats } from './domain/useCases/GetDatasetCitationInOtherFormats'
import { GetDatasetTemplates } from './domain/useCases/GetDatasetTemplates'

const datasetsRepository = new DatasetsRepository()

Expand Down Expand Up @@ -64,6 +65,7 @@ const unlinkDataset = new UnlinkDataset(datasetsRepository)
const getDatasetLinkedCollections = new GetDatasetLinkedCollections(datasetsRepository)
const getDatasetAvailableCategories = new GetDatasetAvailableCategories(datasetsRepository)
const getDatasetCitationInOtherFormats = new GetDatasetCitationInOtherFormats(datasetsRepository)
const getDatasetTemplates = new GetDatasetTemplates(datasetsRepository)

export {
getDataset,
Expand All @@ -86,7 +88,8 @@ export {
unlinkDataset,
getDatasetLinkedCollections,
getDatasetAvailableCategories,
getDatasetCitationInOtherFormats
getDatasetCitationInOtherFormats,
getDatasetTemplates
}
export { DatasetNotNumberedVersion } from './domain/models/DatasetNotNumberedVersion'
export { DatasetUserPermissions } from './domain/models/DatasetUserPermissions'
Expand Down
16 changes: 16 additions & 0 deletions src/datasets/infra/repositories/DatasetsRepository.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AxiosResponse } from 'axios'
import { ApiRepository } from '../../../core/infra/repositories/ApiRepository'
import { IDatasetsRepository } from '../../domain/repositories/IDatasetsRepository'
import { Dataset, VersionUpdateType } from '../../domain/models/Dataset'
Expand All @@ -24,6 +25,9 @@ import { DatasetLinkedCollection } from '../../domain/models/DatasetLinkedCollec
import { CitationFormat } from '../../domain/models/CitationFormat'
import { transformDatasetLinkedCollectionsResponseToDatasetLinkedCollection } from './transformers/datasetLinkedCollectionsTransformers'
import { FormattedCitation } from '../../domain/models/FormattedCitation'
import { DatasetTemplate } from '../../domain/models/DatasetTemplate'
import { DatasetTemplatePayload } from './transformers/DatasetTemplatePayload'
import { transformDatasetTemplatePayloadToDatasetTemplate } from './transformers/datasetTemplateTransformers'

export interface GetAllDatasetPreviewsQueryParams {
per_page?: number
Expand Down Expand Up @@ -357,4 +361,16 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
throw error
})
}

public async getDatasetTemplates(
collectionIdOrAlias: number | string
): Promise<DatasetTemplate[]> {
return this.doGet(`/dataverses/${collectionIdOrAlias}/templates`, true)
.then((response: AxiosResponse<{ data: DatasetTemplatePayload[] }>) =>
transformDatasetTemplatePayloadToDatasetTemplate(response.data.data)
)
.catch((error) => {
throw error
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { MetadataFieldPayload } from './DatasetPayload'

export interface DatasetTemplatePayload {
id: number
name: string
dataverseAlias: string
isDefault: boolean
usageCount: number
createTime: string
createDate: string
// 👇 From Edit Template Metadata
datasetFields: DatasetFieldsPayload
instructions: Instruction[]
// 👇 From Edit Template Terms
termsOfUseAndAccess: {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we may need a separate interface for TermsOfUseAndAccess, based on dataverse TermsOfUseAndAccess? We could make changes on this part until we implement the use case of edit terms

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here as comment above, this is the payload, after the mapping I'm using the already there TermsOfUse model.

id: number
fileAccessRequest: boolean
// This license property is going to be present if not custom terms are added in the UI
license?: {
Comment thread
g-saracca marked this conversation as resolved.
Outdated
id: number
name: string
shortDescription: string
uri: string
iconUrl?: string
active: boolean
isDefault: boolean
sortOrder: number
rightsIdentifier: string
rightsIdentifierScheme?: string
schemeUri: string
languageCode: string
}
// Below fields are going to be present if are added in "Restricted Files + Terms of Access"
termsOfAccess?: string // This is terms of access for restricted files in the JSF UI
dataAccessPlace?: string
originalArchive?: string
availabilityStatus?: string
sizeOfCollection?: string
studyCompletion?: string
contactForAccess?: string
// Below fields are going to be present if custom terms are added in the UI, they will be mapped and grouped under customTerms
termsOfUse?: string
confidentialityDeclaration?: string
specialPermissions?: string
restrictions?: string
citationRequirements?: string
depositorRequirements?: string
conditions?: string
disclaimer?: string
}
}

type DatasetFieldsPayload = Record<string, DatasetFieldInfoPayload>

interface DatasetFieldInfoPayload {
displayName: string
name: string
fields: MetadataFieldPayload[]
}

interface Instruction {
instructionField: string
instructionText: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { DatasetTemplate } from '../../../domain/models/DatasetTemplate'
import { DatasetTemplatePayload } from './DatasetTemplatePayload'
import { transformPayloadToDatasetMetadataBlocks } from './datasetTransformers'

export const transformDatasetTemplatePayloadToDatasetTemplate = (
collectionDatasetTemplatePayload: DatasetTemplatePayload[]
): DatasetTemplate[] => {
return collectionDatasetTemplatePayload.map((payload) => {
const datasetTemplate: DatasetTemplate = {
id: payload.id,
name: payload.name,
collectionAlias: payload.dataverseAlias,
isDefault: payload.isDefault,
usageCount: payload.usageCount,
createTime: payload.createTime,
createDate: payload.createDate,
datasetMetadataBlocks: transformPayloadToDatasetMetadataBlocks(payload.datasetFields, false),
instructions: payload.instructions.map((instruction) => ({
instructionField: instruction.instructionField,
instructionText: instruction.instructionText
})),
termsOfUse: {
termsOfAccess: {
fileAccessRequest: payload.termsOfUseAndAccess.fileAccessRequest,
termsOfAccessForRestrictedFiles: payload.termsOfUseAndAccess.termsOfAccess,
dataAccessPlace: payload.termsOfUseAndAccess.dataAccessPlace,
originalArchive: payload.termsOfUseAndAccess.originalArchive,
availabilityStatus: payload.termsOfUseAndAccess.availabilityStatus,
contactForAccess: payload.termsOfUseAndAccess.contactForAccess,
sizeOfCollection: payload.termsOfUseAndAccess.sizeOfCollection,
studyCompletion: payload.termsOfUseAndAccess.studyCompletion
}
}
}

if (payload.termsOfUseAndAccess.license) {
datasetTemplate.license = {
name: payload.termsOfUseAndAccess.license.name,
uri: payload.termsOfUseAndAccess.license.uri,
iconUri: payload.termsOfUseAndAccess.license.iconUrl
}
} else {
datasetTemplate.termsOfUse.customTerms = {
termsOfUse: payload.termsOfUseAndAccess.termsOfUse as string,
confidentialityDeclaration: payload.termsOfUseAndAccess
.confidentialityDeclaration as string,
specialPermissions: payload.termsOfUseAndAccess.specialPermissions as string,
restrictions: payload.termsOfUseAndAccess.restrictions as string,
citationRequirements: payload.termsOfUseAndAccess.citationRequirements as string,
depositorRequirements: payload.termsOfUseAndAccess.depositorRequirements as string,
conditions: payload.termsOfUseAndAccess.conditions as string,
disclaimer: payload.termsOfUseAndAccess.disclaimer as string
}
}

return datasetTemplate
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ const transformPayloadText = (
return keepRawFields ? text : transformHtmlToMarkdown(text)
}

const transformPayloadToDatasetMetadataBlocks = (
export const transformPayloadToDatasetMetadataBlocks = (
metadataBlocksPayload: MetadataBlocksPayload,
keepRawFields: boolean
): DatasetMetadataBlocks => {
Expand Down
39 changes: 39 additions & 0 deletions test/integration/datasets/DatasetsRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
import { DirectUploadClient } from '../../../src/files/infra/clients/DirectUploadClient'
import { createTestFileUploadDestination } from '../../testHelpers/files/fileUploadDestinationHelper'
import { CitationFormat } from '../../../src/datasets/domain/models/CitationFormat'
import {
createDatasetTemplateViaApi,
deleteDatasetTemplateViaApi
} from '../../testHelpers/datasets/datasetTemplatesHelper'

const TEST_DIFF_DATASET_DTO: DatasetDTO = {
license: {
Expand Down Expand Up @@ -1063,7 +1067,7 @@
])
})
// TODO: add this test when https://github.com/IQSS/dataverse-client-javascript/issues/343 is fixed
test.skip('should throw error if trying to update an outdated internal version dataset', async () => {

Check warning on line 1070 in test/integration/datasets/DatasetsRepository.test.ts

View workflow job for this annotation

GitHub Actions / lint

Disabled test
const testDataset = {
metadataBlockValues: [
{
Expand Down Expand Up @@ -1649,4 +1653,39 @@
await expect(sut.getDatasetAvailableCategories(nonExistentTestDatasetId)).rejects.toThrow()
})
})

describe('getDatasetTemplates', () => {
const testCollectionAlias = 'testGetDatasetTemplates'

beforeAll(async () => {
await createCollectionViaApi(testCollectionAlias)
})

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

test('should return empty dataset templates', async () => {
const actual = await sut.getDatasetTemplates(testCollectionAlias)

expect(actual.length).toBe(0)
})

test('should return dataset templates for a collection', async () => {
const templateCreated = await createDatasetTemplateViaApi(testCollectionAlias)

const actual = await sut.getDatasetTemplates(testCollectionAlias)

expect(actual.length).toBe(1)

expect(actual[0].name).toBe(templateCreated.name)
expect(actual[0].isDefault).toBe(templateCreated.isDefault)
expect(actual[0].datasetMetadataBlocks.length).toBe(1)
expect(actual[0].datasetMetadataBlocks[0].name).toBe('citation')
expect(actual[0].datasetMetadataBlocks[0].fields.author.length).toBe(1)
expect(actual[0].instructions.length).toBe(templateCreated.instructions.length)

await deleteDatasetTemplateViaApi(actual[0].id)
})
})
})
Loading