From 0f62c239383f391db7571dd04a3b36f3fa8b2246 Mon Sep 17 00:00:00 2001 From: nijmra Date: Tue, 10 Dec 2024 16:21:54 +0100 Subject: [PATCH 1/5] setup --- .../formulier/ContactverzoekFormulier.vue | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue b/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue index e923d5184..aaf7f8262 100644 --- a/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue +++ b/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue @@ -250,7 +250,7 @@ type="tel" name="Telefoonnummer 1" class="utrecht-textbox utrecht-textbox--html-input" - @input="setActive" + @input="handleTelefoonInput" /> @@ -506,6 +505,22 @@ const handleTelefoonInput = (event: Event) => { } }; +// https://github.com/django/django/blob/4.2/django/core/validators.py#L174.Voor +const EMAIL_PATTERN = + /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{2,63})+|\[[a-fA-F0-9:.]+\])$/; + +const handleEmailInput = (event: Event) => { + const el = event.target as HTMLInputElement; + + setActive(); + + el.setCustomValidity( + !el.value || EMAIL_PATTERN.test(el.value) + ? "" + : "Vul een geldig emailadres in.", + ); +}; + //als de afdeling wijzigt, dan moet de medewerker gereset worden watch( () => form.value.afdeling, From 23fee6314579dfbf64eadf56dc3633af42ae3436 Mon Sep 17 00:00:00 2001 From: nijmra Date: Wed, 11 Dec 2024 14:36:49 +0100 Subject: [PATCH 4/5] telefoon pattern source, email pattern comment --- .../contactverzoek/formulier/ContactverzoekFormulier.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue b/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue index ee85346b4..20a84ab14 100644 --- a/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue +++ b/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue @@ -486,7 +486,7 @@ watch( ([el, bool]) => el && el.setCustomValidity(!bool ? noContactMessage : ""), ); -// klantinteracties/api/v1/schema/#tag/digitale-adressen/operation/digitaleadressenCreate +// https://github.com/maykinmedia/open-klant/blob/f231f368c48276ffe429fb7e3105b0ce9f0eb444/src/openklant/utils/validators.py#L26 const TELEFOON_PATTERN = /^(0[8-9]00[0-9]{4,7}|0[1-9][0-9]{8}|\+[0-9]{9,20}|1400|140[0-9]{2,3})$/; @@ -505,7 +505,8 @@ const handleTelefoonInput = (event: Event) => { } }; -// https://github.com/django/django/blob/4.2/django/core/validators.py#L174.Voor +// https://github.com/django/django/blob/4.2/django/core/validators.py#L174 +// patterns user_regex / domain_regex / literal_regex gecombineerd const EMAIL_PATTERN = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{2,63})+|\[[a-fA-F0-9:.]+\])$/; From 4f59656bebb81eec795fb07b00424b900095b02a Mon Sep 17 00:00:00 2001 From: nijmra Date: Thu, 12 Dec 2024 11:18:26 +0100 Subject: [PATCH 5/5] tests for phone and email validation --- .../formulier/ContactverzoekFormulier.vue | 10 +-- src/helpers/validation.ts | 16 ++++ src/test/helpers/validation.test.ts | 85 ++++++++++++++++++- 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue b/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue index 20a84ab14..e51cbe50c 100644 --- a/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue +++ b/src/features/contact/contactverzoek/formulier/ContactverzoekFormulier.vue @@ -318,6 +318,7 @@ import AfdelingenSearch from "../../components/AfdelingenSearch.vue"; import GroepenSearch from "./components/GroepenSearch.vue"; import { fetchAfdelingen } from "@/features/contact/components/afdelingen"; import { fetchGroepen } from "./components/groepen"; +import { TELEFOON_PATTERN, EMAIL_PATTERN } from "@/helpers/validation"; const props = defineProps<{ modelValue: ContactmomentContactVerzoek; @@ -486,10 +487,6 @@ watch( ([el, bool]) => el && el.setCustomValidity(!bool ? noContactMessage : ""), ); -// https://github.com/maykinmedia/open-klant/blob/f231f368c48276ffe429fb7e3105b0ce9f0eb444/src/openklant/utils/validators.py#L26 -const TELEFOON_PATTERN = - /^(0[8-9]00[0-9]{4,7}|0[1-9][0-9]{8}|\+[0-9]{9,20}|1400|140[0-9]{2,3})$/; - const handleTelefoonInput = (event: Event) => { const el = event.target as HTMLInputElement; @@ -505,11 +502,6 @@ const handleTelefoonInput = (event: Event) => { } }; -// https://github.com/django/django/blob/4.2/django/core/validators.py#L174 -// patterns user_regex / domain_regex / literal_regex gecombineerd -const EMAIL_PATTERN = - /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{2,63})+|\[[a-fA-F0-9:.]+\])$/; - const handleEmailInput = (event: Event) => { const el = event.target as HTMLInputElement; diff --git a/src/helpers/validation.ts b/src/helpers/validation.ts index 330df1ed0..29b02a593 100644 --- a/src/helpers/validation.ts +++ b/src/helpers/validation.ts @@ -199,3 +199,19 @@ export const vValidate: Directive = { (el as any).removeValidatorSetup?.(); }, }; + +// https://github.com/maykinmedia/open-klant/blob/f231f368c48276ffe429fb7e3105b0ce9f0eb444/src/openklant/utils/validators.py#L26 +export const TELEFOON_PATTERN = + /^(0[8-9]00[0-9]{4,7}|0[1-9][0-9]{8}|\+[0-9]{9,20}|1400|140[0-9]{2,3})$/; + +// https://github.com/django/django/blob/4.2/django/core/validators.py#L174 +export const EMAIL_PATTERN = new RegExp( + "^" + + // user_regex (without quoted string) + "([-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*)" + + "@" + + // domain_regex (without literal_regex) + "((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+(?:[A-Z0-9-]{2,63}(? { test("should allow dd/MM/yyyy", async () => { @@ -52,7 +56,7 @@ describe("parseDutchDate", () => { expect(parsed).toBeInstanceOf(Error); const error = parsed as Error; expect(error.message).toBe( - "Voer een valide datum in, bijvoorbeeld 17-09-2022 of 17092022." + "Voer een valide datum in, bijvoorbeeld 17-09-2022 of 17092022.", ); }); @@ -61,7 +65,7 @@ describe("parseDutchDate", () => { expect(parsed).toBeInstanceOf(Error); const error = parsed as Error; expect(error.message).toBe( - "Voer een valide datum in, bijvoorbeeld 17-09-2022 of 17092022." + "Voer een valide datum in, bijvoorbeeld 17-09-2022 of 17092022.", ); }); }); @@ -84,3 +88,76 @@ describe("parseBsn", () => { expect(parsedError.message).toBe("Voer een BSN in van negen cijfers."); }); }); + +describe("TELEFOON_PATTERN", () => { + test("validates phone numbers correctly", () => { + const testCases = [ + { number: "+31612345678", isValid: true }, + { number: "+441134960000", isValid: true }, + { number: "+12065550100", isValid: true }, + { number: "0612345678", isValid: true }, + { number: "09001234567", isValid: true }, + { number: "1400", isValid: true }, + { number: "14012", isValid: true }, + { number: "14079", isValid: true }, + { number: "0695azerty", isValid: false }, + { number: "azerty0545", isValid: false }, + { number: "@4566544++8", isValid: false }, + { number: "onetwothreefour", isValid: false }, + { number: "020 753 0523", isValid: false }, + { number: "+311234", isValid: false }, + { number: "0800852", isValid: false }, + { number: "080085285212", isValid: false }, + ]; + + testCases.forEach(({ number, isValid }) => + expect(TELEFOON_PATTERN.test(number)).toBe(isValid), + ); + }); +}); + +describe("EMAIL_PATTERN", () => { + test("validates email addresses correctly", () => { + const testCases = [ + { email: "email@here.com", isValid: true }, + { email: "weirder-email@here.and.there.com", isValid: true }, + { email: "example@valid-----hyphens.com", isValid: true }, + { email: "example@valid-with-hyphens.com", isValid: true }, + { email: `example@atm.${"a".repeat(63)}`, isValid: true }, + { email: `example@${"a".repeat(63)}.atm`, isValid: true }, + { + email: `example@${"a".repeat(63)}.${"b".repeat(10)}.atm`, + isValid: true, + }, + { email: `example@atm.${"a".repeat(64)}`, isValid: false }, + { + email: `example@${"b".repeat(64)}.atm.${"a".repeat(63)}.atm`, + isValid: false, + }, + { email: "", isValid: false }, + { email: "abc", isValid: false }, + { email: "abc@", isValid: false }, + { email: "abc@bar", isValid: false }, + { email: "a @x.cz", isValid: false }, + { email: "abc@.com", isValid: false }, + { email: `"test@test"@example.com`, isValid: false }, + { email: "something@@somewhere.com", isValid: false }, + { email: "email@127.0.0.1", isValid: false }, + { email: "example@invalid-.com", isValid: false }, + { email: "example@-invalid.com", isValid: false }, + { email: "example@invalid.com-", isValid: false }, + { email: "example@inv-.alid-.com", isValid: false }, + { email: "example@inv-.-alid.com", isValid: false }, + { email: `test@example.com\n\n