feat: migrate PwResetComponent to Django Rest and fix small bugs in auth process

This commit is contained in:
Chneemann 2025-04-05 22:43:12 +02:00
parent 68a413dc97
commit da9e623325
10 changed files with 72 additions and 15 deletions

View file

@ -28,7 +28,7 @@ export const routes: Routes = [
{ path: 'login/notice/:id', component: LoginComponent }, { path: 'login/notice/:id', component: LoginComponent },
{ path: 'register', component: RegisterComponent }, { path: 'register', component: RegisterComponent },
{ path: 'forgot-pw', component: ForgotPwComponent }, { path: 'forgot-pw', component: ForgotPwComponent },
{ path: 'pw-reset', component: PwResetComponent }, { path: 'pw-reset/:uid/:token', component: PwResetComponent },
{ path: 'login/imprint', component: ImprintComponent }, { path: 'login/imprint', component: ImprintComponent },
{ path: 'login/privacy-policy', component: PrivacyPolicyComponent }, { path: 'login/privacy-policy', component: PrivacyPolicyComponent },
], ],

View file

@ -43,7 +43,7 @@
<div class="error-msg"> <div class="error-msg">
@if (!password.valid && password.touched) { @if (!password.valid && password.touched) {
<p>{{ "register.errorPassword0" | translate }}</p> <p>{{ "register.errorPassword0" | translate }}</p>
} @else { @if (pwResetData.password.length < 6 && password.touched) { } @else { @if (pwResetData.password.length < 8 && password.touched) {
<p>{{ "register.errorPassword1" | translate }}</p> <p>{{ "register.errorPassword1" | translate }}</p>
} } } }
</div> </div>
@ -79,6 +79,8 @@
} @if (pwResetData.password !== pwResetData.passwordConfirm && } @if (pwResetData.password !== pwResetData.passwordConfirm &&
pwResetData.password !== "" && pwResetData.passwordConfirm !== "") { pwResetData.password !== "" && pwResetData.passwordConfirm !== "") {
<p>{{ "register.errorPassword2" | translate }}</p> <p>{{ "register.errorPassword2" | translate }}</p>
} @if (errorHttpMessage === 'Invalid reset link.') {
<p>{{ "forgotPW.invalidLink" | translate }}</p>
} }
</div> </div>
</div> </div>

View file

