From d9589acdf5d6b2e81aadcc682663c2e934bc0b86 Mon Sep 17 00:00:00 2001 From: fpotier Date: Wed, 21 Jan 2026 15:26:52 +0000 Subject: [PATCH 1/6] feat(publisheddata): automatically add issued date to datacite record --- src/published-data/published-data.v4.controller.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 6f25c91dc..4d53752ce 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -26,6 +26,7 @@ import { } from "@nestjs/swagger"; import { Request } from "express"; import { Validator } from "jsonschema"; +import { isArray } from "lodash"; import { FilterQuery, QueryOptions } from "mongoose"; import { firstValueFrom } from "rxjs"; import { AttachmentsService } from "src/attachments/attachments.service"; @@ -574,6 +575,17 @@ export class PublishedDataV4Controller { publishedData.registeredTime = data.registeredTime; publishedData.status = data.status; + if ( + isArray(publishedData.metadata?.dates) && + !publishedData.metadata.dates.some( + (d) => d.hasOwnProperty("dateType") && d.dateType === "Issued", + ) + ) { + publishedData.metadata.dates.push({ + date: data.registeredTime, + dateType: "Issued", + }); + } await this.validateMetadata(publishedData.metadata); From b968bc09fc1f82865096469a3aa7c0dab80f0412 Mon Sep 17 00:00:00 2001 From: fpotier Date: Wed, 21 Jan 2026 15:44:45 +0000 Subject: [PATCH 2/6] add test case --- .../published-data.v4.controller.ts | 20 ++++++++++++++----- test/jest-e2e-tests/publishedData.e2e-spec.ts | 8 ++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 4d53752ce..775a9ebb2 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -575,16 +575,22 @@ export class PublishedDataV4Controller { publishedData.registeredTime = data.registeredTime; publishedData.status = data.status; + + const issuedDate = { + date: data.registeredTime.toISOString(), + dateType: "Issued", + }; + + if (!publishedData.metadata) publishedData.metadata = {}; + publishedData.metadata.dates = publishedData.metadata.dates ?? []; + if ( isArray(publishedData.metadata?.dates) && !publishedData.metadata.dates.some( (d) => d.hasOwnProperty("dateType") && d.dateType === "Issued", ) ) { - publishedData.metadata.dates.push({ - date: data.registeredTime, - dateType: "Issued", - }); + publishedData.metadata.dates.push(issuedDate); } await this.validateMetadata(publishedData.metadata); @@ -645,7 +651,11 @@ export class PublishedDataV4Controller { const res = await this.publishedDataService.update( { doi: publishedData.doi }, - { status: PublishedDataStatus.REGISTERED, registeredTime: new Date() }, + { + status: PublishedDataStatus.REGISTERED, + registeredTime: publishedData.registeredTime, + metadata: publishedData.metadata, + }, ); return res; diff --git a/test/jest-e2e-tests/publishedData.e2e-spec.ts b/test/jest-e2e-tests/publishedData.e2e-spec.ts index e4ab81a91..84dd9fe5f 100644 --- a/test/jest-e2e-tests/publishedData.e2e-spec.ts +++ b/test/jest-e2e-tests/publishedData.e2e-spec.ts @@ -86,6 +86,14 @@ describe.each([undefined, "", "https://api.test.datacite.org/dois"])( .then((res) => { expect(res.body.status).toEqual("registered"); expect(res.body.registeredTime).toBeDefined(); + expect(res.body.metadata.dates).toBeDefined(); + expect(Array.isArray(res.body.metadata.dates)).toBe(true); + expect(res.body.metadata.dates.length).toBeGreaterThan(0); + const issuedDate = res.body.metadata.dates.filter( + (d: { dateType: string }) => d.dateType === "Issued", + ); + expect(issuedDate.length).toBe(1); + expect(issuedDate[0].date).toEqual(res.body.registeredTime); }); }); From 13511fc526390ed147b7d77aac16f6c25ce1c7b0 Mon Sep 17 00:00:00 2001 From: fpotier Date: Thu, 22 Jan 2026 13:12:39 +0000 Subject: [PATCH 3/6] prevent this from breaking validation if schema doesn't support dc dates --- eslint.config.mjs | 11 +++-- .../published-data.v4.controller.ts | 47 ++++++++++++------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 7262a459b..bcde122a4 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,10 +1,10 @@ +import { FlatCompat } from "@eslint/eslintrc"; +import js from "@eslint/js"; import typescriptEslintEslintPlugin from "@typescript-eslint/eslint-plugin"; -import globals from "globals"; import tsParser from "@typescript-eslint/parser"; +import globals from "globals"; import path from "node:path"; import { fileURLToPath } from "node:url"; -import js from "@eslint/js"; -import { FlatCompat } from "@eslint/eslintrc"; const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); @@ -74,7 +74,10 @@ export default [ "@typescript-eslint/no-unused-vars": [ "warn", - { "argsIgnorePattern": "^_" }, + { + "argsIgnorePattern": "^_" , + "caughtErrorsIgnorePattern": "^_" + }, ], }, }, diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 775a9ebb2..78076b214 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -26,7 +26,7 @@ import { } from "@nestjs/swagger"; import { Request } from "express"; import { Validator } from "jsonschema"; -import { isArray } from "lodash"; +import { cloneDeep, isArray } from "lodash"; import { FilterQuery, QueryOptions } from "mongoose"; import { firstValueFrom } from "rxjs"; import { AttachmentsService } from "src/attachments/attachments.service"; @@ -576,24 +576,8 @@ export class PublishedDataV4Controller { publishedData.registeredTime = data.registeredTime; publishedData.status = data.status; - const issuedDate = { - date: data.registeredTime.toISOString(), - dateType: "Issued", - }; - - if (!publishedData.metadata) publishedData.metadata = {}; - publishedData.metadata.dates = publishedData.metadata.dates ?? []; - - if ( - isArray(publishedData.metadata?.dates) && - !publishedData.metadata.dates.some( - (d) => d.hasOwnProperty("dateType") && d.dateType === "Issued", - ) - ) { - publishedData.metadata.dates.push(issuedDate); - } - await this.validateMetadata(publishedData.metadata); + await this.tryAddDateIssued(publishedData, publishedData.registeredTime); await Promise.all( publishedData.datasetPids.map(async (pid) => { @@ -805,4 +789,31 @@ export class PublishedDataV4Controller { return registrationData; } + + private async tryAddDateIssued( + publishedData: PublishedData, + registeredTime: Date, + ) { + const originalMetadata = cloneDeep(publishedData.metadata); + try { + if (!publishedData.metadata) publishedData.metadata = {}; + publishedData.metadata.dates = publishedData.metadata.dates ?? []; + + if ( + isArray(publishedData.metadata.dates) && + !publishedData.metadata.dates.some( + (d) => d.hasOwnProperty("dateType") && d.dateType === "Issued", + ) + ) { + publishedData.metadata.dates.push({ + date: registeredTime.toISOString(), + dateType: "Issued", + }); + } + await this.validateMetadata(publishedData.metadata); + } catch (_validationError) { + // Restore original metadata if schema doesn't support DataCite dates + publishedData.metadata = originalMetadata; + } + } } From 2156202c9411dc12932d22c1acc986fe05526168 Mon Sep 17 00:00:00 2001 From: fpotier Date: Thu, 22 Jan 2026 14:22:31 +0000 Subject: [PATCH 4/6] test exact date count --- test/jest-e2e-tests/publishedData.e2e-spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jest-e2e-tests/publishedData.e2e-spec.ts b/test/jest-e2e-tests/publishedData.e2e-spec.ts index 84dd9fe5f..9e84119a8 100644 --- a/test/jest-e2e-tests/publishedData.e2e-spec.ts +++ b/test/jest-e2e-tests/publishedData.e2e-spec.ts @@ -88,7 +88,7 @@ describe.each([undefined, "", "https://api.test.datacite.org/dois"])( expect(res.body.registeredTime).toBeDefined(); expect(res.body.metadata.dates).toBeDefined(); expect(Array.isArray(res.body.metadata.dates)).toBe(true); - expect(res.body.metadata.dates.length).toBeGreaterThan(0); + expect(res.body.metadata.dates.length).toBe(1); const issuedDate = res.body.metadata.dates.filter( (d: { dateType: string }) => d.dateType === "Issued", ); From 3add1a208bee39330de9c1099de5daf54fac17e5 Mon Sep 17 00:00:00 2001 From: fpotier Date: Thu, 22 Jan 2026 14:29:02 +0000 Subject: [PATCH 5/6] remove unnecessary property existence check --- src/published-data/published-data.v4.controller.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 78076b214..1a8297735 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -801,9 +801,7 @@ export class PublishedDataV4Controller { if ( isArray(publishedData.metadata.dates) && - !publishedData.metadata.dates.some( - (d) => d.hasOwnProperty("dateType") && d.dateType === "Issued", - ) + !publishedData.metadata.dates.some((d) => d.dateType === "Issued") ) { publishedData.metadata.dates.push({ date: registeredTime.toISOString(), From 0c91d97546e55fed47b1eae4cedde8d245bd2e0f Mon Sep 17 00:00:00 2001 From: fpotier Date: Thu, 22 Jan 2026 14:44:30 +0000 Subject: [PATCH 6/6] log if validation fails after adding the date issued --- eslint.config.mjs | 11 ++++------- src/published-data/published-data.v4.controller.ts | 4 +++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index bcde122a4..7262a459b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,10 +1,10 @@ -import { FlatCompat } from "@eslint/eslintrc"; -import js from "@eslint/js"; import typescriptEslintEslintPlugin from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; import globals from "globals"; +import tsParser from "@typescript-eslint/parser"; import path from "node:path"; import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); @@ -74,10 +74,7 @@ export default [ "@typescript-eslint/no-unused-vars": [ "warn", - { - "argsIgnorePattern": "^_" , - "caughtErrorsIgnorePattern": "^_" - }, + { "argsIgnorePattern": "^_" }, ], }, }, diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 1a8297735..e22aa54a6 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -6,6 +6,7 @@ import { Get, HttpException, HttpStatus, + Logger, NotFoundException, Param, Patch, @@ -809,9 +810,10 @@ export class PublishedDataV4Controller { }); } await this.validateMetadata(publishedData.metadata); - } catch (_validationError) { + } catch (validationError) { // Restore original metadata if schema doesn't support DataCite dates publishedData.metadata = originalMetadata; + Logger.warn(validationError, "failed to add data issued to metadata"); } } }