diff --git a/package-lock.json b/package-lock.json index 1b44aea86..49030f55b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13451,7 +13451,7 @@ }, "packages/content": { "name": "@nmshd/content", - "version": "2.8.5", + "version": "2.8.6", "license": "MIT", "dependencies": { "@js-soft/logging-abstractions": "^1.0.1", @@ -13475,7 +13475,7 @@ }, "packages/runtime": { "name": "@nmshd/runtime", - "version": "4.1.2", + "version": "4.1.3", "license": "MIT", "dependencies": { "@js-soft/docdb-querytranslator": "^1.1.2", @@ -13483,7 +13483,7 @@ "@js-soft/ts-serval": "2.0.10", "@js-soft/ts-utils": "^2.3.3", "@nmshd/consumption": "3.9.3", - "@nmshd/content": "2.8.5", + "@nmshd/content": "2.8.6", "@nmshd/crypto": "2.0.6", "@nmshd/transport": "2.3.1", "ajv": "^8.12.0", diff --git a/packages/content/package.json b/packages/content/package.json index 9a8eb499a..e6e36de5a 100644 --- a/packages/content/package.json +++ b/packages/content/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/content", - "version": "2.8.5", + "version": "2.8.6", "description": "The content library defines data structures that can be transmitted using the transport library.", "homepage": "https://enmeshed.eu", "repository": { diff --git a/packages/content/src/ValidationErrorWithoutProperty.ts b/packages/content/src/ValidationErrorWithoutProperty.ts new file mode 100644 index 000000000..af6f0a22f --- /dev/null +++ b/packages/content/src/ValidationErrorWithoutProperty.ts @@ -0,0 +1,9 @@ +import { ValidationError } from "@js-soft/ts-serval"; + +export class ValidationErrorWithoutProperty extends ValidationError { + public constructor(type: string, reason: string, cause?: Error) { + super(type, "n/a", reason, cause); + + this.message = `${type} :: ${reason}`; + } +} diff --git a/packages/content/src/attributes/types/birth/BirthDate.ts b/packages/content/src/attributes/types/birth/BirthDate.ts index 93504b24b..0b55ad693 100644 --- a/packages/content/src/attributes/types/birth/BirthDate.ts +++ b/packages/content/src/attributes/types/birth/BirthDate.ts @@ -1,6 +1,7 @@ -import { serialize, type, validate } from "@js-soft/ts-serval"; +import { Serializable, serialize, type, validate } from "@js-soft/ts-serval"; import nameOf from "easy-tsnameof"; import { DateTime } from "luxon"; +import { ValidationErrorWithoutProperty } from "../../../ValidationErrorWithoutProperty"; import { AbstractAttributeValue } from "../../AbstractAttributeValue"; import { AbstractComplexValue, AbstractComplexValueJSON, IAbstractComplexValue } from "../../AbstractComplexValue"; import { RenderHints, ValueHints } from "../../hints"; @@ -37,6 +38,23 @@ export class BirthDate extends AbstractComplexValue implements IBirthDate { @validate() public year: BirthYear; + protected static override postFrom(value: T): T { + if (!(value instanceof BirthDate)) throw new Error("this should never happen"); + + const dateTime = DateTime.fromObject({ day: value.day.value, month: value.month.value, year: value.year.value }); + const isValid = dateTime.isValid; + + if (!isValid) { + throw new ValidationErrorWithoutProperty(BirthDate.name, "The BirthDate is not a valid date."); + } + + if (DateTime.utc() < dateTime) { + throw new ValidationErrorWithoutProperty(BirthDate.name, "You cannot enter a BirthDate that is in the future."); + } + + return value; + } + public static get valueHints(): ValueHints { return ValueHints.from({ propertyHints: { diff --git a/packages/content/test/attributes/BirthDate.test.ts b/packages/content/test/attributes/BirthDate.test.ts new file mode 100644 index 000000000..d29ee52b9 --- /dev/null +++ b/packages/content/test/attributes/BirthDate.test.ts @@ -0,0 +1,47 @@ +import { UserfriendlyApplicationError } from "@nmshd/app-runtime/src/UserfriendlyApplicationError"; +import { BirthDate } from "@nmshd/content"; +import { ValidationErrorWithoutProperty } from "@nmshd/content/src/ValidationErrorWithoutProperty"; +import { DateTime } from "luxon"; + +describe("creation of RepositoryAttributes of Attribute Value Type BirthDate", () => { + test("can create a RepositoryAttribute of Attribute Value Type BirthDate", function () { + const validBirthDate = BirthDate.from({ day: 1, month: 12, year: 1990 }); + expect(validBirthDate.constructor.name).toBe("BirthDate"); + expect(validBirthDate.day.value).toBe(1); + expect(validBirthDate.month.value).toBe(12); + expect(validBirthDate.year.value).toBe(1990); + }); + + test("returns an error when trying to create an invalid BirthDate with violated validation criteria of a single property", function () { + const invalidBirthDateCall = () => { + BirthDate.from({ day: 1, month: 13, year: 1990 }); + }; + expect(invalidBirthDateCall).toThrow( + new UserfriendlyApplicationError("error.runtime.requestDeserialization", "BirthMonth.value:Number :: must be an integer value between 1 and 12") + ); + }); + + test("returns an error when trying to create an invalid BirthDate with cross-component violated validation criteria for June", function () { + const invalidBirthDateCall = () => { + BirthDate.from({ day: 31, month: 6, year: 1990 }); + }; + expect(invalidBirthDateCall).toThrow(new ValidationErrorWithoutProperty(BirthDate.name, "The BirthDate is not a valid date.")); + }); + + test("returns an error when trying to create an invalid BirthDate with cross-component violated validation criteria for February", function () { + const invalidBirthDateCall = () => { + BirthDate.from({ day: 29, month: 2, year: 2010 }); + }; + expect(invalidBirthDateCall).toThrow(new ValidationErrorWithoutProperty(BirthDate.name, "The BirthDate is not a valid date.")); + }); + + test("returns an error when trying to create an BirthDate that is in the future", function () { + const currentDateTime = DateTime.utc(); + const yearInFuture = currentDateTime.year + 1; + + const invalidBirthDateCall = () => { + BirthDate.from({ day: 10, month: 6, year: yearInFuture }); + }; + expect(invalidBirthDateCall).toThrow(new ValidationErrorWithoutProperty(BirthDate.name, "You cannot enter a BirthDate that is in the future.")); + }); +}); diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 4628e8a07..6ff6fbaca 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/runtime", - "version": "4.1.2", + "version": "4.1.3", "description": "The enmeshed client runtime.", "homepage": "https://enmeshed.eu", "repository": { @@ -65,7 +65,7 @@ "@js-soft/ts-serval": "2.0.10", "@js-soft/ts-utils": "^2.3.3", "@nmshd/consumption": "3.9.3", - "@nmshd/content": "2.8.5", + "@nmshd/content": "2.8.6", "@nmshd/crypto": "2.0.6", "@nmshd/transport": "2.3.1", "ajv": "^8.12.0",