Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

122 - Extend dataset and file models to contain owner information #127

14 changes: 14 additions & 0 deletions src/core/domain/models/DvObjectOwnerNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface DvObjectOwnerNode {
type: DvObjectType;
displayName: string;
identifier: string;
persistentIdentifier?: string;
version?: string;
isPartOf?: DvObjectOwnerNode;
}

export enum DvObjectType {
DATAVERSE = 'DATAVERSE',
DATASET = 'DATASET',
FILE = 'FILE',
}
1 change: 1 addition & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { ReadError } from './domain/repositories/ReadError';
export { WriteError } from './domain/repositories/WriteError';
export { ApiConfig } from './infra/repositories/ApiConfig';
export { DvObjectOwnerNode, DvObjectType } from './domain/models/DvObjectOwnerNode';
8 changes: 8 additions & 0 deletions src/core/infra/repositories/transformers/OwnerNodePayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface OwnerNodePayload {
type: string;
displayName: string;
identifier: string;
persistentIdentifier?: string;
version?: string;
isPartOf?: OwnerNodePayload;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { OwnerNodePayload } from './OwnerNodePayload';
import { DvObjectOwnerNode, DvObjectType } from '../../../domain/models/DvObjectOwnerNode';

export const transformPayloadToOwnerNode = (ownerNodePayload: OwnerNodePayload): DvObjectOwnerNode => {
return {
type: ownerNodePayload.type as DvObjectType,
displayName: ownerNodePayload.displayName,
identifier: ownerNodePayload.identifier,
...(ownerNodePayload.persistentIdentifier && {
persistentIdentifier: ownerNodePayload.persistentIdentifier,
}),
...(ownerNodePayload.version && { version: ownerNodePayload.version }),
...(ownerNodePayload.isPartOf && { isPartOf: transformPayloadToOwnerNode(ownerNodePayload.isPartOf) }),
};
};
3 changes: 3 additions & 0 deletions src/datasets/domain/models/Dataset.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DvObjectOwnerNode } from '../../../core/domain/models/DvObjectOwnerNode';

