From 508cadf56af30b2b294ac9733631035d4ee2c5c2 Mon Sep 17 00:00:00 2001 From: Arthur Belkhayat Date: Fri, 22 Mar 2024 17:52:39 +0100 Subject: [PATCH] feat: allow multi email in contact field --- src/models/contact/contact.spec.ts | 19 +++++------------- src/models/contact/contact.ts | 17 ++++------------ src/models/contact/errors/index.ts | 1 - src/models/courriel/courriel.spec.ts | 20 +++++++++++++++++++ src/models/courriel/courriel.ts | 16 +++++++++++++++ .../errors/courriel.error.ts | 3 +-- src/models/courriel/errors/index.ts | 1 + src/models/courriel/index.ts | 2 ++ src/models/index.ts | 1 + .../from-schema-data-inclusion-fields.ts | 3 ++- .../from-schema-data-inclusion.spec.ts | 3 ++- .../service-to-structure.ts | 3 ++- .../to-schema-data-inclusion-fields.ts | 6 +++++- .../to-schema-data-inclusion.spec.ts | 3 ++- ...ema-lieux-de-mediation-numerique-fields.ts | 3 ++- ...chema-lieux-de-mediation-numerique.spec.ts | 3 ++- ...ema-lieux-de-mediation-numerique-fields.ts | 2 +- ...chema-lieux-de-mediation-numerique.spec.ts | 3 ++- 18 files changed, 70 insertions(+), 39 deletions(-) create mode 100644 src/models/courriel/courriel.spec.ts create mode 100644 src/models/courriel/courriel.ts rename src/models/{contact => courriel}/errors/courriel.error.ts (61%) create mode 100644 src/models/courriel/errors/index.ts create mode 100644 src/models/courriel/index.ts diff --git a/src/models/contact/contact.spec.ts b/src/models/contact/contact.spec.ts index 9232f70..f30317e 100644 --- a/src/models/contact/contact.spec.ts +++ b/src/models/contact/contact.spec.ts @@ -1,14 +1,15 @@ /* eslint-disable @typescript-eslint/naming-convention, camelcase */ +import { Courriel } from '../courriel'; import { Url } from '../url'; import { Contact, ContactToValidate } from './contact'; -import { CourrielError, TelephoneError } from './errors'; +import { TelephoneError } from './errors'; describe('contact model', (): void => { it('should create a valid contact', (): void => { const contactData: ContactToValidate = { telephone: '+33145896378', - courriel: 'contact@cartographienationale.fr', + courriel: [Courriel('contact@cartographienationale.fr')], site_web: [Url('http://www.cartographienationale.fr')] }; @@ -29,7 +30,7 @@ describe('contact model', (): void => { it('should create a valid contact with only courriel property', (): void => { const contactData: ContactToValidate = { - courriel: 'contact@cartographienationale.fr' + courriel: [Courriel('contact@cartographienationale.fr')] }; const contact: Contact = Contact(contactData); @@ -40,7 +41,7 @@ describe('contact model', (): void => { it('should create a valid contact with a phone from French Guiana', (): void => { const contactData: ContactToValidate = { telephone: '+594694020905', - courriel: 'direction.yenkumu.lutu@gmail.com', + courriel: [Courriel('direction.yenkumu.lutu@gmail.com')], site_web: [Url('https://www.facebook.com/YenkumuLutuPapaichton/')] }; @@ -49,16 +50,6 @@ describe('contact model', (): void => { expect(contact).toStrictEqual({ ...contactData } as Contact); }); - it('should throw CourrielError when courriel is invalid', (): void => { - const contactData: ContactToValidate = { - courriel: 'error' - }; - - expect((): void => { - Contact(contactData); - }).toThrow(new CourrielError('error')); - }); - it('should throw TelephoneError when telephone is invalid', (): void => { const contactData: ContactToValidate = { telephone: 'error' diff --git a/src/models/contact/contact.ts b/src/models/contact/contact.ts index 2080415..3fa6db3 100644 --- a/src/models/contact/contact.ts +++ b/src/models/contact/contact.ts @@ -1,38 +1,29 @@ +import { Courriel } from '../courriel'; import { Model } from '../model'; import { Url } from '../url'; -import { CourrielError, TelephoneError } from './errors'; +import { TelephoneError } from './errors'; export type Contact = Model< 'Contact', { telephone?: string; - courriel?: string; /* eslint-disable-next-line @typescript-eslint/naming-convention */ + courriel?: Courriel[]; site_web?: Url[]; } >; export type ContactToValidate = Omit; -const COURRIEL_REG_EXP: RegExp = - /^[a-zA-Z0-9_][a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])+$/u; - const TELEPHONE_REG_EXP: RegExp = /^(?:(?:\+|00)(?:33|594|262|596|269|687|689|590|508|681)[\s.-]{0,3}(?:\(0\)[\s.-]{0,3})?|0)(?:(?:[1-9](?:[\s.-]?\d{2}){4}|\d{2}(?:[\s.-]\d{3}){2})|\d{6}|\s\d{3}(?:\s\d{2}){3})$/u; -export const isValidCourriel = (courriel: string): boolean => COURRIEL_REG_EXP.test(courriel); - export const isValidTelephone = (telephone: string): boolean => TELEPHONE_REG_EXP.test(telephone); const isValidContact = (contact: Omit): contact is Contact => - (contact.courriel == null || isValidCourriel(contact.courriel)) && - (contact.telephone == null || isValidTelephone(contact.telephone)); + contact.telephone == null || isValidTelephone(contact.telephone); const throwContactError = (contact: Omit): Contact => { - if (contact.courriel != null && !isValidCourriel(contact.courriel)) { - throw new CourrielError(contact.courriel); - } - if (contact.telephone != null && !isValidTelephone(contact.telephone)) { throw new TelephoneError(contact.telephone); } diff --git a/src/models/contact/errors/index.ts b/src/models/contact/errors/index.ts index 33582bf..a8b489e 100644 --- a/src/models/contact/errors/index.ts +++ b/src/models/contact/errors/index.ts @@ -1,2 +1 @@ -export * from './courriel.error'; export * from './telephone.error'; diff --git a/src/models/courriel/courriel.spec.ts b/src/models/courriel/courriel.spec.ts new file mode 100644 index 0000000..48f9ae2 --- /dev/null +++ b/src/models/courriel/courriel.spec.ts @@ -0,0 +1,20 @@ +import { Courriel } from './courriel'; +import { CourrielError } from './errors'; + +describe('courriel model', (): void => { + it('should create a valid courriel', (): void => { + const courrielData: string = 'test@gmail.com'; + + const courriel: Courriel = Courriel(courrielData); + + expect(courriel).toStrictEqual(courrielData as Courriel); + }); + + it('should throw CourrielError when email do not have at symbole or domain extension', (): void => { + const courrielData: string = 'test@gmail'; + + expect((): void => { + Courriel(courrielData); + }).toThrow(new CourrielError(courrielData)); + }); +}); diff --git a/src/models/courriel/courriel.ts b/src/models/courriel/courriel.ts new file mode 100644 index 0000000..662aa59 --- /dev/null +++ b/src/models/courriel/courriel.ts @@ -0,0 +1,16 @@ +import { Model } from '../model'; +import { CourrielError } from './errors'; + +export type Courriel = Model<'Courriel', string>; + +const COURRIEL_REG_EXP: RegExp = + /^(?:[a-zA-Z0-9_][a-zA-Z0-9.!#$%&'*+\\=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])+(?:;|$))+$/u; + +const throwCourrielError = (courriel: string): Courriel => { + throw new CourrielError(courriel); +}; + +export const isValidCourriel = (courriel: string): courriel is Courriel => COURRIEL_REG_EXP.test(courriel); + +/* eslint-disable-next-line @typescript-eslint/naming-convention */ +export const Courriel = (courriel: string): Courriel => (isValidCourriel(courriel) ? courriel : throwCourrielError(courriel)); diff --git a/src/models/contact/errors/courriel.error.ts b/src/models/courriel/errors/courriel.error.ts similarity index 61% rename from src/models/contact/errors/courriel.error.ts rename to src/models/courriel/errors/courriel.error.ts index 02a2be2..92ac7c9 100644 --- a/src/models/contact/errors/courriel.error.ts +++ b/src/models/courriel/errors/courriel.error.ts @@ -1,7 +1,6 @@ import { ModelError } from '../../../errors'; -import { Contact } from '../contact'; -export class CourrielError extends ModelError { +export class CourrielError extends ModelError<{ courriel: string }> { constructor(courriel: string) { super('courriel', `Le courriel ${courriel} n'est pas valide`); } diff --git a/src/models/courriel/errors/index.ts b/src/models/courriel/errors/index.ts new file mode 100644 index 0000000..b2503cd --- /dev/null +++ b/src/models/courriel/errors/index.ts @@ -0,0 +1 @@ +export * from './courriel.error' \ No newline at end of file diff --git a/src/models/courriel/index.ts b/src/models/courriel/index.ts new file mode 100644 index 0000000..9071ed4 --- /dev/null +++ b/src/models/courriel/index.ts @@ -0,0 +1,2 @@ +export * from './errors'; +export * from './courriel'; diff --git a/src/models/index.ts b/src/models/index.ts index 0f4034e..6d54366 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -17,3 +17,4 @@ export * from './url'; export * from './lieu-mediation-numerique'; export * from './model'; export * from './presentation'; +export * from './courriel'; diff --git a/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion-fields.ts b/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion-fields.ts index afc48a1..ac9af26 100644 --- a/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion-fields.ts +++ b/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion-fields.ts @@ -6,6 +6,7 @@ import { ConditionAcces, ConditionsAcces, Contact, + Courriel, LabelNational, LabelsNationaux, Localisation, @@ -172,7 +173,7 @@ export const contactFromDataInclusion = (courriel?: string, telephone?: string, ? {} : { contact: Contact({ - ...(courriel == null ? {} : { courriel }), + ...(courriel == null ? {} : { courriel: courriel.split(';').map(Courriel) }), ...(telephone == null ? {} : { telephone }), ...(site_web == null ? {} : { site_web: site_web.split(';').map(Url) }) }) diff --git a/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion.spec.ts b/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion.spec.ts index 5bbc79f..64ce67e 100644 --- a/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion.spec.ts +++ b/src/transfer/schema-data-inclusion/from-schema-data-inclusion/from-schema-data-inclusion.spec.ts @@ -5,6 +5,7 @@ import { ConditionAcces, ConditionsAcces, Contact, + Courriel, Id, LabelNational, LabelsNationaux, @@ -170,7 +171,7 @@ describe('from schema data inclusion', (): void => { typologies: Typologies([Typologie.TIERS_LIEUX]), contact: Contact({ telephone: '+33180059880', - courriel: 'contact@laquincaillerie.tl', + courriel: [Courriel('contact@laquincaillerie.tl')], site_web: [Url('https://www.laquincaillerie.tl/'), Url('https://m.facebook.com/laquincaillerienumerique/')] }), horaires: 'Mo-Fr 09:00-12:00,14:00-18:30; Sa 08:30-12:00', diff --git a/src/transfer/schema-data-inclusion/service-to-structure/service-to-structure.ts b/src/transfer/schema-data-inclusion/service-to-structure/service-to-structure.ts index f2602cc..bba877c 100644 --- a/src/transfer/schema-data-inclusion/service-to-structure/service-to-structure.ts +++ b/src/transfer/schema-data-inclusion/service-to-structure/service-to-structure.ts @@ -12,7 +12,8 @@ import { SchemaStructureDataInclusionPresentationFields, SchemaStructureDataInclusionStructureGeneralFields } from '../schema-data-inclusion'; -import { isValidCourriel, isValidTelephone } from '../../../models'; +import { isValidTelephone } from '../../../models'; +import { isValidCourriel } from '../../../models/courriel'; export const isServiceWithAdresse = ( service: Partial & SchemaServiceDataInclusion diff --git a/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion-fields.ts b/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion-fields.ts index 776c76f..b7a5d51 100644 --- a/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion-fields.ts +++ b/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion-fields.ts @@ -86,6 +86,8 @@ const typologyIfExist = (typologie?: string): { typologie?: string } => (typolog const siteWebIfExist = (site_web?: string): { site_web?: string } => (site_web == null ? {} : { site_web }); +const courrielIfExist = (courriel?: string): { courriel?: string } => (courriel == null ? {} : { courriel }); + const fraisIfExist = (frais?: string): { frais?: string[] } => (frais == null ? {} : { frais: [frais] }); const fraisFromConditionAcces = (conditionAcces?: ConditionAcces): { frais?: string[] } => @@ -131,7 +133,9 @@ export const localisationFields = ( export const contactFields = (lieuMediationNumerique: LieuMediationNumerique): SchemaStructureDataInclusionContactFields => ({ ...(lieuMediationNumerique.contact?.telephone == null ? {} : { telephone: lieuMediationNumerique.contact.telephone }), - ...(lieuMediationNumerique.contact?.courriel == null ? {} : { courriel: lieuMediationNumerique.contact.courriel }), + ...(lieuMediationNumerique.contact?.courriel != null && lieuMediationNumerique.contact.courriel.length > 0 + ? courrielIfExist(lieuMediationNumerique.contact.courriel.at(0)?.toString()) + : {}), ...(lieuMediationNumerique.contact?.site_web != null && lieuMediationNumerique.contact.site_web.length > 0 ? siteWebIfExist(lieuMediationNumerique.contact.site_web.at(0)?.toString()) : {}) diff --git a/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion.spec.ts b/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion.spec.ts index 001a11f..c1d2ed9 100644 --- a/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion.spec.ts +++ b/src/transfer/schema-data-inclusion/to-schema-data-inclusion/to-schema-data-inclusion.spec.ts @@ -5,6 +5,7 @@ import { ConditionAcces, ConditionsAcces, Contact, + Courriel, Id, LabelNational, LabelsNationaux, @@ -100,7 +101,7 @@ describe('to schema data.inclusion', (): void => { contact: Contact({ site_web: [Url('https://www.asso-gonzalez.net/'), Url('https://www.facebook.com/asso-gonzalez.net/')], telephone: '0102030405', - courriel: 'julie@example.net' + courriel: [Courriel('julie@example.net')] }), horaires: 'Mo-Fr 10:00-20:00 "sur rendez-vous"; PH off', presentation: { diff --git a/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique-fields.ts b/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique-fields.ts index f2b7832..e0c6b2f 100644 --- a/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique-fields.ts +++ b/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique-fields.ts @@ -5,6 +5,7 @@ import { CleBan, ConditionsAcces, Contact, + Courriel, LabelsNationaux, Localisation, ModalitesAccompagnement, @@ -45,7 +46,7 @@ export const typologiesIfAny = (typologies?: string): { typologies?: Typologies const telephoneIfAny = (telephone?: string): { telephone?: string } => (telephone == null ? {} : { telephone }); -const courrielIfAny = (courriel?: string): { courriel?: string } => (courriel == null ? {} : { courriel }); +const courrielIfAny = (courriel?: string): { courriel?: Courriel[] } => (courriel == null ? {} : { courriel: listFromString(courriel) }); const siteWebIfAny = (siteWeb?: string): { site_web?: Url[] } => (siteWeb == null ? {} : { site_web: listFromString(siteWeb) }); diff --git a/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique.spec.ts b/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique.spec.ts index 64f498a..fdb629a 100644 --- a/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique.spec.ts +++ b/src/transfer/schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique/from-schema-lieux-de-mediation-numerique.spec.ts @@ -6,6 +6,7 @@ import { ConditionAcces, ConditionsAcces, Contact, + Courriel, Id, LabelNational, LabelsNationaux, @@ -140,7 +141,7 @@ describe('from schema lieux de mediation numerique', (): void => { typologies: Typologies([Typologie.TIERS_LIEUX]), contact: Contact({ telephone: '+33180059880', - courriel: 'contact@laquincaillerie.tl', + courriel: [Courriel('contact@laquincaillerie.tl')], site_web: [Url('https://www.laquincaillerie.tl/'), Url('https://m.facebook.com/laquincaillerienumerique/')] }), horaires: 'Mo-Fr 09:00-12:00,14:00-18:30; Sa 08:30-12:00', diff --git a/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique-fields.ts b/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique-fields.ts index f95a40e..e4ac401 100644 --- a/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique-fields.ts +++ b/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique-fields.ts @@ -44,7 +44,7 @@ export const localisationFields = ( export const contactFields = (lieuMediationNumerique: LieuMediationNumerique): SchemaLieuMediationNumeriqueContactFields => ({ ...(lieuMediationNumerique.contact?.telephone == null ? {} : { telephone: lieuMediationNumerique.contact.telephone }), - ...(lieuMediationNumerique.contact?.courriel == null ? {} : { courriel: lieuMediationNumerique.contact.courriel }), + ...(lieuMediationNumerique.contact?.courriel == null ? {} : { courriel: lieuMediationNumerique.contact.courriel.join(';') }), ...(lieuMediationNumerique.contact?.site_web == null ? {} : { site_web: lieuMediationNumerique.contact.site_web.join(';') }) }); diff --git a/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique.spec.ts b/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique.spec.ts index e9a9baa..ccb3675 100644 --- a/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique.spec.ts +++ b/src/transfer/schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique/to-schema-lieux-de-mediation-numerique.spec.ts @@ -6,6 +6,7 @@ import { ConditionAcces, ConditionsAcces, Contact, + Courriel, Id, LabelNational, LabelsNationaux, @@ -97,7 +98,7 @@ describe('to schema lieux de mediation numerique', (): void => { typologies: Typologies([Typologie.TIERS_LIEUX]), contact: Contact({ telephone: '+33180059880', - courriel: 'contact@laquincaillerie.tl', + courriel: [Courriel('contact@laquincaillerie.tl')], site_web: [Url('https://www.laquincaillerie.tl/'), Url('https://m.facebook.com/laquincaillerienumerique/')] }), horaires: 'Mo-Fr 09:00-12:00,14:00-18:30; Sa 08:30-12:00',