Skip to content
Snippets Groups Projects
Commit 594e88a0 authored by Jérémie BRISON's avatar Jérémie BRISON
Browse files

Merge branch 'feat/reset-password' into 'dev'

feat: add password-reset handling

See merge request web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client!42
parents 69562bfc d9cf529c
No related branches found
No related tags found
3 merge requests!68Recette,!67Dev,!42feat: add password-reset handling
......@@ -5,6 +5,7 @@ import { AuthGuard } from './guards/auth.guard';
import { HomeComponent } from './home/home.component';
import { LegalNoticeComponent } from './legal-notice/legal-notice.component';
import { ProfileComponent } from './profile/profile.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component';
import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component';
import { StructureListComponent } from './structure-list/structure-list.component';
import { UserVerificationComponent } from './user-verification/user-verification.component';
......@@ -48,6 +49,10 @@ const routes: Routes = [
canActivate: [AuthGuard],
component: ProfileComponent,
},
{
path: 'reset-password',
component: ResetPasswordComponent,
},
{
path: '**',
redirectTo: 'home',
......
......@@ -25,6 +25,7 @@ import { UserVerificationComponent } from './user-verification/user-verification
import { AuthGuard } from './guards/auth.guard';
import { CustomHttpInterceptor } from './config/http-interceptor';
import { ProfileModule } from './profile/profile.module';
import { ResetPasswordComponent } from './reset-password/reset-password.component';
@NgModule({
declarations: [
......@@ -43,6 +44,7 @@ import { ProfileModule } from './profile/profile.module';
MenuPhoneComponent,
FormComponent,
UserVerificationComponent,
ResetPasswordComponent,
],
imports: [BrowserModule, HttpClientModule, AppRoutingModule, SharedModule, MapModule, ProfileModule],
providers: [
......
<div fxLayout="column" class="content-container">
<div class="section-container" fxLayout="column" fxLayoutAlign="center center">
<h1>Réinitialisation du mot de passe</h1>
<form *ngIf="!token" [formGroup]="resetForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
autocomplete="on"
formControlName="email"
class="form-control"
[ngClass]="{ 'is-invalid': submitted && f.email.errors }"
/>
<div *ngIf="submitted && f.email.errors" class="invalid-feedback">
<div *ngIf="f.email.errors.required">Email is required</div>
</div>
</div>
<div class="form-group">
<button [disabled]="loading" class="btn btn-primary">
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
Envoyer
</button>
<a routerLink="../login" class="btn btn-link">Cancel</a>
</div>
</form>
<form *ngIf="token" [formGroup]="resetFormChangePassword" (ngSubmit)="onSubmitPassword()">
<div class="form-group">
<label for="password">Mot de passe</label>
<input
type="password"
autocomplete="on"
formControlName="password"
class="form-control"
[ngClass]="{ 'is-invalid': submitted && fPassword.password.errors }"
/>
<div *ngIf="submitted && fPassword.password.errors" class="invalid-feedback">
<div *ngIf="fPassword.password.errors.required">Le mot de passe est obligatoire</div>
<div *ngIf="fPassword.password.errors.pattern">
Le mot de passe doit avoir au minimun 8 caractères, une majuscule, une minuscule, un chiffre et un caractère
spécial.
</div>
</div>
</div>
<div class="form-group">
<label for="confirmPassword">Confirmation du mot de passe</label>
<input
type="password"
autocomplete="on"
formControlName="confirmPassword"
class="form-control"
[ngClass]="{ 'is-invalid': submitted && fPassword.confirmPassword.errors }"
/>
<div *ngIf="submitted && fPassword.confirmPassword.errors" class="invalid-feedback">
<div *ngIf="fPassword.confirmPassword.errors.required">La confirmation du mot de passe est obligatoire</div>
<div *ngIf="fPassword.confirmPassword.errors.mustMatch">Les mot de passe ne sont pas les mêmes</div>
</div>
</div>
<div class="form-group">
<button [disabled]="loading" class="btn btn-primary">
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
Enregistrer
</button>
</div>
</form>
</div>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ResetPasswordComponent } from './reset-password.component';
describe('ResetPasswordComponent', () => {
let component: ResetPasswordComponent;
let fixture: ComponentFixture<ResetPasswordComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ResetPasswordComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ResetPasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { MustMatch } from '../shared/validator/form';
@Component({
selector: 'app-reset-password',
templateUrl: './reset-password.component.html',
})
export class ResetPasswordComponent implements OnInit {
public resetForm: FormGroup;
public resetFormChangePassword: FormGroup;
public token: string;
public loading = false;
public submitted = false;
constructor(
private formBuilder: FormBuilder,
private authService: AuthService,
private router: Router,
private activatedRoute: ActivatedRoute
) {}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe((params) => {
this.token = params['token'];
});
this.initPasswordForm();
this.resetForm = this.formBuilder.group({
email: ['', Validators.required],
});
}
private initPasswordForm(): void {
this.resetFormChangePassword = this.formBuilder.group(
{
password: [
'',
[Validators.required, Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})/)],
],
confirmPassword: [''],
},
{ validator: MustMatch('password', 'confirmPassword') }
);
}
// getter for form fields
get f(): { [key: string]: AbstractControl } {
return this.resetForm.controls;
}
get fPassword(): { [key: string]: AbstractControl } {
return this.resetFormChangePassword.controls;
}
public onSubmit(): void {
this.submitted = true;
// stop here if form is invalid
if (this.resetForm.invalid) {
return;
}
this.loading = true;
this.authService.resetPassword(this.f.email.value).subscribe(
() => {
this.router.navigate(['']);
},
() => {
this.loading = false;
}
);
}
public onSubmitPassword(): void {
this.submitted = true;
// stop here if form is invalid
if (this.resetFormChangePassword.invalid) {
return;
}
this.loading = true;
this.authService.resetPasswordApply(this.token, this.fPassword.password.value).subscribe(
() => {
this.router.navigate(['']);
},
() => {
this.loading = false;
}
);
}
}
......@@ -66,4 +66,15 @@ export class AuthService {
params: { token },
});
}
public resetPassword(email: string): Observable<any> {
return this.http.post(`api/users/reset-password`, { email });
}
public resetPasswordApply(token: string, password: string): Observable<any> {
return this.http.post(`api/users/reset-password/apply`, {
token,
password,
});
}
}
......@@ -40,6 +40,7 @@
</button>
<button (click)="sendSwitchToSignIn()">Inscription</button>
</div>
<a (click)="swithToResetPassword()">Mot de passe oublié</a>
</form>
</div>
</div>
......
......@@ -48,6 +48,11 @@ export class SignUpModalComponent implements OnInit {
this.closed.emit(false);
}
public swithToResetPassword(): void {
this.closed.emit(true);
this.router.navigate(['/reset-password']);
}
public onSubmit(): void {
this.submitted = true;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment