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

✨ Considérer les emails case-insensitive #2603

Merged
merged 7 commits into from
Feb 3, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getLogger } from '@potentiel-libraries/monitoring';
import { Candidature } from '@potentiel-domain/candidature';
import { Option } from '@potentiel-libraries/monads';
import { AppelOffre } from '@potentiel-domain/appel-offre';
import { IdentifiantProjet } from '@potentiel-domain/common';
import { Email, IdentifiantProjet } from '@potentiel-domain/common';

import { buildCertificate, BuildCertificateProps } from './buildCertificate';

Expand Down Expand Up @@ -170,7 +170,7 @@ export const register = () => {
const mapCorrectionToCandidature = (
payload: Candidature.CandidatureCorrigéeEvent['payload'],
): BuildCertificateProps['candidature'] => ({
emailContact: payload.emailContact,
emailContact: Email.convertirEnValueType(payload.emailContact),
evaluationCarboneSimplifiée: payload.evaluationCarboneSimplifiée,
localité: payload.localité,
nomCandidat: payload.nomCandidat,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from 'node:path';
import ReactPDF, { Font } from '@react-pdf/renderer';

import { AppelOffre } from '@potentiel-domain/appel-offre';
import { DateTime, IdentifiantProjet } from '@potentiel-domain/common';
import { DateTime, Email, IdentifiantProjet } from '@potentiel-domain/common';
import { Candidature } from '@potentiel-domain/candidature';

import { fontsFolderPath, imagesFolderPath } from '../../assets';
Expand Down Expand Up @@ -48,7 +48,7 @@ export type BuildCertificateProps = {
};
nomCandidat: string;
nomReprésentantLégal: string;
emailContact: string;
emailContact: Email.ValueType;
puissanceProductionAnnuelle: number;
prixReference: number;
technologie: Candidature.TypeTechnologie.ValueType;
Expand Down Expand Up @@ -133,7 +133,7 @@ const mapToCertificateData = ({

nomCandidat: candidature.nomCandidat,
nomRepresentantLegal: candidature.nomReprésentantLégal,
email: candidature.emailContact,
email: candidature.emailContact.formatter(),

evaluationCarbone: candidature.evaluationCarboneSimplifiée,
prixReference: candidature.prixReference,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ export const register = ({ sendEmail }: RegisterCandidatureNotificationDependenc
templateId: templateId.attestationRegénéréePorteur,
messageSubject: `Potentiel - Une nouvelle attestation est disponible pour le projet ${candidature.nomProjet}`,
recipients: [
{ email: candidature.emailContact, fullName: candidature.nomReprésentantLégal },
{
email: candidature.emailContact.formatter(),
fullName: candidature.nomReprésentantLégal,
},
],
variables: {
nom_projet: candidature.nomProjet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async function getEmailPayloads(
templateId: templateId.notifierPorteur,
recipients: [
{
email,
email: email.formatter(),
fullName,
},
],
Expand Down
5 changes: 3 additions & 2 deletions packages/applications/request-context/src/convertToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { z } from 'zod';
import { jwtVerify } from 'jose';

import { PlainType } from '@potentiel-domain/core';
import { Role, Groupe, IdentifiantUtilisateur, Utilisateur } from '@potentiel-domain/utilisateur';
import { Role, Groupe, Utilisateur } from '@potentiel-domain/utilisateur';
import { Option } from '@potentiel-libraries/monads';
import { Email } from '@potentiel-domain/common';

import { getJwks } from './openid';

Expand Down Expand Up @@ -36,6 +37,6 @@ export const convertToken = async (
role: Role.convertirEnValueType(role ?? ''),
groupe: groupe ? Groupe.convertirEnValueType(groupe) : Option.none,
nom,
identifiantUtilisateur: IdentifiantUtilisateur.convertirEnValueType(email),
identifiantUtilisateur: Email.convertirEnValueType(email),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const mapToProps: MapToProps = (candidature) => ({
nomProjet: candidature.nomProjet,
nomCandidat: candidature.nomCandidat,
nomRepresentantLegal: candidature.nomReprésentantLégal,
emailContact: candidature.emailContact,
emailContact: candidature.emailContact.formatter(),
puissanceProductionAnnuelle: candidature.puissanceProductionAnnuelle,
prixReference: candidature.prixReference,
societeMere: candidature.sociétéMère,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ export const DétailsCandidaturePage: FC<DétailsCandidaturePageProps> = ({
<Field name="Nom du représentant légal">{candidature.nomReprésentantLégal}</Field>
<Field name="Adresse email à la candidature">
<span>
<a href={`mailto:${candidature.emailContact}`}>{candidature.emailContact}</a>
<a href={`mailto:${candidature.emailContact.email}`}>
{candidature.emailContact.email}
</a>
</span>
</Field>
</FieldGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const CandidatureNonNotifiée: Story = {
statut: Candidature.StatutCandidature.classé,
nomProjet: 'Nom projet',
nomCandidat: 'Candidat',
emailContact: '[email protected]',
emailContact: Email.convertirEnValueType('[email protected]'),
localité: {
commune: 'Commune',
département: 'Département',
Expand Down Expand Up @@ -63,7 +63,7 @@ export const CandidatureNotifiée: Story = {
statut: Candidature.StatutCandidature.classé,
nomProjet: 'Nom projet',
nomCandidat: 'Candidat',
emailContact: '[email protected]',
emailContact: Email.convertirEnValueType('[email protected]'),
localité: {
commune: 'Commune',
département: 'Département',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';

import { IdentifiantProjet } from '@potentiel-domain/common';
import { Email, IdentifiantProjet } from '@potentiel-domain/common';
import { Candidature } from '@potentiel-domain/candidature';

import { CandidatureListPage, CandidatureListPageProps } from './CandidatureList.page';
Expand Down Expand Up @@ -29,7 +29,7 @@ const commonItem: CommonItem = {
statut: Candidature.StatutCandidature.classé,
nomProjet: 'Nom projet',
nomCandidat: 'Candidat',
emailContact: '[email protected]',
emailContact: Email.convertirEnValueType('[email protected]'),
localité: {
commune: 'Commune',
département: 'Département',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC } from 'react';

import { PlainType } from '@potentiel-domain/core';
import { IdentifiantProjet } from '@potentiel-domain/common';
import { Email, IdentifiantProjet } from '@potentiel-domain/common';
import { Candidature } from '@potentiel-domain/candidature';
import { AppelOffre } from '@potentiel-domain/appel-offre';

Expand All @@ -21,7 +21,7 @@ export type CandidatureListItemProps = {
nomProjet: Candidature.ConsulterCandidatureReadModel['nomProjet'];
nomCandidat: Candidature.ConsulterCandidatureReadModel['nomCandidat'];
nomReprésentantLégal: Candidature.ConsulterCandidatureReadModel['nomReprésentantLégal'];
emailContact: Candidature.ConsulterCandidatureReadModel['emailContact'];
emailContact: PlainType<Email.ValueType>;
puissanceProductionAnnuelle: Candidature.ConsulterCandidatureReadModel['puissanceProductionAnnuelle'];
prixReference: Candidature.ConsulterCandidatureReadModel['prixReference'];
evaluationCarboneSimplifiée: Candidature.ConsulterCandidatureReadModel['evaluationCarboneSimplifiée'];
Expand Down Expand Up @@ -91,8 +91,8 @@ export const CandidatureListItem: FC<CandidatureListItemProps> = ({
/>
<div className="flex flex-col overflow-hidden">
<div>{nomReprésentantLégal}</div>
<div className="truncate" title={emailContact}>
{emailContact}
<div className="truncate" title={emailContact.email}>
{emailContact.email}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type ConsulterCandidatureReadModel = {
};
nomCandidat: string;
nomReprésentantLégal: string;
emailContact: string;
emailContact: Email.ValueType;
puissanceProductionAnnuelle: number;
prixReference: number;
technologie: TypeTechnologie.ValueType;
Expand Down Expand Up @@ -115,7 +115,7 @@ export const mapToReadModel = ({
localité,
nomCandidat,
nomReprésentantLégal,
emailContact,
emailContact: Email.convertirEnValueType(emailContact),
puissanceProductionAnnuelle,
prixReference,
sociétéMère,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type CandidatureImportéeEventCommonPayload = {
prixReference: number;
noteTotale: number;
nomReprésentantLégal: string;
emailContact: string;
emailContact: Email.RawType;
localité: {
adresse1: string;
adresse2: string;
Expand Down Expand Up @@ -70,7 +70,7 @@ export type ImporterCandidatureBehaviorCommonOptions = {
prixReference: number;
noteTotale: number;
nomReprésentantLégal: string;
emailContact: string;
emailContact: Email.ValueType;
localité: {
adresse1: string;
adresse2: string;
Expand Down Expand Up @@ -194,7 +194,7 @@ export const mapToEventPayload = (candidature: ImporterCandidatureBehaviorCommon
prixReference: candidature.prixReference,
noteTotale: candidature.noteTotale,
nomReprésentantLégal: candidature.nomReprésentantLégal,
emailContact: candidature.emailContact,
emailContact: candidature.emailContact.formatter(),
localité: candidature.localité,
motifÉlimination: candidature.motifÉlimination,
puissanceALaPointe: candidature.puissanceALaPointe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type ImporterCandidatureCommandCommonOptions = {
prixReference: number;
noteTotale: number;
nomReprésentantLégal: string;
emailContact: string;
emailContact: Email.ValueType;
localité: {
adresse1: string;
adresse2: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const mapPayloadForCommand = (payload: ImporterCandidatureUseCaseCommonPa
historiqueAbandon: HistoriqueAbandon.convertirEnValueType(payload.historiqueAbandonValue),
nomProjet: payload.nomProjetValue,
localité: payload.localitéValue,
emailContact: payload.emailContactValue,
emailContact: Email.convertirEnValueType(payload.emailContactValue),
evaluationCarboneSimplifiée: payload.evaluationCarboneSimplifiéeValue,
nomCandidat: payload.nomCandidatValue,
nomReprésentantLégal: payload.nomReprésentantLégalValue,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message, MessageHandler, mediator } from 'mediateur';

import { List, RangeOptions, Where } from '@potentiel-domain/entity';
import { IdentifiantProjet } from '@potentiel-domain/common';
import { Email, IdentifiantProjet } from '@potentiel-domain/common';
import { DocumentProjet } from '@potentiel-domain/document';

import * as StatutCandidature from '../statutCandidature.valueType';
Expand Down Expand Up @@ -120,7 +120,7 @@ export const mapToReadModel = ({
nomProjet,
nomCandidat,
nomReprésentantLégal,
emailContact,
emailContact: Email.convertirEnValueType(emailContact),
puissanceProductionAnnuelle,
prixReference,
evaluationCarboneSimplifiée,
Expand Down
4 changes: 2 additions & 2 deletions packages/domain/common/src/valueTypes/email.valueType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export const bind = ({ email }: PlainType<ValueType>): ValueType => {

export const convertirEnValueType = (value: string): ValueType => {
return bind({
email: value,
email: value.toLowerCase(),
});
benjlevesque marked this conversation as resolved.
Show resolved Hide resolved
};

const regexEmail = /^[a-zA-Z0-9.+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
const regexEmail = /^[a-z0-9.+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9-]+)*$/;

export const system = () => convertirEnValueType('system@system');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ export const bind = ({ email }: PlainType<ValueType>): ValueType => {
*/
export const convertirEnValueType = (value: string): ValueType => {
return bind({
email: value,
email: value.toLowerCase(),
});
};

/**
* @deprecated Use potentiel-domain/common Email ValueType instead
*/
const regexEmail = /^[a-zA-Z0-9.+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
const regexEmail = /^[a-z0-9.+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9-]+)*$/;

/**
* @deprecated Use potentiel-domain/common Email ValueType instead
Expand Down
6 changes: 3 additions & 3 deletions packages/domain/utilisateur/src/utilisateur.valueType.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { PlainType, ReadonlyValueType } from '@potentiel-domain/core';
import { Option } from '@potentiel-libraries/monads';
import { Email } from '@potentiel-domain/common';

import * as Role from './role.valueType';
import * as Groupe from './groupe.valueType';
import * as IdentifiantUtilisateur from './identifiantUtilisateur.valueType';

export type ValueType = ReadonlyValueType<{
nom: string;
identifiantUtilisateur: IdentifiantUtilisateur.ValueType;
identifiantUtilisateur: Email.ValueType;
role: Role.ValueType;
groupe: Option.Type<Groupe.ValueType>;
}>;
Expand All @@ -18,7 +18,7 @@ export const bind = ({
groupe,
role,
}: PlainType<ValueType>): ValueType => {
const _identifiantUtilisateur = IdentifiantUtilisateur.bind(identifiantUtilisateur);
const _identifiantUtilisateur = Email.bind(identifiantUtilisateur);
return {
nom,
role: Role.bind(role),
Expand Down
4 changes: 2 additions & 2 deletions packages/specifications/src/candidature/candidature.world.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Candidature } from '@potentiel-domain/candidature';
import { DateTime, IdentifiantProjet } from '@potentiel-domain/common';
import { DateTime, Email, IdentifiantProjet } from '@potentiel-domain/common';
import { DocumentProjet } from '@potentiel-domain/document';

import { CorrigerCandidatureFixture } from './fixtures/corrigerCandidature.fixture';
Expand Down Expand Up @@ -91,7 +91,7 @@ export class CandidatureWorld {
dateÉchéanceGf: expectedValues.dateÉchéanceGfValue
? DateTime.convertirEnValueType(expectedValues.dateÉchéanceGfValue)
: undefined,
emailContact: expectedValues.emailContactValue,
emailContact: Email.convertirEnValueType(expectedValues.emailContactValue),
evaluationCarboneSimplifiée: expectedValues.evaluationCarboneSimplifiéeValue,
historiqueAbandon: Candidature.HistoriqueAbandon.convertirEnValueType(
expectedValues.historiqueAbandonValue,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { assert } from 'chai';

import { EmailPayload } from '@potentiel-applications/notifications';
import { Email } from '@potentiel-domain/common';

export class NotificationWorld {
#notifications: EmailPayload[] = [];
Expand All @@ -9,10 +10,11 @@ export class NotificationWorld {
this.#notifications.push(notification);
}

récupérerNotification(email: string, sujet?: string) {
récupérerNotification(emailValue: string, sujet?: string) {
const email = Email.convertirEnValueType(emailValue);
const notif = this.#notifications.find(
(notif) =>
notif.recipients.find((r) => r.email === email) &&
notif.recipients.find((r) => Email.convertirEnValueType(r.email).estÉgaleÀ(email)) &&
(!sujet || notif.messageSubject.match(new RegExp(sujet))),
);
assert(notif, 'Pas de notification');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export abstract class AbstractUtilisateur implements Utilisateur {

protected créer(partial?: Partial<Readonly<Omit<Utilisateur, 'role>'>>>): Readonly<Utilisateur> {
const utilisateur: Utilisateur = {
email: faker.internet.email(),
email: faker.internet.email().toLowerCase(),
nom: faker.person.fullName(),
id: faker.string.uuid(),
...partial,
Expand Down