Merge pull request 'feat : maj du mot de passe' (#22) from ttp-16 into main
Reviewed-on: #22 Reviewed-by: technostrea <contact@technostrea.fr>
This commit is contained in:
@@ -22,8 +22,8 @@ describe('AppComponent', () => {
|
|||||||
isAuthenticated: jest.fn(),
|
isAuthenticated: jest.fn(),
|
||||||
isEmailVerified: jest.fn(),
|
isEmailVerified: jest.fn(),
|
||||||
register: jest.fn(),
|
register: jest.fn(),
|
||||||
resetPassword: jest.fn(),
|
sendRequestPasswordReset: jest.fn(),
|
||||||
sendPasswordResetEmail: jest.fn(),
|
confirmPasswordReset: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mockProfileRepo = {
|
mockProfileRepo = {
|
||||||
|
|||||||
@@ -1,50 +1,44 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { authGuard } from './auth.guard';
|
import { authGuard } from './auth.guard';
|
||||||
import { CanActivateFn, Router } from '@angular/router';
|
import { CanActivateFn, Router, UrlTree } from '@angular/router';
|
||||||
import { AuthRepository } from '@app/domain/authentification/auth.repository';
|
import { AuthRepository } from '@app/domain/authentification/auth.repository';
|
||||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||||
import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token';
|
import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token';
|
||||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||||
|
import { AuthFacade } from '@app/ui/authentification/auth.facade';
|
||||||
|
|
||||||
describe('authGuard', () => {
|
describe('authGuard', () => {
|
||||||
let mockRouter: Partial<Router>;
|
// 1. Définition des variables pour les Mocks
|
||||||
|
let mockRouter: { parseUrl: jest.Mock };
|
||||||
let mockAuthRepository: jest.Mocked<Partial<AuthRepository>>;
|
let mockAuthFacade: {
|
||||||
let mockProfileRepo: jest.Mocked<Partial<ProfileRepository>>;
|
verifyEmail: jest.Mock;
|
||||||
|
verifyAuthenticatedUser: jest.Mock;
|
||||||
|
isAuthenticated: jest.Mock;
|
||||||
|
isEmailVerified: jest.Mock;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Fonction helper pour exécuter le guard dans le contexte d'injection
|
||||||
const executeGuard: CanActivateFn = (...guardParameters) =>
|
const executeGuard: CanActivateFn = (...guardParameters) =>
|
||||||
TestBed.runInInjectionContext(() => authGuard(...guardParameters));
|
TestBed.runInInjectionContext(() => authGuard(...guardParameters));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
// 3. Initialisation des Mocks
|
||||||
mockRouter = {
|
mockRouter = {
|
||||||
parseUrl: jest.fn(),
|
parseUrl: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mockAuthRepository = {
|
mockAuthFacade = {
|
||||||
get: jest.fn(),
|
verifyEmail: jest.fn(),
|
||||||
login: jest.fn(),
|
verifyAuthenticatedUser: jest.fn(),
|
||||||
sendVerificationEmail: jest.fn(),
|
isAuthenticated: jest.fn(), // On changera la valeur de retour selon le test
|
||||||
logout: jest.fn(),
|
isEmailVerified: jest.fn(), // On changera la valeur de retour selon le test
|
||||||
isAuthenticated: jest.fn(),
|
|
||||||
isEmailVerified: jest.fn(),
|
|
||||||
register: jest.fn(),
|
|
||||||
resetPassword: jest.fn(),
|
|
||||||
sendPasswordResetEmail: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockProfileRepo = {
|
|
||||||
create: jest.fn(),
|
|
||||||
list: jest.fn(),
|
|
||||||
update: jest.fn(),
|
|
||||||
getByUserId: jest.fn(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: Router, useValue: mockRouter },
|
{ provide: Router, useValue: mockRouter },
|
||||||
{ provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository },
|
{ provide: AuthFacade, useValue: mockAuthFacade }, // On fournit la Facade, pas le Repo
|
||||||
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -53,26 +47,50 @@ describe('authGuard', () => {
|
|||||||
expect(executeGuard).toBeTruthy();
|
expect(executeGuard).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
/*it('should allow access if user is valid', () => {
|
// --- SCÉNARIO 1 : L'utilisateur a tout bon ---
|
||||||
const mockRoute = {} as any;
|
it('should return true if user is authenticated AND email is verified', () => {
|
||||||
const mockState = {} as any;
|
// Setup : Tout est OK
|
||||||
|
mockAuthFacade.isAuthenticated.mockReturnValue(true);
|
||||||
|
mockAuthFacade.isEmailVerified.mockReturnValue(true);
|
||||||
|
|
||||||
const result = TestBed.runInInjectionContext(() => executeGuard(mockRoute, mockState));
|
const result = executeGuard({} as any, {} as any); // On passe des fausses routes/state
|
||||||
expect(result).toEqual(true);
|
|
||||||
|
// Vérifications
|
||||||
|
expect(result).toBe(true);
|
||||||
|
// On vérifie aussi que le guard a bien lancé les vérifications
|
||||||
|
expect(mockAuthFacade.verifyEmail).toHaveBeenCalled();
|
||||||
|
expect(mockAuthFacade.verifyAuthenticatedUser).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect to /auth if user is not valid', () => {
|
// --- SCÉNARIO 2 : L'utilisateur n'est pas connecté ---
|
||||||
mockFacade.isAuthenticated();
|
it('should redirect to /auth if user is NOT authenticated', () => {
|
||||||
mockFacade.isEmailVerified();
|
// Setup : Pas connecté
|
||||||
|
mockAuthFacade.isAuthenticated.mockReturnValue(false);
|
||||||
|
mockAuthFacade.isEmailVerified.mockReturnValue(true); // Peu importe ici
|
||||||
|
|
||||||
const mockRoute = {} as any;
|
// On prépare le router pour qu'il renvoie une fausse UrlTree
|
||||||
const mockState = {} as any;
|
const dummyUrlTree = {} as UrlTree;
|
||||||
|
mockRouter.parseUrl.mockReturnValue(dummyUrlTree);
|
||||||
|
|
||||||
(mockRouter.parseUrl as jest.Mock).mockReturnValue('/auth');
|
const result = executeGuard({} as any, {} as any);
|
||||||
|
|
||||||
const result = TestBed.runInInjectionContext(() => executeGuard(mockRoute, mockState));
|
// Le guard doit retourner la redirection (UrlTree)
|
||||||
|
expect(result).toBe(dummyUrlTree);
|
||||||
expect(result).toEqual('/auth' as any);
|
|
||||||
expect(mockRouter.parseUrl).toHaveBeenCalledWith('/auth');
|
expect(mockRouter.parseUrl).toHaveBeenCalledWith('/auth');
|
||||||
});*/
|
});
|
||||||
|
|
||||||
|
// --- SCÉNARIO 3 : Connecté mais email non vérifié ---
|
||||||
|
it('should redirect to /auth if user is authenticated but email is NOT verified', () => {
|
||||||
|
// Setup : Connecté mais mail pas bon
|
||||||
|
mockAuthFacade.isAuthenticated.mockReturnValue(true);
|
||||||
|
mockAuthFacade.isEmailVerified.mockReturnValue(false);
|
||||||
|
|
||||||
|
const dummyUrlTree = {} as UrlTree;
|
||||||
|
mockRouter.parseUrl.mockReturnValue(dummyUrlTree);
|
||||||
|
|
||||||
|
const result = executeGuard({} as any, {} as any);
|
||||||
|
|
||||||
|
expect(result).toBe(dummyUrlTree);
|
||||||
|
expect(mockRouter.parseUrl).toHaveBeenCalledWith('/auth');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ThemeService } from './theme.service';
|
import { ThemeService } from './theme.service';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
describe('ThemeService', () => {
|
describe('ThemeService', () => {
|
||||||
let service: ThemeService;
|
let service: ThemeService;
|
||||||
|
|
||||||
const routerSpy = {
|
|
||||||
navigate: jest.fn(),
|
|
||||||
navigateByUrl: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [
|
providers: [ThemeService],
|
||||||
{ provide: Router, useValue: routerSpy }, // <<— spy: neutralise la navigation
|
|
||||||
],
|
|
||||||
imports: [],
|
|
||||||
});
|
});
|
||||||
service = TestBed.inject(ThemeService);
|
service = TestBed.inject(ThemeService);
|
||||||
});
|
});
|
||||||
@@ -24,4 +15,31 @@ describe('ThemeService', () => {
|
|||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(service).toBeTruthy();
|
expect(service).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test de la valeur initiale
|
||||||
|
it('should have initial value "null"', () => {
|
||||||
|
// Avec les Signals, on accède à la valeur en exécutant la fonction : signal()
|
||||||
|
expect(service.darkModeSignal()).toBe('null');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test du basculement vers Dark
|
||||||
|
it('should switch to "dark" when updateDarkMode is called and current is "null"', () => {
|
||||||
|
// Action
|
||||||
|
service.updateDarkMode();
|
||||||
|
|
||||||
|
// Vérification
|
||||||
|
expect(service.darkModeSignal()).toBe('dark');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test du basculement inverse (Dark vers Null)
|
||||||
|
it('should switch back to "null" when updateDarkMode is called and current is "dark"', () => {
|
||||||
|
// 1. Préparation : On force l'état à 'dark' pour tester ce cas précis
|
||||||
|
service.darkModeSignal.set('dark');
|
||||||
|
|
||||||
|
// 2. Action
|
||||||
|
service.updateDarkMode();
|
||||||
|
|
||||||
|
// 3. Vérification
|
||||||
|
expect(service.darkModeSignal()).toBe('null');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,8 +18,12 @@ export interface AuthRepository {
|
|||||||
|
|
||||||
get(): User | undefined;
|
get(): User | undefined;
|
||||||
|
|
||||||
sendPasswordResetEmail(email: string): Observable<boolean>;
|
sendRequestPasswordReset(email: string): Observable<boolean>;
|
||||||
resetPassword(token: string, newPassword: string): Observable<boolean>;
|
confirmPasswordReset(
|
||||||
|
resetToken: string,
|
||||||
|
newPassword: string,
|
||||||
|
confirmPassword: string
|
||||||
|
): Observable<boolean>;
|
||||||
|
|
||||||
sendVerificationEmail(email: string): Observable<boolean>;
|
sendVerificationEmail(email: string): Observable<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { environment } from '@env/environment';
|
import { environment } from '@env/environment';
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
import { AuthRepository, AuthResponse } from '@app/domain/authentification/auth.repository';
|
import { AuthRepository, AuthResponse } from '@app/domain/authentification/auth.repository';
|
||||||
import { from, map, Observable, of } from 'rxjs';
|
import { from, map, Observable } from 'rxjs';
|
||||||
import { User } from '@app/domain/users/user.model';
|
import { User } from '@app/domain/users/user.model';
|
||||||
import { LoginDto } from '@app/domain/authentification/dto/login-dto';
|
import { LoginDto } from '@app/domain/authentification/dto/login-dto';
|
||||||
import { RegisterDto } from '@app/domain/authentification/dto/register-dto';
|
import { RegisterDto } from '@app/domain/authentification/dto/register-dto';
|
||||||
@@ -46,11 +46,17 @@ export class PbAuthRepository implements AuthRepository {
|
|||||||
return from(this.pb.collection('users').create<User>(registerDto));
|
return from(this.pb.collection('users').create<User>(registerDto));
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPassword(token: string, newPassword: string): Observable<boolean> {
|
confirmPasswordReset(
|
||||||
return of(false);
|
resetToken: string,
|
||||||
|
newPassword: string,
|
||||||
|
confirmPassword: string
|
||||||
|
): Observable<boolean> {
|
||||||
|
return from(
|
||||||
|
this.pb.collection('users').confirmPasswordReset(resetToken, newPassword, confirmPassword)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPasswordResetEmail(email: string): Observable<boolean> {
|
sendRequestPasswordReset(email: string): Observable<boolean> {
|
||||||
return from(this.pb.collection('users').requestPasswordReset(email));
|
return from(this.pb.collection('users').requestPasswordReset(email));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { Profile } from '@app/domain/profiles/profile.model';
|
|||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token';
|
import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token';
|
||||||
import { UserRepository } from '@app/domain/users/user.repository';
|
import { UserRepository } from '@app/domain/users/user.repository';
|
||||||
|
import { AuthRepository } from '@app/domain/authentification/auth.repository';
|
||||||
|
import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token';
|
||||||
|
|
||||||
describe('MyProfileComponent', () => {
|
describe('MyProfileComponent', () => {
|
||||||
let component: MyProfileComponent;
|
let component: MyProfileComponent;
|
||||||
@@ -17,6 +19,7 @@ describe('MyProfileComponent', () => {
|
|||||||
let mockProfileRepo: ProfileRepository;
|
let mockProfileRepo: ProfileRepository;
|
||||||
let mockToastrService: Partial<ToastrService>;
|
let mockToastrService: Partial<ToastrService>;
|
||||||
let mockUserRepo: Partial<UserRepository>;
|
let mockUserRepo: Partial<UserRepository>;
|
||||||
|
let mockAuthRepository: jest.Mocked<Partial<AuthRepository>>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
mockProfileRepo = {
|
mockProfileRepo = {
|
||||||
@@ -37,11 +40,25 @@ describe('MyProfileComponent', () => {
|
|||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mockAuthRepository = {
|
||||||
|
get: jest.fn(),
|
||||||
|
login: jest.fn(),
|
||||||
|
sendVerificationEmail: jest.fn(),
|
||||||
|
logout: jest.fn(),
|
||||||
|
isAuthenticated: jest.fn(),
|
||||||
|
isEmailVerified: jest.fn(),
|
||||||
|
register: jest.fn(),
|
||||||
|
sendRequestPasswordReset: jest.fn(),
|
||||||
|
confirmPasswordReset: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [MyProfileComponent],
|
imports: [MyProfileComponent],
|
||||||
providers: [
|
providers: [
|
||||||
provideRouter([]),
|
provideRouter([]),
|
||||||
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
||||||
|
{ provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository },
|
||||||
{ provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo },
|
{ provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo },
|
||||||
{ provide: ToastrService, useValue: mockToastrService },
|
{ provide: ToastrService, useValue: mockToastrService },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ describe('MyProfileUpdateProjectFormComponent', () => {
|
|||||||
isAuthenticated: jest.fn(),
|
isAuthenticated: jest.fn(),
|
||||||
isEmailVerified: jest.fn(),
|
isEmailVerified: jest.fn(),
|
||||||
register: jest.fn(),
|
register: jest.fn(),
|
||||||
resetPassword: jest.fn(),
|
sendRequestPasswordReset: jest.fn(),
|
||||||
sendPasswordResetEmail: jest.fn(),
|
confirmPasswordReset: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mockProfileRepo = {
|
mockProfileRepo = {
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ describe('NavBarComponent', () => {
|
|||||||
isAuthenticated: jest.fn(),
|
isAuthenticated: jest.fn(),
|
||||||
isEmailVerified: jest.fn(),
|
isEmailVerified: jest.fn(),
|
||||||
register: jest.fn(),
|
register: jest.fn(),
|
||||||
resetPassword: jest.fn(),
|
sendRequestPasswordReset: jest.fn(),
|
||||||
sendPasswordResetEmail: jest.fn(),
|
confirmPasswordReset: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mockProfileRepo = {
|
mockProfileRepo = {
|
||||||
|
|||||||
@@ -1 +1,47 @@
|
|||||||
<p>user-password-form works!</p>
|
@if (loading().action === ActionType.CREATE && loading().isLoading) {
|
||||||
|
<app-loading message="Mise à jour encours..." />
|
||||||
|
} @else {
|
||||||
|
<ng-container *ngTemplateOutlet="form" />
|
||||||
|
}
|
||||||
|
<ng-template #form>
|
||||||
|
<!-- Titre -->
|
||||||
|
<div class="flex items-center gap-3 pb-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 bg-indigo-100 dark:bg-indigo-900 rounded-lg flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="w-6 h-6 text-indigo-600 dark:text-indigo-400"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Mise à jour du mot de passe</h3>
|
||||||
|
</div>
|
||||||
|
<!-- Bouton de soumission -->
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
(click)="onSubmit()"
|
||||||
|
class="w-full py-3 px-4 bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 text-white font-medium rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
|
||||||
|
>
|
||||||
|
<span class="flex items-center justify-center gap-2">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-5 w-5"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7.707 10.293a1 1 0 10-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 11.586V6h5a2 2 0 012 2v7a2 2 0 01-2 2H4a2 2 0 01-2-2V8a2 2 0 012-2h5v5.586l-1.293-1.293zM9 4a1 1 0 012 0v2H9V4z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Réinitialiser le mot de passe
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</ng-template>
|
||||||
|
|||||||
@@ -1,22 +1,92 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { UserPasswordFormComponent } from './user-password-form.component';
|
import { UserPasswordFormComponent } from './user-password-form.component';
|
||||||
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { AuthFacade } from '@app/ui/authentification/auth.facade';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { ActionType } from '@app/domain/action-type.util';
|
||||||
|
import { signal, WritableSignal } from '@angular/core';
|
||||||
|
|
||||||
describe('UserPasswordFormComponent', () => {
|
describe('UserPasswordFormComponent', () => {
|
||||||
let component: UserPasswordFormComponent;
|
let component: UserPasswordFormComponent;
|
||||||
let fixture: ComponentFixture<UserPasswordFormComponent>;
|
let fixture: ComponentFixture<UserPasswordFormComponent>;
|
||||||
|
|
||||||
|
let mockToastrService: Partial<ToastrService>;
|
||||||
|
|
||||||
|
// On mocke la Facade car c'est ce que le composant utilise directement
|
||||||
|
let mockAuthFacade: {
|
||||||
|
sendRequestPasswordReset: jest.Mock;
|
||||||
|
loading: WritableSignal<{ isLoading: boolean; action: ActionType }>;
|
||||||
|
error: WritableSignal<{ hasError: boolean }>;
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
mockToastrService = {
|
||||||
|
warning: jest.fn(),
|
||||||
|
success: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
mockAuthFacade = {
|
||||||
|
sendRequestPasswordReset: jest.fn(),
|
||||||
|
loading: signal({ isLoading: false, action: ActionType.NONE }),
|
||||||
|
error: signal({ hasError: false }),
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [UserPasswordFormComponent],
|
imports: [UserPasswordFormComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: ToastrService, useValue: mockToastrService },
|
||||||
|
{ provide: AuthFacade, useValue: mockAuthFacade }, // On fournit le mock à la place du vrai
|
||||||
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(UserPasswordFormComponent);
|
fixture = TestBed.createComponent(UserPasswordFormComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
// 3. Input obligatoire
|
||||||
|
component.user = { email: 'test@example.com' } as any;
|
||||||
|
|
||||||
|
fixture.detectChanges(); // Déclenche le ngOnInit et le premier rendu
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- TEST DE L'UI (Interaction utilisateur) ---
|
||||||
|
it('should call sendRequestPasswordReset when the submit button is clicked', () => {
|
||||||
|
// Simulation du clic
|
||||||
|
const button = fixture.debugElement.query(By.css('button'));
|
||||||
|
button.nativeElement.click();
|
||||||
|
|
||||||
|
// Vérification
|
||||||
|
expect(mockAuthFacade.sendRequestPasswordReset).toHaveBeenCalledWith('test@example.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- TEST DE L'UI (État de chargement) ---
|
||||||
|
it('should show loading spinner when loading action is CREATE', () => {
|
||||||
|
// Mise à jour du signal
|
||||||
|
mockAuthFacade.loading.set({ isLoading: true, action: ActionType.CREATE });
|
||||||
|
fixture.detectChanges(); // Mise à jour du DOM
|
||||||
|
|
||||||
|
const loadingComponent = fixture.debugElement.query(By.css('app-loading'));
|
||||||
|
expect(loadingComponent).toBeTruthy(); // Le composant de loading doit être là
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- TEST DE LOGIQUE (Effect & Toast) ---
|
||||||
|
it('should show success toast when action finishes successfully', () => {
|
||||||
|
// 1. On simule la fin du chargement (isLoading: false) avec l'action CREATE
|
||||||
|
mockAuthFacade.loading.set({ isLoading: false, action: ActionType.CREATE });
|
||||||
|
mockAuthFacade.error.set({ hasError: false });
|
||||||
|
|
||||||
|
// Nécessaire pour déclencher l'effect()
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(mockToastrService.success).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('test@example.com'),
|
||||||
|
'Mise à jour',
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,33 +1,71 @@
|
|||||||
import { Component, inject, Input, output } from '@angular/core';
|
import { Component, effect, inject, Input, output } from '@angular/core';
|
||||||
import { User } from '@app/domain/users/user.model';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { FormBuilder, FormControl, Validators } from '@angular/forms';
|
import { UserViewModel } from '@app/ui/users/user.presenter.model';
|
||||||
|
import { AuthFacade } from '@app/ui/authentification/auth.facade';
|
||||||
|
import { ActionType } from '@app/domain/action-type.util';
|
||||||
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { LoadingComponent } from '@app/shared/components/loading/loading.component';
|
||||||
|
import { NgTemplateOutlet } from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-user-password-form',
|
selector: 'app-user-password-form',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [],
|
imports: [ReactiveFormsModule, LoadingComponent, NgTemplateOutlet],
|
||||||
templateUrl: './user-password-form.component.html',
|
templateUrl: './user-password-form.component.html',
|
||||||
styleUrl: './user-password-form.component.scss',
|
styleUrl: './user-password-form.component.scss',
|
||||||
})
|
})
|
||||||
export class UserPasswordFormComponent {
|
export class UserPasswordFormComponent {
|
||||||
@Input({ required: true }) user: User | undefined = undefined;
|
private readonly toastrService = inject(ToastrService);
|
||||||
|
@Input({ required: true }) user: UserViewModel | undefined = undefined;
|
||||||
onFormSubmitted = output<any>();
|
onFormSubmitted = output<any>();
|
||||||
|
|
||||||
private fb = inject(FormBuilder);
|
private readonly authFacade = inject(AuthFacade);
|
||||||
|
protected readonly loading = this.authFacade.loading;
|
||||||
|
protected readonly error = this.authFacade.error;
|
||||||
|
|
||||||
protected userPasswordForm = this.fb.group({
|
constructor() {
|
||||||
password: new FormControl('', [Validators.required]),
|
let message = '';
|
||||||
passwordConfirm: new FormControl('', [Validators.required]),
|
|
||||||
oldPassword: new FormControl('', [Validators.required]),
|
effect(() => {
|
||||||
|
if (!this.loading().isLoading) {
|
||||||
|
switch (this.loading().action) {
|
||||||
|
case ActionType.CREATE:
|
||||||
|
message = `Un mail de réinitialisation vous a été envoyé à cette adresse mail : ${this.user!.email}`;
|
||||||
|
this.customToast(ActionType.CREATE, message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onUserPasswordFormSubmit() {
|
onSubmit() {
|
||||||
if (this.userPasswordForm.invalid) {
|
this.authFacade.sendRequestPasswordReset(this.user!.email);
|
||||||
|
}
|
||||||
|
|
||||||
|
private customToast(action: ActionType, message: string): void {
|
||||||
|
if (this.error().hasError) {
|
||||||
|
this.toastrService.error(
|
||||||
|
`Une erreur s'est produite, veuillez réessayer ulterieurement`,
|
||||||
|
`Erreur`,
|
||||||
|
{
|
||||||
|
closeButton: true,
|
||||||
|
progressAnimation: 'decreasing',
|
||||||
|
progressBar: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = this.userPasswordForm.getRawValue();
|
this.toastrService.success(
|
||||||
|
`${message}`,
|
||||||
this.onFormSubmitted.emit(data);
|
`${action === ActionType.CREATE ? 'Mise à jour' : ''}`,
|
||||||
|
{
|
||||||
|
closeButton: true,
|
||||||
|
progressAnimation: 'decreasing',
|
||||||
|
progressBar: true,
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly ActionType = ActionType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ describe('LoginComponent', () => {
|
|||||||
isAuthenticated: jest.fn(),
|
isAuthenticated: jest.fn(),
|
||||||
isEmailVerified: jest.fn(),
|
isEmailVerified: jest.fn(),
|
||||||
register: jest.fn(),
|
register: jest.fn(),
|
||||||
resetPassword: jest.fn(),
|
sendRequestPasswordReset: jest.fn(),
|
||||||
sendPasswordResetEmail: jest.fn(),
|
confirmPasswordReset: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mockProfileRepo = {
|
mockProfileRepo = {
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ describe('RegisterComponent', () => {
|
|||||||
isAuthenticated: jest.fn(),
|
isAuthenticated: jest.fn(),
|
||||||
isEmailVerified: jest.fn(),
|
isEmailVerified: jest.fn(),
|
||||||
register: jest.fn(),
|
register: jest.fn(),
|
||||||
resetPassword: jest.fn(),
|
sendRequestPasswordReset: jest.fn(),
|
||||||
sendPasswordResetEmail: jest.fn(),
|
confirmPasswordReset: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
|
|||||||
@@ -30,5 +30,12 @@
|
|||||||
>
|
>
|
||||||
<app-user-form [userId]="user!.id" />
|
<app-user-form [userId]="user!.id" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Section Mot de passe -->
|
||||||
|
<div
|
||||||
|
class="bg-white dark:bg-gray-800 rounded-xl shadow-lg p-6 animate-fade-in animation-delay-100"
|
||||||
|
>
|
||||||
|
<app-user-password-form [user]="user" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import { Component, Input } from '@angular/core';
|
|||||||
import { UserFormComponent } from '@app/shared/components/user-form/user-form.component';
|
import { UserFormComponent } from '@app/shared/components/user-form/user-form.component';
|
||||||
import { UserAvatarFormComponent } from '@app/shared/components/user-avatar-form/user-avatar-form.component';
|
import { UserAvatarFormComponent } from '@app/shared/components/user-avatar-form/user-avatar-form.component';
|
||||||
import { UserViewModel } from '@app/ui/users/user.presenter.model';
|
import { UserViewModel } from '@app/ui/users/user.presenter.model';
|
||||||
|
import { UserPasswordFormComponent } from '@app/shared/components/user-password-form/user-password-form.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-update-user',
|
selector: 'app-update-user',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [UserFormComponent, UserAvatarFormComponent],
|
imports: [UserFormComponent, UserAvatarFormComponent, UserPasswordFormComponent],
|
||||||
templateUrl: './update-user.component.html',
|
templateUrl: './update-user.component.html',
|
||||||
styleUrl: './update-user.component.scss',
|
styleUrl: './update-user.component.scss',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { AuthRepository, AuthResponse } from '@app/domain/authentification/auth.repository';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { User } from '@app/domain/users/user.model';
|
||||||
|
import { LoginDto } from '@app/domain/authentification/dto/login-dto';
|
||||||
|
import { RegisterDto } from '@app/domain/authentification/dto/register-dto';
|
||||||
|
import { fakeUsers } from '@app/testing/user.mock';
|
||||||
|
|
||||||
|
export class FakeAuthRepository implements AuthRepository {
|
||||||
|
confirmPasswordReset(
|
||||||
|
resetToken: string,
|
||||||
|
newPassword: string,
|
||||||
|
confirmPassword: string
|
||||||
|
): Observable<boolean> {
|
||||||
|
return of(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(): User | undefined {
|
||||||
|
return fakeUsers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
isAuthenticated(): boolean {
|
||||||
|
return fakeUsers[0] !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmailVerified(): boolean {
|
||||||
|
return fakeUsers[0].verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
login(loginDto: LoginDto): Observable<AuthResponse> {
|
||||||
|
const user = fakeUsers.find((u) => u.email === loginDto.email);
|
||||||
|
return of({ isValid: true, record: user, token: 'fakeToken' } as AuthResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
logout(): void {
|
||||||
|
fakeUsers.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
register(registerDto: RegisterDto): Observable<User> {
|
||||||
|
const user = {
|
||||||
|
...fakeUsers[0],
|
||||||
|
id: 'fakeId',
|
||||||
|
email: registerDto.email,
|
||||||
|
};
|
||||||
|
fakeUsers.push(user);
|
||||||
|
return of(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendRequestPasswordReset(email: string): Observable<boolean> {
|
||||||
|
return of(fakeUsers[0].email === email);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendVerificationEmail(email: string): Observable<boolean> {
|
||||||
|
return of(fakeUsers[0].email === email);
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/app/testing/usecase/authentification/.gitkeep
Normal file
0
src/app/testing/usecase/authentification/.gitkeep
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { GetCurrentUserUseCase } from '@app/usecase/authentification/get-current-user.usecase';
|
||||||
|
import { fakeUsers } from '@app/testing/user.mock';
|
||||||
|
|
||||||
|
describe('GetUserUsecase', () => {
|
||||||
|
it("devrait retourner l'utilisateur connecté ", () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new GetCurrentUserUseCase(repo);
|
||||||
|
|
||||||
|
const res = useCase.execute();
|
||||||
|
expect(res).toBeTruthy();
|
||||||
|
expect(res).toBe(fakeUsers[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { LoginUseCase } from '@app/usecase/authentification/login.usecase';
|
||||||
|
import { LoginDto } from '@app/domain/authentification/dto/login-dto';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
describe('LoginUsecase', () => {
|
||||||
|
it('devrait se connecter ', async () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new LoginUseCase(repo);
|
||||||
|
|
||||||
|
const loginDto: LoginDto = {
|
||||||
|
email: 'foo@bar.com',
|
||||||
|
password: 'password1234',
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await firstValueFrom(useCase.execute(loginDto));
|
||||||
|
|
||||||
|
expect(response.isValid).toBe(true);
|
||||||
|
expect(response.token).toEqual('fakeToken');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { LogoutUseCase } from '@app/usecase/authentification/logout.usecase';
|
||||||
|
import { fakeUsers } from '@app/testing/user.mock';
|
||||||
|
|
||||||
|
describe('LogoutUsecase', () => {
|
||||||
|
it("devrait supprimer les infos de l'utilisateur en cache ", async () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new LogoutUseCase(repo);
|
||||||
|
|
||||||
|
expect(fakeUsers[0]).toBeTruthy();
|
||||||
|
|
||||||
|
useCase.execute();
|
||||||
|
|
||||||
|
expect(fakeUsers[0]).toBeUndefined();
|
||||||
|
expect(fakeUsers.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { RegisterUseCase } from '@app/usecase/authentification/register.usecase';
|
||||||
|
import { RegisterDto } from '@app/domain/authentification/dto/register-dto';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
describe('RegisterUsecase', () => {
|
||||||
|
it("devrait s'enregister", async () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new RegisterUseCase(repo);
|
||||||
|
|
||||||
|
const registerDto: RegisterDto = {
|
||||||
|
email: 'bar@foo.com',
|
||||||
|
emailVisibility: false,
|
||||||
|
password: 'password1234',
|
||||||
|
passwordConfirm: 'password1234',
|
||||||
|
};
|
||||||
|
const response = await firstValueFrom(useCase.execute(registerDto));
|
||||||
|
|
||||||
|
expect(response.email).toEqual('bar@foo.com');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { SendRequestPasswordResetUsecase } from '@app/usecase/authentification/send-request-password-reset.usecase';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
describe('SendRequestPasswordUsecase', () => {
|
||||||
|
it('devrait envoyer une demande de maj du mot de passe ', async () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new SendRequestPasswordResetUsecase(repo);
|
||||||
|
|
||||||
|
const email = 'foo@bar.com';
|
||||||
|
|
||||||
|
const res = await firstValueFrom(useCase.execute(email));
|
||||||
|
expect(res).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { SendVerificationEmailUsecase } from '@app/usecase/authentification/send-verification-email.usecase';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
describe('SendVerificationEmailUsecase', () => {
|
||||||
|
it('devrait effectuer une verification de mail ', async () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new SendVerificationEmailUsecase(repo);
|
||||||
|
const email = 'foo@bar.com';
|
||||||
|
|
||||||
|
const response = await firstValueFrom(useCase.execute(email));
|
||||||
|
expect(response).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { VerifyAuthenticatedUsecase } from '@app/usecase/authentification/verify-authenticated.usecase';
|
||||||
|
|
||||||
|
describe('VerifyAuthenticationUseCase', () => {
|
||||||
|
it("devrait retourner l'utilisateur authentifier ", () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new VerifyAuthenticatedUsecase(repo);
|
||||||
|
|
||||||
|
expect(useCase.execute()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { FakeAuthRepository } from '@app/testing/domain/authentification/fake-auth.repository';
|
||||||
|
import { VerifyEmailUseCase } from '@app/usecase/authentification/verify-email.usecase';
|
||||||
|
|
||||||
|
describe('VerifyEmailUseCase', () => {
|
||||||
|
it("devrait verifier le mail de l'utilisateur ", () => {
|
||||||
|
const repo = new FakeAuthRepository();
|
||||||
|
const useCase = new VerifyEmailUseCase(repo);
|
||||||
|
|
||||||
|
expect(useCase.execute()).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -16,6 +16,7 @@ import { LogoutUseCase } from '@app/usecase/authentification/logout.usecase';
|
|||||||
import { VerifyAuthenticatedUsecase } from '@app/usecase/authentification/verify-authenticated.usecase';
|
import { VerifyAuthenticatedUsecase } from '@app/usecase/authentification/verify-authenticated.usecase';
|
||||||
import { VerifyEmailUseCase } from '@app/usecase/authentification/verify-email.usecase';
|
import { VerifyEmailUseCase } from '@app/usecase/authentification/verify-email.usecase';
|
||||||
import { GetCurrentUserUseCase } from '@app/usecase/authentification/get-current-user.usecase';
|
import { GetCurrentUserUseCase } from '@app/usecase/authentification/get-current-user.usecase';
|
||||||
|
import { SendRequestPasswordResetUsecase } from '@app/usecase/authentification/send-request-password-reset.usecase';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class AuthFacade {
|
export class AuthFacade {
|
||||||
@@ -33,9 +34,14 @@ export class AuthFacade {
|
|||||||
private readonly verifyAuthenticatedUseCase = new VerifyAuthenticatedUsecase(this.authRepository);
|
private readonly verifyAuthenticatedUseCase = new VerifyAuthenticatedUsecase(this.authRepository);
|
||||||
private readonly verifyEmailUseCase = new VerifyEmailUseCase(this.authRepository);
|
private readonly verifyEmailUseCase = new VerifyEmailUseCase(this.authRepository);
|
||||||
|
|
||||||
|
private readonly senRequestPasswordResetUseCase = new SendRequestPasswordResetUsecase(
|
||||||
|
this.authRepository
|
||||||
|
);
|
||||||
|
|
||||||
readonly isAuthenticated = signal<boolean>(false);
|
readonly isAuthenticated = signal<boolean>(false);
|
||||||
readonly isEmailVerified = signal<boolean>(false);
|
readonly isEmailVerified = signal<boolean>(false);
|
||||||
readonly isVerificationEmailSent = signal<boolean>(false);
|
readonly isVerificationEmailSent = signal<boolean>(false);
|
||||||
|
readonly isRequestPasswordSent = signal<boolean>(false);
|
||||||
|
|
||||||
readonly user = signal<User | undefined>(undefined);
|
readonly user = signal<User | undefined>(undefined);
|
||||||
readonly authResponse = signal<AuthResponse | undefined>(undefined);
|
readonly authResponse = signal<AuthResponse | undefined>(undefined);
|
||||||
@@ -94,6 +100,19 @@ export class AuthFacade {
|
|||||||
this.user.set(this.getUserUseCase.execute());
|
this.user.set(this.getUserUseCase.execute());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendRequestPasswordReset(email: string) {
|
||||||
|
this.handleError(ActionType.CREATE, false, null, true);
|
||||||
|
this.senRequestPasswordResetUseCase.execute(email).subscribe({
|
||||||
|
next: (res) => {
|
||||||
|
this.isRequestPasswordSent.set(res);
|
||||||
|
this.handleError(ActionType.CREATE, false, null, false);
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.handleError(ActionType.CREATE, true, err.message, false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private sendVerificationEmail(email: string) {
|
private sendVerificationEmail(email: string) {
|
||||||
this.handleError(ActionType.CREATE, false, null, true);
|
this.handleError(ActionType.CREATE, false, null, true);
|
||||||
this.sendVerificationEmailUseCase.execute(email).subscribe({
|
this.sendVerificationEmailUseCase.execute(email).subscribe({
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { AuthRepository } from '@app/domain/authentification/auth.repository';
|
||||||
|
|
||||||
|
export class ConfirmPasswordResetUsecase {
|
||||||
|
constructor(private readonly authRepo: AuthRepository) {}
|
||||||
|
|
||||||
|
execute(resetToken: string, newPassword: string, confirmPassword: string) {
|
||||||
|
return this.authRepo.confirmPasswordReset(resetToken, newPassword, confirmPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { AuthRepository } from '@app/domain/authentification/auth.repository';
|
||||||
|
|
||||||
|
export class SendRequestPasswordResetUsecase {
|
||||||
|
constructor(private readonly authRepo: AuthRepository) {}
|
||||||
|
|
||||||
|
execute(email: string) {
|
||||||
|
return this.authRepo.sendRequestPasswordReset(email);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user