export interface Dataset {
id: number;
persistentId: string;
Expand All @@ -8,6 +10,7 @@ export interface Dataset {
publicationDate?: string;
citationDate?: string;
metadataBlocks: DatasetMetadataBlocks;
isPartOf: DvObjectOwnerNode;
}

export interface DatasetVersionInfo {
Expand Down
5 changes: 4 additions & 1 deletion src/datasets/infra/repositories/DatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
}

public async getPrivateUrlDataset(token: string): Promise<Dataset> {
return this.doGet(this.buildApiEndpoint(this.datasetsResourceName, `privateUrlDatasetVersion/${token}`))
return this.doGet(this.buildApiEndpoint(this.datasetsResourceName, `privateUrlDatasetVersion/${token}`), false, {
returnOwners: true,
})
.then((response) => transformVersionResponseToDataset(response))
.catch((error) => {
throw error;
Expand All @@ -49,6 +51,7 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
{
includeDeaccessioned: includeDeaccessioned,
excludeFiles: true,
returnOwners: true,
},
)
.then((response) => transformVersionResponseToDataset(response))
Expand Down
53 changes: 53 additions & 0 deletions src/datasets/infra/repositories/transformers/DatasetPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { FilePayload } from '../../../../files/infra/repositories/transformers/FilePayload';
import { OwnerNodePayload } from '../../../../core/infra/repositories/transformers/OwnerNodePayload';

export interface DatasetPayload {
datasetId: number;
datasetPersistentId: string;
id: number;
versionNumber: number;
versionMinorNumber: number;
versionState: string;
createTime: string;
lastUpdateTime: string;
releaseTime: string;
metadataBlocks: MetadataBlocksPayload;
license?: LicensePayload;
alternativePersistentId?: string;
publicationDate?: string;
citationDate?: string;
files: FilePayload[];
isPartOf: OwnerNodePayload;
}

export interface LicensePayload {
name: string;
uri: string;
iconUri?: string;
}

export interface MetadataBlocksPayload {
[blockName: string]: MetadataBlockPayload;
}

export interface MetadataBlockPayload {
name: string;
fields: MetadataFieldPayload[];
}

export interface MetadataFieldPayload {
typeName: string;
value: MetadataFieldValuePayload;
typeClass: string;
multiple: boolean;
}

export type MetadataFieldValuePayload =
| string
| string[]
| MetadataSubfieldValuePayload
| MetadataSubfieldValuePayload[];

export interface MetadataSubfieldValuePayload {
[key: string]: { value: string; typeName: string; multiple: boolean; typeClass: string };
}
108 changes: 71 additions & 37 deletions src/datasets/infra/repositories/transformers/datasetTransformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,26 @@ import {
DatasetMetadataFieldValue,
DatasetLicense,
DatasetMetadataBlocks,
ANONYMIZED_FIELD_VALUE,
} from '../../../domain/models/Dataset';
import { AxiosResponse } from 'axios';
import {
DatasetPayload,
LicensePayload,
MetadataBlocksPayload,
MetadataSubfieldValuePayload,
MetadataFieldPayload,
MetadataFieldValuePayload,
} from './DatasetPayload';
import { transformPayloadToOwnerNode } from '../../../../core/infra/repositories/transformers/dvObjectOwnerNodeTransformer';
import { NodeHtmlMarkdown } from 'node-html-markdown';

export const transformVersionResponseToDataset = (response: AxiosResponse): Dataset => {
const versionPayload = response.data.data;
return transformVersionPayloadToDataset(versionPayload);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transformVersionPayloadToDataset = (versionPayload: any): Dataset => {

const transformVersionPayloadToDataset = (versionPayload: DatasetPayload): Dataset => {
const datasetModel: Dataset = {
id: versionPayload.datasetId,
persistentId: versionPayload.datasetPersistentId,
Expand All @@ -29,6 +39,7 @@ const transformVersionPayloadToDataset = (versionPayload: any): Dataset => {
releaseTime: new Date(versionPayload.releaseTime),
},
metadataBlocks: transformPayloadToDatasetMetadataBlocks(versionPayload.metadataBlocks),
isPartOf: transformPayloadToOwnerNode(versionPayload.isPartOf),
};
if ('license' in versionPayload) {
datasetModel.license = transformPayloadToDatasetLicense(versionPayload.license);
Expand All @@ -44,8 +55,8 @@ const transformVersionPayloadToDataset = (versionPayload: any): Dataset => {
}
return datasetModel;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transformPayloadToDatasetLicense = (licensePayload: any): DatasetLicense => {

const transformPayloadToDatasetLicense = (licensePayload: LicensePayload): DatasetLicense => {
const datasetLicense: DatasetLicense = {
name: licensePayload.name,
uri: licensePayload.uri,
Expand All @@ -56,49 +67,72 @@ const transformPayloadToDatasetLicense = (licensePayload: any): DatasetLicense =
}
return datasetLicense;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transformPayloadToDatasetMetadataBlocks = (metadataBlocksPayload: any): DatasetMetadataBlocks => {

const transformPayloadToDatasetMetadataBlocks = (
metadataBlocksPayload: MetadataBlocksPayload,
): DatasetMetadataBlocks => {
return Object.keys(metadataBlocksPayload).map((metadataBlockKey) => {
const metadataBlock = metadataBlocksPayload[metadataBlockKey];
return {
name: metadataBlockKey,
fields: transformPayloadToDatasetMetadataFields(metadataBlocksPayload[metadataBlockKey].fields),
name: metadataBlock.name,
fields: transformPayloadToDatasetMetadataFields(metadataBlock.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 (const metadataFieldKey of metadataFieldKeys) {
const metadataField = metadataFieldsPayload[metadataFieldKey];
const metadataFieldTypeName = metadataField.typeName;
metadataFields[metadataFieldTypeName] = transformPayloadToDatasetMetadataFieldValue(metadataField.value);
}
return metadataFields;

const transformPayloadToDatasetMetadataFields = (
metadataFieldsPayload: MetadataFieldPayload[],
): DatasetMetadataFields => {
return metadataFieldsPayload.reduce(
(datasetMetadataFieldsMap: DatasetMetadataFields, field: MetadataFieldPayload) => {
datasetMetadataFieldsMap[field.typeName] = transformPayloadToDatasetMetadataFieldValue(
field.value,
field.typeClass,
);
return datasetMetadataFieldsMap;
},
{},
);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transformPayloadToDatasetMetadataFieldValue = (metadataFieldValuePayload: any): DatasetMetadataFieldValue => {
let metadataFieldValue: DatasetMetadataFieldValue;
if (Array.isArray(metadataFieldValuePayload)) {
const isArrayOfObjects = typeof metadataFieldValuePayload[0] === 'object';
if (!isArrayOfObjects) {
metadataFieldValue = metadataFieldValuePayload.map(transformHtmlToMarkdown);

const transformPayloadToDatasetMetadataFieldValue = (
metadataFieldValuePayload: MetadataFieldValuePayload,
typeClass: string,
): DatasetMetadataFieldValue => {
function isArrayOfSubfieldValue(
array: (string | MetadataSubfieldValuePayload)[],
): array is MetadataSubfieldValuePayload[] {
return array.length > 0 && typeof array[0] !== 'string';
}

if (typeClass === 'anonymized') {
return ANONYMIZED_FIELD_VALUE;
}

if (typeof metadataFieldValuePayload === 'string') {
return transformHtmlToMarkdown(metadataFieldValuePayload);
} else if (Array.isArray(metadataFieldValuePayload)) {
if (isArrayOfSubfieldValue(metadataFieldValuePayload)) {
return metadataFieldValuePayload.map((metadataSubfieldValuePayload) =>
transformPayloadToDatasetMetadataSubfieldValue(metadataSubfieldValuePayload),
);
} else {
const datasetMetadataSubfields: DatasetMetadataSubField[] = [];
metadataFieldValuePayload.forEach(function (metadataSubFieldValuePayload) {
const subFieldKeys = Object.keys(metadataSubFieldValuePayload);
const record: DatasetMetadataSubField = {};
for (const subFieldKey of subFieldKeys) {
record[subFieldKey] = transformHtmlToMarkdown(metadataSubFieldValuePayload[subFieldKey].value);
}
datasetMetadataSubfields.push(record);
});
metadataFieldValue = datasetMetadataSubfields;
return metadataFieldValuePayload.map(transformHtmlToMarkdown);
}
} else {
metadataFieldValue = transformHtmlToMarkdown(metadataFieldValuePayload);
return transformPayloadToDatasetMetadataSubfieldValue(metadataFieldValuePayload as MetadataSubfieldValuePayload);
}
return metadataFieldValue;
};

const transformPayloadToDatasetMetadataSubfieldValue = (
metadataSubfieldValuePayload: MetadataSubfieldValuePayload,
): DatasetMetadataSubField => {
const result: DatasetMetadataSubField = {};
Object.keys(metadataSubfieldValuePayload).forEach((key) => {
const subFieldValue = metadataSubfieldValuePayload[key].value;
result[key] = transformHtmlToMarkdown(subFieldValue);
});
return result;
};

const transformHtmlToMarkdown = (source: string): string => {
Expand Down
3 changes: 3 additions & 0 deletions src/files/domain/models/File.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DvObjectOwnerNode } from '../../../core/domain/models/DvObjectOwnerNode';

export interface File {
id: number;
persistentId: string;
Expand Down Expand Up @@ -31,6 +33,7 @@ export interface File {
deleted: boolean;
tabularData: boolean;
fileAccessRequest?: boolean;
isPartOf?: DvObjectOwnerNode;
}

export interface FileEmbargo {
Expand Down
4 changes: 3 additions & 1 deletion src/files/infra/repositories/FilesRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ export class FilesRepository extends ApiRepository implements IFilesRepository {
}

public async getFile(fileId: number | string, datasetVersionId: string): Promise<File> {
return this.doGet(this.buildApiEndpoint(this.filesResourceName, `versions/${datasetVersionId}`, fileId), true)
return this.doGet(this.buildApiEndpoint(this.filesResourceName, `versions/${datasetVersionId}`, fileId), true, {
returnOwners: true,
})
.then((response) => transformFileResponseToFile(response))
.catch((error) => {
throw error;
Expand Down
52 changes: 52 additions & 0 deletions src/files/infra/repositories/transformers/FilePayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { OwnerNodePayload } from '../../../../core/infra/repositories/transformers/OwnerNodePayload';

export interface FilePayload {
dataFile: {
id: number;
persistentId: string;
filename: string;
pidURL?: string;
filesize: number;
version: number;
description?: string;
restricted: boolean;
directoryLabel?: string;
datasetVersionId?: number;
categories?: string[];
contentType: string;
friendlyType: string;
embargo?: EmbargoPayload;
storageIdentifier?: string;
originalFormat?: string;
originalFormatLabel?: string;
originalSize?: number;
originalName?: string;
UNF?: string;
rootDataFileId?: number;
previousDataFileId?: number;
md5?: string;
checksum?: ChecksumPayload;
fileMetadataId?: number;
tabularTags?: string[];
creationDate?: string;
publicationDate?: string;
deleted: boolean;
tabularData: boolean;
fileAccessRequest?: boolean;
isPartOf?: OwnerNodePayload;
};
version: number;
restricted: boolean;
label: string;
datasetVersionId: number;
}

export interface EmbargoPayload {
dateAvailable: string;
reason?: string;
}

export interface ChecksumPayload {
type: string;
value: string;
}
Loading
Loading