Skip to content

Commit

Permalink
feat: route de déconnexion (compat. france connect) (#926)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matteo-OCTO authored Feb 14, 2025
1 parent 02215c5 commit 7b85aef
Show file tree
Hide file tree
Showing 29 changed files with 159 additions and 42 deletions.
18 changes: 13 additions & 5 deletions src/components/custom/Compte/CompteSkeleton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,23 @@
<script setup lang="ts">
import CompteMenuLateral from '@/components/custom/Compte/CompteMenuLateral.vue';
import FilDAriane from '@/components/dsfr/FilDAriane.vue';
import { SessionRepositoryStore } from '@/domaines/authentification/adapters/session.repository.store';
import { UtilisateurRepositoryAxios } from '@/domaines/authentification/adapters/utilisateur.repository.axios';
import { DeconnecterUtilisateurUsecase } from '@/domaines/authentification/deconnecterUtilisateur.usecase';
import router from '@/router';
import { utilisateurStore } from '@/store/utilisateur';
const store = utilisateurStore();
defineProps<{ pageCourante: string }>();
const logout = () => {
store.reset();
router.replace('/');
const utilisateurId = utilisateurStore().utilisateur.id;
const seDeconnecterUsecase = new DeconnecterUtilisateurUsecase(
new UtilisateurRepositoryAxios(),
new SessionRepositoryStore(),
);
const logout = async () => {
await seDeconnecterUsecase.execute(utilisateurId).finally(async () => {
await router.replace('/');
});
};
</script>
16 changes: 13 additions & 3 deletions src/components/dsfr/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@
import { RouteAidesName } from '@/router/aides/routeAidesName';
import { RouteThematiquesName } from '@/router/thematiques/routes';
import { ClefThematiqueAPI, MenuThematiques } from '@/domaines/thematiques/MenuThematiques';
import { DeconnecterUtilisateurUsecase } from '@/domaines/authentification/deconnecterUtilisateur.usecase';
import { UtilisateurRepositoryAxios } from '@/domaines/authentification/adapters/utilisateur.repository.axios';
import { SessionRepositoryStore } from '@/domaines/authentification/adapters/session.repository.store';
const route = useRoute();
const store = utilisateurStore();
Expand All @@ -218,9 +221,16 @@
() => estConnecte.value && !store.utilisateur.onboardingAEteRealise,
);
const logout = () => {
store.reset();
router.replace('/');
const utilisateurId = utilisateurStore().utilisateur.id;
const seDeconnecterUsecase = new DeconnecterUtilisateurUsecase(
new UtilisateurRepositoryAxios(),
new SessionRepositoryStore(),
);
const logout = async () => {
await seDeconnecterUsecase.execute(utilisateurId).finally(async () => {
await router.push('/');
});
};
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { Utilisateur } from '@/domaines/authentification/ports/utilisateur.repository';
import { Score } from '@/domaines/score/ports/score.repository';
import { utilisateurStore } from '@/store/utilisateur';
Expand All @@ -15,4 +15,8 @@ export class SessionRepositoryStore implements SessionRepository {
sauvegarderScore(score: Score): void {
utilisateurStore().setScore(score);
}

deconnecterUtilisateur() {
utilisateurStore().reset();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,9 @@ export class UtilisateurRepositoryAxios implements UtilisateurRepository {
token: response.data.token,
};
}

async deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
const axiosInstance = AxiosFactory.getAxios();
await axiosInstance.post(`/utilisateurs/${idUtilisateur}/logout`, {});
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import { Utilisateur, UtilisateurRepository } from '@/domaines/authentification/ports/utilisateur.repository';
import { Score } from '@/domaines/score/ports/score.repository';

export interface SessionRepository {
sauvegarderUtilisateur(utilisateur: Partial<Utilisateur>): void;

sauvegarderScore(score: Score): void;
}
import { UtilisateurRepository } from '@/domaines/authentification/ports/utilisateur.repository';

export class AuthentifierUtilisateurUsecase {
constructor(private readonly utilisateurRepository: UtilisateurRepository) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { AuthentificationResultatPresenter } from '@/domaines/authentification/ports/authentificationResultatPresenter';
import { PostOnboardingRepository } from '@/domaines/authentification/ports/postOnboarding.repository';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { UtilisateurRepository } from '@/domaines/authentification/ports/utilisateur.repository';
import { AuthentificationResultat } from '@/domaines/authentification/validerAuthentificationUtilisateur.usecase';

Expand Down
14 changes: 14 additions & 0 deletions src/domaines/authentification/deconnecterUtilisateur.usecase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { UtilisateurRepository } from '@/domaines/authentification/ports/utilisateur.repository';

export class DeconnecterUtilisateurUsecase {
constructor(
private utilisateurRepository: UtilisateurRepository,
private sessionRepository: SessionRepository,
) {}

async execute(utilisateurId: string): Promise<void> {
await this.utilisateurRepository.deconnecterUtilisateur(utilisateurId);
this.sessionRepository.deconnecterUtilisateur();
}
}
10 changes: 10 additions & 0 deletions src/domaines/authentification/ports/session.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Utilisateur } from '@/domaines/authentification/ports/utilisateur.repository';
import { Score } from '@/domaines/score/ports/score.repository';

export interface SessionRepository {
sauvegarderUtilisateur(utilisateur: Partial<Utilisateur>): void;

sauvegarderScore(score: Score): void;

deconnecterUtilisateur(): void;
}
2 changes: 2 additions & 0 deletions src/domaines/authentification/ports/utilisateur.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ export interface UtilisateurRepository {
terminerRedefinirMotDePasse(email: string, motDePasse: string, code: string): Promise<void>;

seConnecterAvecFranceConnect(oidcCode: string, oidcState: string): Promise<Utilisateur>;

deconnecterUtilisateur(idUtilisateur: string): Promise<void>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { AuthentificationResultatPresenter } from '@/domaines/authentification/ports/authentificationResultatPresenter';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { UtilisateurRepository } from '@/domaines/authentification/ports/utilisateur.repository';

export enum AuthentificationResultat {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { UtilisateurRepository } from '@/domaines/authentification/ports/utilisateur.repository';

export class ValiderCompteUtilisateurUsecase {
Expand Down
2 changes: 1 addition & 1 deletion src/domaines/compte/chargerCompteUtilisateur.usecase.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { CompteUtilisateurPresenter } from '@/domaines/compte/ports/compteUtilisateur.presenter';
import { CompteUtilisateurRepository } from '@/domaines/compte/ports/compteUtilisateur.repository';

Expand Down
2 changes: 1 addition & 1 deletion src/domaines/compte/creerCompteUtilisateur.usecase.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { CompteUtilisateurRepository } from '@/domaines/compte/ports/compteUtilisateur.repository';
import { CreerComptePresenter } from '@/domaines/compte/ports/creerComptePresenter';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { CompteUtilisateurRepository } from '@/domaines/compte/ports/compteUtilisateur.repository';
import { OnboardingPostCreationCompteState } from '@/store/onboardingPostCreationCompte';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { ProfileUtilisateurViewModel } from '@/domaines/profileUtilisateur/adapters/profileUtilisateur.presenter.impl';
import { ProfileUtilisateurRepository } from '@/domaines/profileUtilisateur/ports/profileUtilisateur.repository';

Expand Down
2 changes: 1 addition & 1 deletion src/domaines/score/chargementScore.usecase.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionRepository } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SessionRepository } from '@/domaines/authentification/ports/session.repository';
import { ScoreRepository } from '@/domaines/score/ports/score.repository';

export class ChargementScoreUsecase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
UtilisateurRepository,
} from '@/domaines/authentification/ports/utilisateur.repository';

export class MockUtilisateurRepository implements UtilisateurRepository {
export class UtilisateurRepositoryMock implements UtilisateurRepository {
authentifierUtilisateur(email: string, motDePasse: string): Promise<void> {
throw Error;
}
Expand Down Expand Up @@ -62,4 +62,8 @@ export class MockUtilisateurRepository implements UtilisateurRepository {
token: 'token',
});
}

deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
return Promise.resolve();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
UtilisateurRepository,
} from '@/domaines/authentification/ports/utilisateur.repository';

export class SpyUtilisateurRepository implements UtilisateurRepository {
export class UtilisateurRepositorySpy implements UtilisateurRepository {
constructor() {}

private _authentifierUtilisateurArgs: { motDePasse: string; nomUtilisateur: string } | null = null;
Expand All @@ -13,6 +13,12 @@ export class SpyUtilisateurRepository implements UtilisateurRepository {
return this._authentifierUtilisateurArgs;
}

private _utilisateurAEteDeco: boolean = false;

get utilisateurAEteDeco(): boolean {
return this._utilisateurAEteDeco;
}

authentifierUtilisateur(nomUtilisateur: string, motDePasse: string): Promise<void> {
this._authentifierUtilisateurArgs = { nomUtilisateur, motDePasse };
return Promise.resolve();
Expand Down Expand Up @@ -45,4 +51,9 @@ export class SpyUtilisateurRepository implements UtilisateurRepository {
seConnecterAvecFranceConnect(oidcCode: string, oidcState: string): Promise<Utilisateur> {
throw Error;
}

deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
this._utilisateurAEteDeco = true;
return Promise.resolve();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ export class UtilisateurRepositoryForTest implements UtilisateurRepository {
afficherDisclaimerAides: false,
});
}

deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
throw Error;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { AuthentifierUtilisateurUsecase } from '@/domaines/authentification/authentifierUtilisateur.usecase';
import { SpyUtilisateurRepository } from './adapters/spyUtilisateurRepository';
import { UtilisateurRepositorySpy } from './adapters/utilisateur.repository.spy';

describe("Fichier de tests concernant l'authentification ", () => {
it("Lorsque je passe un email et un mot de passe doit lancer le processus d'authentification", async () => {
// GIVEN
const spyUtilisateurRepository = new SpyUtilisateurRepository();
const spyUtilisateurRepository = new UtilisateurRepositorySpy();
const usecase = new AuthentifierUtilisateurUsecase(spyUtilisateurRepository);
// WHEN
await usecase.execute('[email protected]', '123');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { SpySauvegarderUtilisateurSessionRepository } from '../compte/sessionRepository.sauvegarderUtilisateur.spy';
import { MockUtilisateurRepository } from './adapters/mockUtilisateurRepository';
import { Utilisateur } from '@/domaines/authentification/ports/utilisateur.repository';
import { AuthentifierUtilisateurFranceConnectUsecase } from '@/domaines/authentification/authentifierUtilisateurFranceConnect.usecase';
import { AuthentificationResultatPresenterImpl } from '@/domaines/authentification/adapters/authentificationResultatPresenterImpl';
import { UtilisateurRepositoryForTest } from './adapters/utilisateurRepositoryForTest';
import { RouteComptePath } from '@/router/compte/routes';
import { RouteCoachPath } from '@/router/coach/routes';
import { PostOnboardingRepositorySpy } from './adapters/postOnboarding.repository.spy';
import { UtilisateurRepositoryMock } from './adapters/utilisateur.repository.mock';

describe("Fichier de tests concernant l'authentification France Connect", () => {
it("En donnant un state et un code doit valider l'authentification puis le sauvegarder en session", async () => {
Expand All @@ -15,7 +15,7 @@ describe("Fichier de tests concernant l'authentification France Connect", () =>
const spySessionRepository = SpySauvegarderUtilisateurSessionRepository.sansOnBoardingRealise();
const spyPostOnboardingRepositorySpy = new PostOnboardingRepositorySpy();
const usecase = new AuthentifierUtilisateurFranceConnectUsecase(
new MockUtilisateurRepository(),
new UtilisateurRepositoryMock(),
spySessionRepository,
spyPostOnboardingRepositorySpy,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class SpyUtilisateurRepository implements UtilisateurRepository {
seConnecterAvecFranceConnect(oidcCode: string, oidcState: string): Promise<Utilisateur> {
throw Error;
}

deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
throw Error('not implemented yet');
}
}

describe('Fichier de tests concernant la réinitialisation du mot de passe', () => {
Expand Down
32 changes: 32 additions & 0 deletions tests/authentification/deconnecterUtilisateur.usecase.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { DeconnecterUtilisateurUsecase } from '@/domaines/authentification/deconnecterUtilisateur.usecase';
import { UtilisateurRepositorySpy } from './adapters/utilisateur.repository.spy';
import { SpySauvegarderUtilisateurSessionRepository } from '../compte/sessionRepository.sauvegarderUtilisateur.spy';
import { expect } from 'vitest';

describe("Fichier de tests concernant la déconnexion d'un compte utilisateur", () => {
it("L'utilisateur est déconnecté du service et sa session est terminée", async () => {
// GIVEN
const utilisateurRepository = new UtilisateurRepositorySpy();
const sessionRepository = SpySauvegarderUtilisateurSessionRepository.avecOnBoardingRealise({
id: 'id',
mail: 'mail',
prenom: 'prenom',
nom: 'nom',
});

// WHEN
const usecase = new DeconnecterUtilisateurUsecase(utilisateurRepository, sessionRepository);
await usecase.execute('utilisateurId');

// THEN
expect(sessionRepository.utilisateur).toStrictEqual({
id: '',
mail: '',
prenom: '',
nom: '',
onboardingAEteRealise: false,
afficherDisclaimerAides: false,
});
expect(utilisateurRepository.utilisateurAEteDeco).toBeTruthy();
});
});
4 changes: 4 additions & 0 deletions tests/authentification/renvoyerCodeOTP.usecase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class SpyUtilisateurRepository implements UtilisateurRepository {
seConnecterAvecFranceConnect(oidcCode: string, oidcState: string): Promise<Utilisateur> {
throw Error;
}

deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
throw Error('not implemented yet');
}
}

describe('Fichier de tests concernant le renvoie du code OTP', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class SpyUtilisateurRepository implements UtilisateurRepository {
seConnecterAvecFranceConnect(oidcCode: string, oidcState: string): Promise<Utilisateur> {
throw Error;
}
deconnecterUtilisateur(idUtilisateur: string): Promise<void> {
throw Error;
}
}

describe('Fichier de tests concernant la fin de la réinitialisation du mot de passe', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Utilisateur } from '@/domaines/authentification/ports/utilisateur.repository';
import { SpySauvegarderUtilisateurSessionRepository } from '../compte/sessionRepository.sauvegarderUtilisateur.spy';
import { MockUtilisateurRepository } from './adapters/mockUtilisateurRepository';
import { UtilisateurRepositoryMock } from './adapters/utilisateur.repository.mock';
import { AuthentificationResultatPresenterImpl } from '@/domaines/authentification/adapters/authentificationResultatPresenterImpl';
import { ValiderAuthentificationUtilisateurUsecase } from '@/domaines/authentification/validerAuthentificationUtilisateur.usecase';
import { RouteComptePath } from '@/router/compte/routes';
Expand All @@ -13,14 +13,10 @@ describe("Fichier de tests concernant la validation de l'authentification de l'u
// WHEN
const spySessionRepository = SpySauvegarderUtilisateurSessionRepository.sansOnBoardingRealise();
const usecase = new ValiderAuthentificationUtilisateurUsecase(
new MockUtilisateurRepository(),
new UtilisateurRepositoryMock(),
spySessionRepository,
);
await usecase.execute(
'[email protected]',
'123456',
new AuthentificationResultatPresenterImpl((viewModel: string) => {}),
);
await usecase.execute('[email protected]', '123456', new AuthentificationResultatPresenterImpl(() => {}));

// THEN
expect(spySessionRepository.utilisateur).toStrictEqual<Utilisateur>({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ValiderCompteUtilisateurUsecase } from '@/domaines/authentification/validerCompteUtilisateur.usecase';
import { Utilisateur } from '@/domaines/authentification/ports/utilisateur.repository';
import { SpySauvegarderUtilisateurSessionRepository } from '../compte/sessionRepository.sauvegarderUtilisateur.spy';
import { MockUtilisateurRepository } from './adapters/mockUtilisateurRepository';
import { UtilisateurRepositoryMock } from './adapters/utilisateur.repository.mock';

describe('Fichier de tests concernant la validation du compte utilisateur', () => {
it('En donnant un mail et un code doit valider le compte puis le sauvegarder en session', async () => {
// GIVEN
// WHEN
const spySessionRepository = SpySauvegarderUtilisateurSessionRepository.sansOnBoardingRealise();
const usecase = new ValiderCompteUtilisateurUsecase(new MockUtilisateurRepository(), spySessionRepository);
const usecase = new ValiderCompteUtilisateurUsecase(new UtilisateurRepositoryMock(), spySessionRepository);
await usecase.execute('[email protected]', '123456');
// THEN
expect(spySessionRepository.utilisateur).toStrictEqual<Utilisateur>({
Expand Down
Loading

0 comments on commit 7b85aef

Please sign in to comment.