Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow multi email in contact field #50

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions src/models/contact/contact.spec.ts
Original file line number Diff line number Diff line change
@@ -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: '[email protected]',
courriel: [Courriel('[email protected]')],
site_web: [Url('http://www.cartographienationale.fr')]
};

Expand All @@ -29,7 +30,7 @@ describe('contact model', (): void => {

it('should create a valid contact with only courriel property', (): void => {
const contactData: ContactToValidate = {
courriel: '[email protected]'
courriel: [Courriel('[email protected]')]
};

const contact: Contact = Contact(contactData);
Expand All @@ -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: '[email protected]',
courriel: [Courriel('[email protected]')],
site_web: [Url('https://www.facebook.com/YenkumuLutuPapaichton/')]
};

Expand All @@ -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'
Expand Down
18 changes: 5 additions & 13 deletions src/models/contact/contact.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,30 @@
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[];
/* eslint-disable-next-line @typescript-eslint/naming-convention */
site_web?: Url[];
}
>;

export type ContactToValidate = Omit<Contact, 'isContact'>;

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, 'isContact'>): 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, 'isContact'>): 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);
}
Expand Down
1 change: 0 additions & 1 deletion src/models/contact/errors/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './courriel.error';
export * from './telephone.error';
20 changes: 20 additions & 0 deletions src/models/courriel/courriel.spec.ts
Original file line number Diff line number Diff line change
@@ -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 = '[email protected]';

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));
});
});
16 changes: 16 additions & 0 deletions src/models/courriel/courriel.ts
Original file line number Diff line number Diff line change
@@ -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));
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ModelError } from '../../../errors';
import { Contact } from '../contact';

export class CourrielError extends ModelError<Contact> {
export class CourrielError extends ModelError<{ courriel: string }> {
constructor(courriel: string) {
super('courriel', `Le courriel ${courriel} n'est pas valide`);
}
Expand Down
1 change: 1 addition & 0 deletions src/models/courriel/errors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './courriel.error';
2 changes: 2 additions & 0 deletions src/models/courriel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './errors';
export * from './courriel';
1 change: 1 addition & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './url';
export * from './lieu-mediation-numerique';
export * from './model';
export * from './presentation';
export * from './courriel';
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ConditionAcces,
ConditionsAcces,
Contact,
Courriel,
LabelNational,
LabelsNationaux,
Localisation,
Expand Down Expand Up @@ -172,9 +173,9 @@ 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) })
...(site_web == null ? {} : { site_web: site_web.split('|').map(Url) })
})
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ConditionAcces,
ConditionsAcces,
Contact,
Courriel,
Id,
LabelNational,
LabelsNationaux,
Expand Down Expand Up @@ -76,9 +77,9 @@ describe('from schema data inclusion', (): void => {
siret: '43493312300029',
source: 'Hubik',
accessibilite: 'https://acceslibre.beta.gouv.fr/app/29-lampaul-plouarzel/a/bibliotheque-mediatheque/erp/mediatheque-13/',
courriel: '[email protected]',
courriel: '[email protected]|[email protected]',
telephone: '+33180059880',
site_web: 'https://www.laquincaillerie.tl/;https://m.facebook.com/laquincaillerienumerique/',
site_web: 'https://www.laquincaillerie.tl/|https://m.facebook.com/laquincaillerienumerique/',
horaires_ouverture: 'Mo-Fr 09:00-12:00,14:00-18:30; Sa 08:30-12:00',
labels_nationaux: ['france-service', 'aptic'],
labels_autres: ['SudLabs', 'Nièvre médiation numérique'],
Expand Down Expand Up @@ -170,7 +171,7 @@ describe('from schema data inclusion', (): void => {
typologies: Typologies([Typologie.TIERS_LIEUX]),
contact: Contact({
telephone: '+33180059880',
courriel: '[email protected]',
courriel: [Courriel('[email protected]'), Courriel('[email protected]')],
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',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/naming-convention, camelcase */

import { isValidTelephone, isValidCourriel } from '../../../models';
import {
SchemaServiceDataInclusion,
SchemaServiceDataInclusionWithAdresse,
Expand All @@ -12,7 +13,6 @@ import {
SchemaStructureDataInclusionPresentationFields,
SchemaStructureDataInclusionStructureGeneralFields
} from '../schema-data-inclusion';
import { isValidCourriel, isValidTelephone } from '../../../models';

export const isServiceWithAdresse = (
service: Partial<SchemaStructureDataInclusionAdresseFields> & SchemaServiceDataInclusion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[] } =>
Expand Down Expand Up @@ -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())
: {})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ConditionAcces,
ConditionsAcces,
Contact,
Courriel,
Id,
LabelNational,
LabelsNationaux,
Expand Down Expand Up @@ -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: '[email protected]'
courriel: [Courriel('[email protected]')]
}),
horaires: 'Mo-Fr 10:00-20:00 "sur rendez-vous"; PH off',
presentation: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CleBan,
ConditionsAcces,
Contact,
Courriel,
LabelsNationaux,
Localisation,
ModalitesAccompagnement,
Expand Down Expand Up @@ -45,7 +46,8 @@ 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) });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ConditionAcces,
ConditionsAcces,
Contact,
Courriel,
Id,
LabelNational,
LabelsNationaux,
Expand Down Expand Up @@ -140,7 +141,7 @@ describe('from schema lieux de mediation numerique', (): void => {
typologies: Typologies([Typologie.TIERS_LIEUX]),
contact: Contact({
telephone: '+33180059880',
courriel: '[email protected]',
courriel: [Courriel('[email protected]')],
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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ 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?.site_web == null ? {} : { site_web: lieuMediationNumerique.contact.site_web.join(';') })
...(lieuMediationNumerique.contact?.courriel == null ? {} : { courriel: lieuMediationNumerique.contact.courriel.join('|') }),
...(lieuMediationNumerique.contact?.site_web == null ? {} : { site_web: lieuMediationNumerique.contact.site_web.join('|') })
});

export const presentationFields = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ConditionAcces,
ConditionsAcces,
Contact,
Courriel,
Id,
LabelNational,
LabelsNationaux,
Expand Down Expand Up @@ -97,7 +98,7 @@ describe('to schema lieux de mediation numerique', (): void => {
typologies: Typologies([Typologie.TIERS_LIEUX]),
contact: Contact({
telephone: '+33180059880',
courriel: '[email protected]',
courriel: [Courriel('[email protected]')],
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',
Expand Down Expand Up @@ -142,7 +143,7 @@ describe('to schema lieux de mediation numerique', (): void => {
typologie: 'TIERS_LIEUX',
telephone: '+33180059880',
courriel: '[email protected]',
site_web: 'https://www.laquincaillerie.tl/;https://m.facebook.com/laquincaillerienumerique/',
site_web: 'https://www.laquincaillerie.tl/|https://m.facebook.com/laquincaillerienumerique/',
horaires: 'Mo-Fr 09:00-12:00,14:00-18:30; Sa 08:30-12:00',
presentation_resume:
'Notre association propose des formations aux outils numériques à destination des personnes âgées.',
Expand Down
Loading