@ -5,10 +5,11 @@ import { FormBtnComponent } from '../../../../shared/components/buttons/form-btn
import { FooterComponent } from '../../footer/footer.component'; import { FooterComponent } from '../../footer/footer.component';
import { HeaderComponent } from '../../header/header.component'; import { HeaderComponent } from '../../header/header.component';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { LoginService } from '../../../../services/login.service';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ButtonStateService } from '../../../../services/button-state.service'; import { ButtonStateService } from '../../../../services/button-state.service';
import { AuthService } from '../../../../services/auth.service';
import { LoginService } from '../../../../services/login.service';
@Component({ @Component({
selector: 'app-pw-reset', selector: 'app-pw-reset',
@ -25,8 +26,11 @@ import { ButtonStateService } from '../../../../services/button-state.service';
styleUrl: './pw-reset.component.scss', styleUrl: './pw-reset.component.scss',
}) })
export class PwResetComponent { export class PwResetComponent {
oobCode: string = ''; private routeSubscription: Subscription = new Subscription();
private queryParamsSubscription: Subscription = new Subscription();
uid: string = '';
token: string = '';
errorHttpMessage: string = '';
pwResetData = { pwResetData = {
password: '', password: '',
@ -35,26 +39,42 @@ export class PwResetComponent {
constructor( constructor(
public loginService: LoginService, public loginService: LoginService,
private authService: AuthService,
private buttonStateService: ButtonStateService, private buttonStateService: ButtonStateService,
private route: ActivatedRoute private route: ActivatedRoute
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
this.queryParamsSubscription = this.route.queryParams.subscribe( this.routeSubscription = this.route.params.subscribe((params) => {
(params) => { this.uid = params['uid'];
this.oobCode = params['oobCode']; this.token = params['token'];
} });
); }
ngOnDestroy(): void {
if (this.routeSubscription) {
this.routeSubscription.unsubscribe();
}
} }
isButtonDisabled() { isButtonDisabled() {
return this.buttonStateService.isButtonDisabled; return this.buttonStateService.isButtonDisabled;
} }
onSubmit(ngForm: NgForm) { async onSubmit(ngForm: NgForm) {
this.buttonStateService.enableButton(); this.buttonStateService.disableButton();
if (ngForm.submitted && ngForm.form.valid) { if (ngForm.submitted && ngForm.form.valid) {
this.loginService.newPassword(this.pwResetData.password, this.oobCode); try {
await this.authService.resetPasswordConfirm(
this.pwResetData.password,
this.uid,
this.token
);
this.buttonStateService.enableButton();
} catch (error: any) {
this.errorHttpMessage = error.message;
this.buttonStateService.enableButton();
}
} }
} }
} }

View file

@ -76,6 +76,7 @@ export class LoginComponent {
async onSubmit(ngForm: NgForm) { async onSubmit(ngForm: NgForm) {
this.buttonStateService.disableButton(); this.buttonStateService.disableButton();
if (ngForm.submitted && ngForm.form.valid) { if (ngForm.submitted && ngForm.form.valid) {
this.loginData.email = this.loginData.email.toLowerCase();
try { try {
await this.authService.login(this.loginData, this.checkboxRememberMe); await this.authService.login(this.loginData, this.checkboxRememberMe);
this.router.navigate(['/summary']); this.router.navigate(['/summary']);

View file

@ -53,6 +53,7 @@ export class RegisterComponent {
this.buttonStateService.disableButton(); this.buttonStateService.disableButton();
if (ngForm.submitted && ngForm.form.valid) { if (ngForm.submitted && ngForm.form.valid) {
this.extractFirstAndLastName(); this.extractFirstAndLastName();
this.registerData.email = this.registerData.email.toLowerCase();
try { try {
await this.authService.register(this.registerData); await this.authService.register(this.registerData);
this.buttonStateService.enableButton(); this.buttonStateService.enableButton();
@ -71,8 +72,11 @@ export class RegisterComponent {
extractFirstAndLastName() { extractFirstAndLastName() {
const names = this.registerData.name.split(' '); const names = this.registerData.name.split(' ');
this.registerData.firstName = names[0]; this.registerData.firstName =
this.registerData.lastName = names.slice(1).join(' '); names[0].charAt(0).toUpperCase() + names[0].slice(1).toLowerCase();
this.registerData.lastName =
names.slice(1).join(' ').charAt(0).toUpperCase() +
names.slice(1).join(' ').slice(1).toLowerCase();
} }
isEmailValid(emailValue: string) { isEmailValid(emailValue: string) {

View file

@ -84,6 +84,23 @@ export class AuthService {
} }
} }
async resetPasswordConfirm(password: string, uid: string, token: string) {
try {
await lastValueFrom(
this.apiService.request('POST', `/auth/reset/confirm/`, {
password,
uid,
token,
})
);
this.toastNotificationService.resetPasswordConfirmSuccessToast();
this.router.navigate(['/login']);
} catch (error: any) {
console.error('Password reset confirmation failed:', error);
throw new Error(error?.error?.error);
}
}
checkAuthUser(): Observable<boolean> { checkAuthUser(): Observable<boolean> {
return this.apiService.request('GET', `/auth/`).pipe( return this.apiService.request('GET', `/auth/`).pipe(
map(() => true), map(() => true),

View file

@ -33,6 +33,10 @@ export class ErrorNotificationService {
errorMessage = errorMessage =
'The requested page could not be found. Please make sure the URL is correct and try again.'; 'The requested page could not be found. Please make sure the URL is correct and try again.';
break; break;
case 406:
errorMessage =
'The request was not acceptable. Invalid request parameters were provided.';
break;
case 408: case 408:
errorMessage = errorMessage =
'The request timed out. Please check your connection and try again later.'; 'The request timed out. Please check your connection and try again later.';

View file

@ -36,6 +36,13 @@ export class ToastNotificationService {
); );
} }
resetPasswordConfirmSuccessToast(): void {
this.createSuccessToast(
'You have successfully reset your password. Please log in.',
'Password Reset Successful'
);
}
showSessionExpiredMessage(): void { showSessionExpiredMessage(): void {
this.createInfoToast( this.createInfoToast(
'Your session has expired, please log in again.', 'Your session has expired, please log in again.',

View file

@ -20,6 +20,7 @@
"email": "Ihre E-Mail", "email": "Ihre E-Mail",
"sendMail": "E-Mail senden", "sendMail": "E-Mail senden",
"pwChange": "Passwort ändern", "pwChange": "Passwort ändern",
"invalidLink": "Dieser Link zum Zurücksetzen Ihres Passworts ist ungültig",
"notice": "Wir senden Ihnen eine E-Mail, über die Sie Ihr Passwort ändern können" "notice": "Wir senden Ihnen eine E-Mail, über die Sie Ihr Passwort ändern können"
}, },
"msgDialog": { "msgDialog": {

View file

@ -20,6 +20,7 @@
"email": "Your Email", "email": "Your Email",
"sendMail": "Send Mail", "sendMail": "Send Mail",
"pwChange": "Change Password", "pwChange": "Change Password",
"invalidLink": "This link to reset your password is invalid",
"notice": "We will send you an email to change your password." "notice": "We will send you an email to change your password."
}, },
"msgDialog": { "msgDialog": {