diff --git a/package-lock.json b/package-lock.json index ca858690..65bb9e11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@types/node": "^18.15.11", - "@types/turndown": "5.0.1", + "@types/turndown": "^5.0.1", "axios": "^1.3.4", "turndown": "^7.1.2", "typescript": "^4.9.5" diff --git a/src/core/domain/useCases/UseCase.ts b/src/core/domain/useCases/UseCase.ts index b2580cb0..5e401bf9 100644 --- a/src/core/domain/useCases/UseCase.ts +++ b/src/core/domain/useCases/UseCase.ts @@ -1,3 +1,4 @@ export interface UseCase { + // eslint-disable-next-line @typescript-eslint/no-explicit-any execute(...args: any[]): Promise; } diff --git a/src/core/infra/repositories/ApiRepository.ts b/src/core/infra/repositories/ApiRepository.ts index 84edfce2..1abbb64d 100644 --- a/src/core/infra/repositories/ApiRepository.ts +++ b/src/core/infra/repositories/ApiRepository.ts @@ -10,7 +10,7 @@ import { WriteError } from '../../domain/repositories/WriteError'; For 2.0.0, we must also support API key auth to be backwards compatible and support use cases other than SPA MVP. */ export abstract class ApiRepository { - public async doGet(apiEndpoint: string, withCredentials: boolean = false): Promise { + public async doGet(apiEndpoint: string, withCredentials = false): Promise { return await axios .get(this.buildRequestUrl(apiEndpoint), { withCredentials: withCredentials }) .then((response) => response) diff --git a/src/datasets/domain/models/Dataset.ts b/src/datasets/domain/models/Dataset.ts index 046f4022..53c4874e 100644 --- a/src/datasets/domain/models/Dataset.ts +++ b/src/datasets/domain/models/Dataset.ts @@ -4,7 +4,7 @@ export interface Dataset { versionId: number; versionInfo: DatasetVersionInfo; license?: DatasetLicense; - metadataBlocks: DatasetMetadataBlock[]; + metadataBlocks: DatasetMetadataBlocks; } export interface DatasetVersionInfo { @@ -29,13 +29,151 @@ export interface DatasetLicense { iconUri?: string; } +export type DatasetMetadataBlocks = [CitationMetadataBlock, ...DatasetMetadataBlock[]]; + export interface DatasetMetadataBlock { name: string; fields: DatasetMetadataFields; } +export const ANONYMIZED_FIELD_VALUE = 'withheld'; +type AnonymizedField = typeof ANONYMIZED_FIELD_VALUE; export type DatasetMetadataFields = Record; -export type DatasetMetadataFieldValue = string | string[] | DatasetMetadataSubField | DatasetMetadataSubField[]; +export type DatasetMetadataFieldValue = + | string + | string[] + | DatasetMetadataSubField + | DatasetMetadataSubField[] + | AnonymizedField; export type DatasetMetadataSubField = Record; + +export interface CitationMetadataBlock extends DatasetMetadataBlock { + name: 'citation'; + fields: { + title: string; + author: Author[] | AnonymizedField; + datasetContact: DatasetContact[] | AnonymizedField; + dsDescription: DatasetDescription[] | AnonymizedField; + subject: string[] | AnonymizedField; + subtitle?: string; + alternativeTitle?: string; + alternativeURL?: string; + otherId?: OtherId[] | AnonymizedField; + keyword?: Keyword[] | AnonymizedField; + topicClassification?: TopicClassification[] | AnonymizedField; + publication?: Publication[] | AnonymizedField; + notesText?: string; + language?: string[] | AnonymizedField; + producer?: Producer[] | AnonymizedField; + productionDate?: string; + productionPlace?: string[] | AnonymizedField; + contributor?: Contributor[] | AnonymizedField; + grantNumber?: GrantNumber[] | AnonymizedField; + distributor?: Distributor[] | AnonymizedField; + distributionDate?: string; + depositor?: string; + dateOfDeposit?: string; + timePeriodCovered?: TimePeriodCovered[] | AnonymizedField; + dateOfCollection?: DateOfCollection[] | AnonymizedField; + kindOfData?: string[] | AnonymizedField; + series?: Series[] | AnonymizedField; + software?: Software[] | AnonymizedField; + relatedMaterial?: string[] | AnonymizedField; + relatedDatasets?: string[] | AnonymizedField; + otherReferences?: string[] | AnonymizedField; + dataSources?: string[] | AnonymizedField; + originOfSources?: string; + characteristicOfSources?: string; + accessToSources?: string; + }; +} + +interface OtherId extends DatasetMetadataSubField { + otherIdAgency?: string; + otherIdValue?: string; +} + +export interface Author extends DatasetMetadataSubField { + authorName: string; + authorAffiliation: string; + authorIdentifierScheme?: string; + authorIdentifier?: string; +} + +export interface DatasetContact extends DatasetMetadataSubField { + datasetContactName: string; + datasetContactEmail: string; + datasetContactAffiliation?: string; +} + +export interface DatasetDescription extends DatasetMetadataSubField { + dsDescriptionValue: string; + dsDescriptionDate?: string; +} + +interface Keyword extends DatasetMetadataSubField { + keywordValue?: string; + keywordVocabulary?: string; + keywordVocabularyURI?: string; +} + +interface TopicClassification extends DatasetMetadataSubField { + topicClassValue?: string; + topicClassVocab?: string; + topicClassVocabURI?: string; +} + +interface Publication extends DatasetMetadataSubField { + publicationCitation?: string; + publicationIDType?: string; + publicationIDNumber?: string; + publicationURL?: string; +} + +interface Producer extends DatasetMetadataSubField { + producerName?: string; + producerAffiliation?: string; + producerAbbreviation?: string; + producerURL?: string; + producerLogoURL?: string; +} + +interface Contributor extends DatasetMetadataSubField { + contributorType?: string; + contributorName?: string; +} + +interface GrantNumber extends DatasetMetadataSubField { + grantNumberAgency?: string; + grantNumberValue?: string; +} + +interface Distributor extends DatasetMetadataSubField { + distributorName?: string; + distributorAffiliation?: string; + distributorAbbreviation?: string; + distributorURL?: string; + distributorLogoURL?: string; +} + +interface TimePeriodCovered extends DatasetMetadataSubField { + timePeriodCoveredStart?: string; + timePeriodCoveredEnd?: string; +} + +interface DateOfCollection extends DatasetMetadataSubField { + dateOfCollectionStart?: string; + dateOfCollectionEnd?: string; +} + +interface Series extends DatasetMetadataSubField { + seriesName?: string; + seriesInformation?: string; +} + +interface Software extends DatasetMetadataSubField { + softwareName?: string; + softwareVersion?: string; +} diff --git a/src/datasets/index.ts b/src/datasets/index.ts index 64c39963..90394f78 100644 --- a/src/datasets/index.ts +++ b/src/datasets/index.ts @@ -28,6 +28,7 @@ export { DatasetVersionInfo, DatasetVersionState, DatasetLicense, + DatasetMetadataBlocks, DatasetMetadataBlock, DatasetMetadataFields, DatasetMetadataFieldValue, diff --git a/src/datasets/infra/repositories/transformers/datasetTransformers.ts b/src/datasets/infra/repositories/transformers/datasetTransformers.ts index a678ca70..aeae6f75 100644 --- a/src/datasets/infra/repositories/transformers/datasetTransformers.ts +++ b/src/datasets/infra/repositories/transformers/datasetTransformers.ts @@ -2,10 +2,10 @@ import { Dataset, DatasetVersionState, DatasetMetadataFields, - DatasetMetadataBlock, DatasetMetadataSubField, DatasetMetadataFieldValue, DatasetLicense, + DatasetMetadataBlocks, } from '../../../domain/models/Dataset'; import { AxiosResponse } from 'axios'; import TurndownService from 'turndown'; @@ -16,9 +16,9 @@ export const transformVersionResponseToDataset = (response: AxiosResponse): Data const versionPayload = response.data.data; return transformVersionPayloadToDataset(versionPayload); }; - +// eslint-disable-next-line @typescript-eslint/no-explicit-any const transformVersionPayloadToDataset = (versionPayload: any): Dataset => { - let datasetModel: Dataset = { + const datasetModel: Dataset = { id: versionPayload.datasetId, persistentId: versionPayload.datasetPersistentId, versionId: versionPayload.id, @@ -32,43 +32,44 @@ const transformVersionPayloadToDataset = (versionPayload: any): Dataset => { }, metadataBlocks: transformPayloadToDatasetMetadataBlocks(versionPayload.metadataBlocks), }; - if (versionPayload.hasOwnProperty('license')) { + if ('license' in versionPayload) { datasetModel.license = transformPayloadToDatasetLicense(versionPayload.license); } return datasetModel; }; - +// eslint-disable-next-line @typescript-eslint/no-explicit-any const transformPayloadToDatasetLicense = (licensePayload: any): DatasetLicense => { - let datasetLicense: DatasetLicense = { + const datasetLicense: DatasetLicense = { name: licensePayload.name, uri: licensePayload.uri, }; - if (licensePayload.hasOwnProperty('iconUri')) { + + if ('iconUri' in licensePayload) { datasetLicense.iconUri = licensePayload.iconUri; } return datasetLicense; }; - -const transformPayloadToDatasetMetadataBlocks = (metadataBlocksPayload: any): DatasetMetadataBlock[] => { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const transformPayloadToDatasetMetadataBlocks = (metadataBlocksPayload: any): DatasetMetadataBlocks => { return Object.keys(metadataBlocksPayload).map((metadataBlockKey) => { return { name: metadataBlockKey, fields: transformPayloadToDatasetMetadataFields(metadataBlocksPayload[metadataBlockKey].fields), }; - }); + }) as DatasetMetadataBlocks; }; - +// eslint-disable-next-line @typescript-eslint/no-explicit-any const transformPayloadToDatasetMetadataFields = (metadataFieldsPayload: any): DatasetMetadataFields => { const metadataFieldKeys = Object.keys(metadataFieldsPayload); const metadataFields: DatasetMetadataFields = {}; - for (let metadataFieldKey of metadataFieldKeys) { + for (const metadataFieldKey of metadataFieldKeys) { const metadataField = metadataFieldsPayload[metadataFieldKey]; const metadataFieldTypeName = metadataField.typeName; metadataFields[metadataFieldTypeName] = transformPayloadToDatasetMetadataFieldValue(metadataField.value); } return metadataFields; }; - +// eslint-disable-next-line @typescript-eslint/no-explicit-any const transformPayloadToDatasetMetadataFieldValue = (metadataFieldValuePayload: any): DatasetMetadataFieldValue => { let metadataFieldValue: DatasetMetadataFieldValue; if (Array.isArray(metadataFieldValuePayload)) { @@ -80,7 +81,7 @@ const transformPayloadToDatasetMetadataFieldValue = (metadataFieldValuePayload: metadataFieldValuePayload.forEach(function (metadataSubFieldValuePayload) { const subFieldKeys = Object.keys(metadataSubFieldValuePayload); const record: DatasetMetadataSubField = {}; - for (let subFieldKey of subFieldKeys) { + for (const subFieldKey of subFieldKeys) { record[subFieldKey] = transformHtmlToMarkdown(metadataSubFieldValuePayload[subFieldKey].value); } datasetMetadataSubfields.push(record); diff --git a/test/testHelpers/datasets/datasetHelper.ts b/test/testHelpers/datasets/datasetHelper.ts index c5116f04..6ac30605 100644 --- a/test/testHelpers/datasets/datasetHelper.ts +++ b/test/testHelpers/datasets/datasetHelper.ts @@ -11,7 +11,7 @@ const DATASET_HTML_DESCRIPTION = '

