From c4ba470dc4d514bad9e27ce9b6e2d42e1c5ae3ce Mon Sep 17 00:00:00 2001 From: garronej Date: Mon, 11 Oct 2021 20:56:43 +0200 Subject: [PATCH] Implement and type validators --- src/lib/getKcContext/KcContextBase.ts | 74 +++++- .../kcContextMocks/kcContextMocks.ts | 222 ++++++++++++++++-- 2 files changed, 260 insertions(+), 36 deletions(-) diff --git a/src/lib/getKcContext/KcContextBase.ts b/src/lib/getKcContext/KcContextBase.ts index 0e43dcd1..c480ddc5 100644 --- a/src/lib/getKcContext/KcContextBase.ts +++ b/src/lib/getKcContext/KcContextBase.ts @@ -1,8 +1,8 @@ import type { PageId } from "../../bin/build-keycloak-theme/generateFtl"; import type { KcLanguageTag } from "../i18n/KcLanguageTag"; -import { assert } from "tsafe/assert"; -import type { Equals } from "tsafe"; +import { assert } from "tsafe/assert"; +import type { Equals } from "tsafe"; import type { MessageKey } from "../i18n/useKcMessage"; import type { LanguageLabel } from "../i18n/KcLanguageTag"; @@ -135,20 +135,13 @@ export declare namespace KcContextBase { }; }; + export type RegisterUserProfile = RegisterCommon & { pageId: "register-user-profile.ftl"; profile: { - attributes: { - name: string; - displayName?: string; - required: boolean; - value?: string; - group?: string; - groupDisplayHeader?: string; - groupDisplayDescription?: string; - readOnly: boolean; - autocomplete?: string; - }[]; + context: "REGISTRATION_PROFILE"; + attributes: Attribute[]; + attributesByName: Record; } }; @@ -213,6 +206,61 @@ export declare namespace KcContextBase { } +export type Attribute = { + name: string; + displayName?: string; + required: boolean; + value?: string; + group?: string; + groupDisplayHeader?: string; + groupDisplayDescription?: string; + readOnly: boolean; + autocomplete?: string; + validators: Validators; + annotations: Record; + groupAnnotations: Record +}; + +export type Validators = Partial<{ + length: Validators.DoIgnoreEmpty & Validators.Range; + double: Validators.DoIgnoreEmpty & Validators.Range; + integer: Validators.DoIgnoreEmpty & Validators.Range; + email: Validators.DoIgnoreEmpty; + 'up-immutable-attribute': {}; + 'up-attribute-required-by-metadata-value': {}; + 'up-username-has-value': {}; + 'up-duplicate-username': {}; + 'up-username-mutation': {}; + 'up-email-exists-as-username': {}; + 'up-blank-attribute-value': Validators.ErrorMessage & { + 'fail-on-null': boolean; + }; + 'up-duplicate-email': {}; + 'local-date': Validators.DoIgnoreEmpty; + pattern: Validators.DoIgnoreEmpty & Validators.ErrorMessage & { pattern: string; }; + 'person-name-prohibited-characters': Validators.DoIgnoreEmpty & Validators.ErrorMessage; + uri: Validators.DoIgnoreEmpty; + 'username-prohibited-characters': Validators.DoIgnoreEmpty & Validators.ErrorMessage; +}>; + +export declare namespace Validators { + + export type DoIgnoreEmpty = { + 'ignore.empty.value'?: boolean; + }; + + export type ErrorMessage = { + 'error-message'?: string; + } + + export type Range = { + /** "0", "1", "2"... yeah I know, don't tell me */ + min?: string; + max?: string; + }; + +} + assert>(); diff --git a/src/lib/getKcContext/kcContextMocks/kcContextMocks.ts b/src/lib/getKcContext/kcContextMocks/kcContextMocks.ts index 56e8fa78..a339e760 100644 --- a/src/lib/getKcContext/kcContextMocks/kcContextMocks.ts +++ b/src/lib/getKcContext/kcContextMocks/kcContextMocks.ts @@ -1,5 +1,6 @@ -import type { KcContextBase } from "../KcContextBase"; +import "minimal-polyfills/Object.fromEntries"; +import type { KcContextBase, Attribute } from "../KcContextBase"; import { getEvtKcLanguage } from "../../i18n/useKcLanguageTag"; import { getKcLanguageTagLabel } from "../../i18n/KcLanguageTag"; //NOTE: Aside because we want to be able to import them from node @@ -24,10 +25,10 @@ export const kcContextCommonMock: KcContextBase.Common = { "registrationEmailAsUsername": true, }, "messagesPerField": { - "printIfExists": (...[, x]) => x, - "existsError": ()=> true, - "get": key=> `Fake error for ${key}`, - "exists": ()=> true + "printIfExists": (...[, x]) => x, + "existsError": () => true, + "get": key => `Fake error for ${key}`, + "exists": () => true }, "locale": { "supported": [ @@ -163,25 +164,200 @@ export const kcContextMocks: KcContextBase[] = [ "registrationDisabled": false, }), - id({ - ...kcContextCommonMock, - "pageId": "register.ftl", - "url": { - ...loginUrl, - "registrationAction": "http://localhost:8080/auth/realms/myrealm/login-actions/registration?session_code=gwZdUeO7pbYpFTRxiIxRg_QtzMbtFTKrNu6XW_f8asM&execution=12146ce0-b139-4bbd-b25b-0eccfee6577e&client_id=account&tab_id=uS8lYfebLa0" - }, - "scripts": [], - "isAppInitiatedAction": false, - "register": { - "formData": {} - }, - "passwordRequired": true, - "recaptchaRequired": false, - "social": { - "displayInfo": true - }, + ...(() => { - }), + const registerCommon: KcContextBase.RegisterCommon = { + ...kcContextCommonMock, + "url": { + ...loginUrl, + "registrationAction": "http://localhost:8080/auth/realms/myrealm/login-actions/registration?session_code=gwZdUeO7pbYpFTRxiIxRg_QtzMbtFTKrNu6XW_f8asM&execution=12146ce0-b139-4bbd-b25b-0eccfee6577e&client_id=account&tab_id=uS8lYfebLa0" + }, + "scripts": [], + "isAppInitiatedAction": false, + "passwordRequired": true, + "recaptchaRequired": false, + "social": { + "displayInfo": true + }, + }; + + return [ + id({ + "pageId": "register.ftl", + ...registerCommon, + "register": { + "formData": {} + }, + }), + id({ + "pageId": "register-user-profile.ftl", + ...registerCommon, + + + "profile": { + "context": "REGISTRATION_PROFILE" as const, + ...(() => { + + const attributes: Attribute[] = [ + { + "validators": { + "username-prohibited-characters": { + "ignore.empty.value": true + }, + "up-username-has-value": { + + }, + "length": { + "ignore.empty.value": true, + "min": "3", + "max": "255" + }, + "up-duplicate-username": { + + }, + "up-username-mutation": { + + } + }, + "displayName": "${username}", + "annotations": { + + }, + "required": true, + "groupAnnotations": { + + }, + "autocomplete": "username", + "readOnly": false, + "name": "username" + }, + { + "validators": { + "up-email-exists-as-username": { + + }, + "length": { + "max": "255", + "ignore.empty.value": true + }, + "up-blank-attribute-value": { + "error-message": "missingEmailMessage", + "fail-on-null": false + }, + "up-duplicate-email": { + + }, + "email": { + "ignore.empty.value": true + } + }, + "displayName": "${email}", + "annotations": { + + }, + "required": true, + "groupAnnotations": { + + }, + "autocomplete": "email", + "readOnly": false, + "name": "email" + }, + { + "validators": { + "length": { + "max": "255", + "ignore.empty.value": true + }, + "person-name-prohibited-characters": { + "ignore.empty.value": true + }, + "up-immutable-attribute": { + + }, + "up-attribute-required-by-metadata-value": { + + } + }, + "displayName": "${firstName}", + "annotations": { + + }, + "required": true, + "groupAnnotations": { + + }, + "readOnly": false, + "name": "firstName" + }, + { + "validators": { + "length": { + "max": "255", + "ignore.empty.value": true + }, + "person-name-prohibited-characters": { + "ignore.empty.value": true + }, + "up-immutable-attribute": {}, + "up-attribute-required-by-metadata-value": {} + }, + "displayName": "${lastName}", + "annotations": { + + }, + "required": true, + "groupAnnotations": { + + }, + "readOnly": false, + "name": "lastName" + }, + { + "validators": { + "length": { + "ignore.empty.value": true, + "min": "3", + "max": "9" + }, + "up-immutable-attribute": {}, + "up-attribute-required-by-metadata-value": {}, + "email": { + "ignore.empty.value": true + } + }, + "displayName": "${foo}", + "annotations": { + "this_is_second_key": "this_is_second_value", + "this_is_first_key": "this_is_first_value" + }, + "required": true, + "groupAnnotations": { + + }, + "readOnly": false, + "name": "foo" + } + ]; + + return { + attributes, + "attributesByName": Object.fromEntries( + attributes.map(attribute => [attribute.name, attribute]) + ) as any + } as any; + + + })() + } + + + }) + ]; + + + + })(), id({ ...kcContextCommonMock, "pageId": "info.ftl",