From c40dacb16ec4de1743a7fd2b50500528ee8982ea Mon Sep 17 00:00:00 2001 From: Andrea De Castri Date: Mon, 27 Nov 2023 14:32:31 +0100 Subject: [PATCH 1/5] feat: add nationality def in common fields and in customer fields --- maas-schemas/schemas/core/components/common.json | 12 ++++++++++++ maas-schemas/schemas/core/customer.json | 3 +++ 2 files changed, 15 insertions(+) diff --git a/maas-schemas/schemas/core/components/common.json b/maas-schemas/schemas/core/components/common.json index e67024a43..47977a766 100644 --- a/maas-schemas/schemas/core/components/common.json +++ b/maas-schemas/schemas/core/components/common.json @@ -172,6 +172,18 @@ "type": "object", "properties": {}, "additionalProperties": false + }, + "nationality": { + "description": "ISO 3166-1 alpha-2 country code, see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2", + "type": "string", + "pattern": "^[A-Z]{2,2}$", + "examples": ["FI", "GB"], + "invalid": { + "IiI=": "empty string", + "IvCfkqki": "emoji", + "ImZpIg==": "lower case alpha-2 country code", + "IkZJTiI=": "alpha-3 country code" + } } } } diff --git a/maas-schemas/schemas/core/customer.json b/maas-schemas/schemas/core/customer.json index ab61d1955..8253421e3 100644 --- a/maas-schemas/schemas/core/customer.json +++ b/maas-schemas/schemas/core/customer.json @@ -76,6 +76,9 @@ "zipCode": { "$ref": "https://schemas.maas.global/core/components/address.json#/definitions/zipCode" }, + "nationality": { + "$ref": "https://schemas.maas.global/core/components/common.json#/definitions/nationality" + }, "locale": { "$ref": "https://schemas.maas.global/core/components/i18n.json#/definitions/locale" }, From c25eae8da154d53fdf1430724eb2275a23810f8a Mon Sep 17 00:00:00 2001 From: Andrea De Castri Date: Mon, 27 Nov 2023 14:55:59 +0100 Subject: [PATCH 2/5] chore: generate types --- .../io-ts/_types/core/components/common.ts | 27 +++++++++++++++++++ .../src/io-ts/_types/core/customer.ts | 4 +++ 2 files changed, 31 insertions(+) diff --git a/maas-schemas/src/io-ts/_types/core/components/common.ts b/maas-schemas/src/io-ts/_types/core/components/common.ts index 4099fe01b..cbca16bc8 100644 --- a/maas-schemas/src/io-ts/_types/core/components/common.ts +++ b/maas-schemas/src/io-ts/_types/core/components/common.ts @@ -459,6 +459,33 @@ export type EmptyObjectBrand = { readonly EmptyObject: unique symbol; }; +// Nationality +// ISO 3166-1 alpha-2 country code, see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 +export type Nationality = t.Branded; +export type NationalityC = t.BrandC; +export const Nationality: NationalityC = t.brand( + t.string, + (x): x is t.Branded => + typeof x !== 'string' || x.match(RegExp('^[A-Z]{2,2}$', 'u')) !== null, + 'Nationality', +); +export type NationalityBrand = { + readonly Nationality: unique symbol; +}; +/** require('io-ts-validator').validator(nonEmptyArray(Nationality)).decodeSync(examplesNationality) // => examplesNationality */ +export const examplesNationality: NonEmptyArray = [ + 'FI', + 'GB', +] as unknown as NonEmptyArray; +// NEGATIVE Test Case: empty string +/** require('io-ts-validator').validator(Nationality).decodeEither("")._tag // => 'Left' */ +// NEGATIVE Test Case: emoji +/** require('io-ts-validator').validator(Nationality).decodeEither("💩")._tag // => 'Left' */ +// NEGATIVE Test Case: lower case alpha-2 country code +/** require('io-ts-validator').validator(Nationality).decodeEither("fi")._tag // => 'Left' */ +// NEGATIVE Test Case: alpha-3 country code +/** require('io-ts-validator').validator(Nationality).decodeEither("FIN")._tag // => 'Left' */ + // Common // The default export. More information at the top. export type Common = t.Branded; diff --git a/maas-schemas/src/io-ts/_types/core/customer.ts b/maas-schemas/src/io-ts/_types/core/customer.ts index 26a03897a..2c0b01904 100644 --- a/maas-schemas/src/io-ts/_types/core/customer.ts +++ b/maas-schemas/src/io-ts/_types/core/customer.ts @@ -65,6 +65,7 @@ export type Customer = t.Branded< state?: Address_2d0a_.State; country?: Address_2d0a_.Country; zipCode?: Address_2d0a_.ZipCode; + nationality?: Common_ffba_.Nationality; locale?: I18n_b70d_.Locale; appInstanceId?: Common_ffba_.AppInstanceId; opaqueId?: Common_ffba_.OpaqueId; @@ -118,6 +119,7 @@ export type CustomerC = t.BrandC< state: typeof Address_2d0a_.State; country: typeof Address_2d0a_.Country; zipCode: typeof Address_2d0a_.ZipCode; + nationality: typeof Common_ffba_.Nationality; locale: typeof I18n_b70d_.Locale; appInstanceId: typeof Common_ffba_.AppInstanceId; opaqueId: typeof Common_ffba_.OpaqueId; @@ -204,6 +206,7 @@ export const Customer: CustomerC = t.brand( state: Address_2d0a_.State, country: Address_2d0a_.Country, zipCode: Address_2d0a_.ZipCode, + nationality: Common_ffba_.Nationality, locale: I18n_b70d_.Locale, appInstanceId: Common_ffba_.AppInstanceId, opaqueId: Common_ffba_.OpaqueId, @@ -274,6 +277,7 @@ export const Customer: CustomerC = t.brand( state?: Address_2d0a_.State; country?: Address_2d0a_.Country; zipCode?: Address_2d0a_.ZipCode; + nationality?: Common_ffba_.Nationality; locale?: I18n_b70d_.Locale; appInstanceId?: Common_ffba_.AppInstanceId; opaqueId?: Common_ffba_.OpaqueId; From 376b8648bad1c7b208032b1adde424ab23744f25 Mon Sep 17 00:00:00 2001 From: Konrad Markus Date: Mon, 18 Dec 2023 16:22:58 +0200 Subject: [PATCH 3/5] Add personalDataCatalogue to customers-retrieve resoponse --- .../customers/personalDataCatalogue.json | 68 +++++++++++++++++++ .../customers/retrieve/response.json | 8 ++- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json diff --git a/maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json b/maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json new file mode 100644 index 000000000..1bd7bb46c --- /dev/null +++ b/maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.maas.global/maas-backend/customers/personalDataCatalogue.json", + "description": "MaaS customer personal data catalogue schema", + "definitions": { + "regionRestriction": { + "type": "array", + "description": "Restrict to the specified list of regions", + "items": { + "$ref": "https://schemas.maas.global/core/region.json#/definitions/regionId" + } + }, + "dependsOnRestriction": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of another personal data item that this item depends on. I.e. the dependee item must have a value for this item to be enabled" + }, + "values": { + "type": "array", + "description": "A list of possible values of the dependee item which enable the dependency", + "items": { + "type": "string" + } + } + } + }, + "personalDataCatalogueItem": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["string", "ISODate", "email", "phone", "locale"] + }, + "enum": { + "type": "array", + "description": "The value is limited to a fixed set of possible values", + "items": { + "type": "string" + } + }, + "canShowPlain": { + "type": "boolean", + "description": "True if the client should show the value in plain text. False if the value should be obfuscated." + }, + "isReadOnly": { + "type": "boolean", + "description": "True if the item is read-only. False if the item can be edited." + }, + "description": { + "type": "string" + }, + "regionRestriction": { + "$ref": "#/definitions/regionRestriction" + }, + "dependsOn": { + "$ref": "#/definitions/dependsOnRestriction" + } + }, + "required": ["name", "type", "canShowPlain", "isReadOnly"], + "additionalProperties": false + } + } +} diff --git a/maas-schemas/schemas/maas-backend/customers/retrieve/response.json b/maas-schemas/schemas/maas-backend/customers/retrieve/response.json index 82b407823..e4829c9a1 100644 --- a/maas-schemas/schemas/maas-backend/customers/retrieve/response.json +++ b/maas-schemas/schemas/maas-backend/customers/retrieve/response.json @@ -6,8 +6,14 @@ "properties": { "customer": { "$ref": "https://schemas.maas.global/maas-backend/customers/customer.json" + }, + "personalDataCatalogue": { + "type": "array", + "items": { + "$ref": "https://schemas.maas.global/maas-backend/customers/personalDataCatalogue.json#/definitions/personalDataCatalogueItem" + } } }, "additionalProperties": false, - "required": ["customer"] + "required": ["customer", "personalDataCatalogue"] } From de04b0de4d4e5a9919b841c08536764a8228beea Mon Sep 17 00:00:00 2001 From: Konrad Markus Date: Mon, 18 Dec 2023 16:26:25 +0200 Subject: [PATCH 4/5] chore: generate types --- ...atalogue.json => personalDataCatalog.json} | 25 +- .../customers/retrieve/response.json | 6 +- maas-schemas/src/ajv/registry.ts | 1 + maas-schemas/src/io-ts/_translation.log | 14 ++ .../customers/personalDataCatalog.ts | 223 ++++++++++++++++++ .../customers/retrieve/response.ts | 11 + .../customers/personalDataCatalog.ts | 3 + 7 files changed, 266 insertions(+), 17 deletions(-) rename maas-schemas/schemas/maas-backend/customers/{personalDataCatalogue.json => personalDataCatalog.json} (75%) create mode 100644 maas-schemas/src/io-ts/_types/maas-backend/customers/personalDataCatalog.ts create mode 100644 maas-schemas/src/io-ts/maas-backend/customers/personalDataCatalog.ts diff --git a/maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json b/maas-schemas/schemas/maas-backend/customers/personalDataCatalog.json similarity index 75% rename from maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json rename to maas-schemas/schemas/maas-backend/customers/personalDataCatalog.json index 1bd7bb46c..ab63cdeda 100644 --- a/maas-schemas/schemas/maas-backend/customers/personalDataCatalogue.json +++ b/maas-schemas/schemas/maas-backend/customers/personalDataCatalog.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://schemas.maas.global/maas-backend/customers/personalDataCatalogue.json", - "description": "MaaS customer personal data catalogue schema", + "$id": "https://schemas.maas.global/maas-backend/customers/personalDataCatalog.json", + "description": "MaaS customer personal data catalog schema", "definitions": { "regionRestriction": { "type": "array", @@ -24,9 +24,10 @@ "type": "string" } } - } + }, + "required": ["name"] }, - "personalDataCatalogueItem": { + "personalDataCatalogItem": { "type": "object", "properties": { "name": { @@ -34,7 +35,7 @@ }, "type": { "type": "string", - "enum": ["string", "ISODate", "email", "phone", "locale"] + "enum": ["string", "ISODate", "ISODatetime", "ISOCountryAlpha2"] }, "enum": { "type": "array", @@ -47,21 +48,17 @@ "type": "boolean", "description": "True if the client should show the value in plain text. False if the value should be obfuscated." }, - "isReadOnly": { - "type": "boolean", - "description": "True if the item is read-only. False if the item can be edited." - }, - "description": { - "type": "string" - }, "regionRestriction": { "$ref": "#/definitions/regionRestriction" }, "dependsOn": { - "$ref": "#/definitions/dependsOnRestriction" + "type": "array", + "items": { + "$ref": "#/definitions/dependsOnRestriction" + } } }, - "required": ["name", "type", "canShowPlain", "isReadOnly"], + "required": ["name", "type", "canShowPlain"], "additionalProperties": false } } diff --git a/maas-schemas/schemas/maas-backend/customers/retrieve/response.json b/maas-schemas/schemas/maas-backend/customers/retrieve/response.json index e4829c9a1..d3bb2eb11 100644 --- a/maas-schemas/schemas/maas-backend/customers/retrieve/response.json +++ b/maas-schemas/schemas/maas-backend/customers/retrieve/response.json @@ -7,13 +7,13 @@ "customer": { "$ref": "https://schemas.maas.global/maas-backend/customers/customer.json" }, - "personalDataCatalogue": { + "personalDataCatalog": { "type": "array", "items": { - "$ref": "https://schemas.maas.global/maas-backend/customers/personalDataCatalogue.json#/definitions/personalDataCatalogueItem" + "$ref": "https://schemas.maas.global/maas-backend/customers/personalDataCatalog.json#/definitions/personalDataCatalogItem" } } }, "additionalProperties": false, - "required": ["customer", "personalDataCatalogue"] + "required": ["customer", "personalDataCatalog"] } diff --git a/maas-schemas/src/ajv/registry.ts b/maas-schemas/src/ajv/registry.ts index e4fd47022..138141cc9 100644 --- a/maas-schemas/src/ajv/registry.ts +++ b/maas-schemas/src/ajv/registry.ts @@ -163,6 +163,7 @@ export const registry: mjsv.Registry = { require('../../schemas/maas-backend/customers/personal-documents/update/request.json'), require('../../schemas/maas-backend/customers/personal-documents/update/response.json'), require('../../schemas/maas-backend/customers/personalData.json'), + require('../../schemas/maas-backend/customers/personalDataCatalog.json'), require('../../schemas/maas-backend/customers/retrieve/request.json'), require('../../schemas/maas-backend/customers/retrieve/response.json'), require('../../schemas/maas-backend/customers/stats/request.json'), diff --git a/maas-schemas/src/io-ts/_translation.log b/maas-schemas/src/io-ts/_translation.log index 301517a62..750ce5650 100644 --- a/maas-schemas/src/io-ts/_translation.log +++ b/maas-schemas/src/io-ts/_translation.log @@ -1610,6 +1610,20 @@ INFO: missing description in schemas/maas-backend/customers/personalData.json INFO: missing description in schemas/maas-backend/customers/personalData.json +INFO: primitive type "string" used outside top-level definitions + in schemas/maas-backend/customers/personalDataCatalog.json +INFO: primitive type "string" used outside top-level definitions + in schemas/maas-backend/customers/personalDataCatalog.json +INFO: primitive type "string" used outside top-level definitions + in schemas/maas-backend/customers/personalDataCatalog.json +INFO: primitive type "string" used outside top-level definitions + in schemas/maas-backend/customers/personalDataCatalog.json +INFO: primitive type "string" used outside top-level definitions + in schemas/maas-backend/customers/personalDataCatalog.json +INFO: missing description + in schemas/maas-backend/customers/personalDataCatalog.json +INFO: missing description + in schemas/maas-backend/customers/personalDataCatalog.json INFO: primitive type "integer" used outside top-level definitions in schemas/maas-backend/customers/stats/response.json WARNING: minimum field not supported outside top-level definitions diff --git a/maas-schemas/src/io-ts/_types/maas-backend/customers/personalDataCatalog.ts b/maas-schemas/src/io-ts/_types/maas-backend/customers/personalDataCatalog.ts new file mode 100644 index 000000000..30a033443 --- /dev/null +++ b/maas-schemas/src/io-ts/_types/maas-backend/customers/personalDataCatalog.ts @@ -0,0 +1,223 @@ +/* + +undefined +MaaS customer personal data catalog schema + +!!! AUTO GENERATED BY IOTSFJS REFRAIN FROM MANUAL EDITING !!! +See https://www.npmjs.com/package/io-ts-from-json-schema + +*/ + +import * as t from 'io-ts'; + +import * as Region_ad49_ from '../../core/region'; + +export type Defined = {} | null; +export class DefinedType extends t.Type { + readonly _tag: 'DefinedType' = 'DefinedType'; + constructor() { + super( + 'defined', + (u): u is Defined => typeof u !== 'undefined', + (u, c) => (this.is(u) ? t.success(u) : t.failure(u, c)), + t.identity, + ); + } +} +export type DefinedC = {} & DefinedType; +export const Defined: DefinedC = new DefinedType(); + +export const schemaId = + 'https://schemas.maas.global/maas-backend/customers/personalDataCatalog.json'; + +// RegionRestriction +// Restrict to the specified list of regions +export type RegionRestriction = t.Branded< + Array, + RegionRestrictionBrand +>; +export type RegionRestrictionC = t.BrandC< + t.ArrayC, + RegionRestrictionBrand +>; +export const RegionRestriction: RegionRestrictionC = t.brand( + t.array(Region_ad49_.RegionId), + (x): x is t.Branded, RegionRestrictionBrand> => true, + 'RegionRestriction', +); +export type RegionRestrictionBrand = { + readonly RegionRestriction: unique symbol; +}; + +// DependsOnRestriction +// The purpose of this remains a mystery +export type DependsOnRestriction = t.Branded< + ({ + name?: string; + values?: Array; + } & Record) & { + name: Defined; + }, + DependsOnRestrictionBrand +>; +export type DependsOnRestrictionC = t.BrandC< + t.IntersectionC< + [ + t.IntersectionC< + [ + t.PartialC<{ + name: t.StringC; + values: t.ArrayC; + }>, + t.RecordC, + ] + >, + t.TypeC<{ + name: typeof Defined; + }>, + ] + >, + DependsOnRestrictionBrand +>; +export const DependsOnRestriction: DependsOnRestrictionC = t.brand( + t.intersection([ + t.intersection([ + t.partial({ + name: t.string, + values: t.array(t.string), + }), + t.record(t.string, t.unknown), + ]), + t.type({ + name: Defined, + }), + ]), + ( + x, + ): x is t.Branded< + ({ + name?: string; + values?: Array; + } & Record) & { + name: Defined; + }, + DependsOnRestrictionBrand + > => true, + 'DependsOnRestriction', +); +export type DependsOnRestrictionBrand = { + readonly DependsOnRestriction: unique symbol; +}; + +// PersonalDataCatalogItem +// The purpose of this remains a mystery +export type PersonalDataCatalogItem = t.Branded< + { + name?: string; + type?: string & ('string' | 'ISODate' | 'ISODatetime' | 'ISOCountryAlpha2'); + enum?: Array; + canShowPlain?: boolean; + regionRestriction?: RegionRestriction; + dependsOn?: Array; + } & { + name: Defined; + type: Defined; + canShowPlain: Defined; + }, + PersonalDataCatalogItemBrand +>; +export type PersonalDataCatalogItemC = t.BrandC< + t.IntersectionC< + [ + t.PartialC<{ + name: t.StringC; + type: t.IntersectionC< + [ + t.StringC, + t.UnionC< + [ + t.LiteralC<'string'>, + t.LiteralC<'ISODate'>, + t.LiteralC<'ISODatetime'>, + t.LiteralC<'ISOCountryAlpha2'>, + ] + >, + ] + >; + enum: t.ArrayC; + canShowPlain: t.BooleanC; + regionRestriction: typeof RegionRestriction; + dependsOn: t.ArrayC; + }>, + t.TypeC<{ + name: typeof Defined; + type: typeof Defined; + canShowPlain: typeof Defined; + }>, + ] + >, + PersonalDataCatalogItemBrand +>; +export const PersonalDataCatalogItem: PersonalDataCatalogItemC = t.brand( + t.intersection([ + t.partial({ + name: t.string, + type: t.intersection([ + t.string, + t.union([ + t.literal('string'), + t.literal('ISODate'), + t.literal('ISODatetime'), + t.literal('ISOCountryAlpha2'), + ]), + ]), + enum: t.array(t.string), + canShowPlain: t.boolean, + regionRestriction: RegionRestriction, + dependsOn: t.array(DependsOnRestriction), + }), + t.type({ + name: Defined, + type: Defined, + canShowPlain: Defined, + }), + ]), + ( + x, + ): x is t.Branded< + { + name?: string; + type?: string & ('string' | 'ISODate' | 'ISODatetime' | 'ISOCountryAlpha2'); + enum?: Array; + canShowPlain?: boolean; + regionRestriction?: RegionRestriction; + dependsOn?: Array; + } & { + name: Defined; + type: Defined; + canShowPlain: Defined; + }, + PersonalDataCatalogItemBrand + > => true, + 'PersonalDataCatalogItem', +); +export type PersonalDataCatalogItemBrand = { + readonly PersonalDataCatalogItem: unique symbol; +}; + +// PersonalDataCatalog +// The default export. More information at the top. +export type PersonalDataCatalog = t.Branded; +export type PersonalDataCatalogC = t.BrandC; +export const PersonalDataCatalog: PersonalDataCatalogC = t.brand( + t.unknown, + (x): x is t.Branded => true, + 'PersonalDataCatalog', +); +export type PersonalDataCatalogBrand = { + readonly PersonalDataCatalog: unique symbol; +}; + +export default PersonalDataCatalog; + +// Success diff --git a/maas-schemas/src/io-ts/_types/maas-backend/customers/retrieve/response.ts b/maas-schemas/src/io-ts/_types/maas-backend/customers/retrieve/response.ts index 0bad413f6..fc767632d 100644 --- a/maas-schemas/src/io-ts/_types/maas-backend/customers/retrieve/response.ts +++ b/maas-schemas/src/io-ts/_types/maas-backend/customers/retrieve/response.ts @@ -11,6 +11,7 @@ See https://www.npmjs.com/package/io-ts-from-json-schema import * as t from 'io-ts'; import * as Customer_1cb6_ from '../customer'; +import * as PersonalDataCatalog_96ca_ from '../personalDataCatalog'; export type Defined = {} | null; export class DefinedType extends t.Type { @@ -35,8 +36,10 @@ export const schemaId = export type Response = t.Branded< { customer?: Customer_1cb6_.Customer; + personalDataCatalog?: Array; } & { customer: Defined; + personalDataCatalog: Defined; }, ResponseBrand >; @@ -45,9 +48,13 @@ export type ResponseC = t.BrandC< [ t.PartialC<{ customer: typeof Customer_1cb6_.Customer; + personalDataCatalog: t.ArrayC< + typeof PersonalDataCatalog_96ca_.PersonalDataCatalogItem + >; }>, t.TypeC<{ customer: typeof Defined; + personalDataCatalog: typeof Defined; }>, ] >, @@ -57,9 +64,11 @@ export const Response: ResponseC = t.brand( t.intersection([ t.partial({ customer: Customer_1cb6_.Customer, + personalDataCatalog: t.array(PersonalDataCatalog_96ca_.PersonalDataCatalogItem), }), t.type({ customer: Defined, + personalDataCatalog: Defined, }), ]), ( @@ -67,8 +76,10 @@ export const Response: ResponseC = t.brand( ): x is t.Branded< { customer?: Customer_1cb6_.Customer; + personalDataCatalog?: Array; } & { customer: Defined; + personalDataCatalog: Defined; }, ResponseBrand > => true, diff --git a/maas-schemas/src/io-ts/maas-backend/customers/personalDataCatalog.ts b/maas-schemas/src/io-ts/maas-backend/customers/personalDataCatalog.ts new file mode 100644 index 000000000..5ac5cb1f7 --- /dev/null +++ b/maas-schemas/src/io-ts/maas-backend/customers/personalDataCatalog.ts @@ -0,0 +1,3 @@ +// Generated by update-index.ts Do not edit! + +export * from '../../_types/maas-backend/customers/personalDataCatalog'; From 05cdfd44feaa45772ab2a4e4c5fdd76093f8735b Mon Sep 17 00:00:00 2001 From: Konrad Markus Date: Tue, 19 Dec 2023 15:34:52 +0200 Subject: [PATCH 5/5] Version 22.0.0 --- maas-schemas/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maas-schemas/package.json b/maas-schemas/package.json index a1f892ee3..08fc7591f 100644 --- a/maas-schemas/package.json +++ b/maas-schemas/package.json @@ -1,6 +1,6 @@ { "name": "maas-schemas", - "version": "21.1.0", + "version": "22.0.0", "description": "Schemas for MaaS infrastructure", "main": "index.js", "engine": {