Title 1

Test paragraph 1

Test paragraph 2

Hello world

Title 2

Title 3

'; export const createDatasetModel = (license?: DatasetLicense): Dataset => { - let datasetModel: Dataset = { + const datasetModel: Dataset = { id: 1, persistentId: 'doi:10.5072/FK2/HC6KTB', versionId: 19, @@ -43,6 +43,11 @@ export const createDatasetModel = (license?: DatasetLicense): Dataset => { { dsDescriptionValue: turndownService.turndown(DATASET_HTML_DESCRIPTION), }, + ], datasetContact: [ + { + datasetContactName: 'Admin, Dataverse', + datasetContactEmail: 'someemail@test.com' + }, ], }, }, @@ -55,7 +60,7 @@ export const createDatasetModel = (license?: DatasetLicense): Dataset => { }; export const createDatasetVersionPayload = (license?: DatasetLicense): any => { - let datasetPayload: any = { + const datasetPayload: any = { id: 19, datasetId: 1, datasetPersistentId: 'doi:10.5072/FK2/HC6KTB', @@ -136,6 +141,27 @@ export const createDatasetVersionPayload = (license?: DatasetLicense): any => { }, ], }, + { + typeName: "datasetContact", + multiple: true, + typeClass: "compound", + value: [ + { + datasetContactName: { + typeName: "datasetContactName", + multiple: false, + typeClass: "primitive", + value: 'Admin, Dataverse', + }, + datasetContactEmail: { + typeName: "datasetContactEmail", + multiple: false, + typeClass: "primitive", + value: 'someemail@test.com' + } + } + ] + }, ], }, }, @@ -148,7 +174,7 @@ export const createDatasetVersionPayload = (license?: DatasetLicense): any => { }; export const createDatasetLicenseModel = (withIconUri: boolean = true): DatasetLicense => { - let datasetLicense: DatasetLicense = { + const datasetLicense: DatasetLicense = { name: 'CC0 1.0', uri: 'https://creativecommons.org/publicdomain/zero/1.0/', };