From 8075cafc9e1e18652498c338d31eaad32a8b02db Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sat, 24 Feb 2024 15:08:06 +0100 Subject: [PATCH] Request password reset from user settings --- .../password-reset.component.html | 11 +++- .../password-reset.component.ts | 50 +++++++++++++++++-- src/app/user/settings/settings.component.html | 6 ++- src/app/user/settings/settings.component.ts | 32 ++++++++++++ src/services/auth.service.ts | 7 +++ 5 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/app/auth/password-reset/password-reset.component.html b/src/app/auth/password-reset/password-reset.component.html index 0bd76f6e..f6b72ffd 100644 --- a/src/app/auth/password-reset/password-reset.component.html +++ b/src/app/auth/password-reset/password-reset.component.html @@ -1,7 +1,7 @@

Reset your password!

-
+
{{ errorTranslationKey | translate }}
@@ -9,10 +9,17 @@

Reset your password!

-
+
+
+ +
+
diff --git a/src/app/auth/password-reset/password-reset.component.ts b/src/app/auth/password-reset/password-reset.component.ts index 7cad6895..ccbbc791 100644 --- a/src/app/auth/password-reset/password-reset.component.ts +++ b/src/app/auth/password-reset/password-reset.component.ts @@ -1,4 +1,7 @@ import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { AuthService } from '../../../services/auth.service'; +import { firstValueFrom } from 'rxjs'; @Component({ selector: 'app-password-reset', @@ -6,14 +9,55 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./password-reset.component.scss'] }) export class PasswordResetComponent implements OnInit { - errorTranslationKey: string | null = 'auth.passwordReset.bla'; + errorTranslationKey: string | null = 'auth.passwordReset.error.PASSWORD_RESET_CODE_INVALID'; + resetToken: string | null = null; - loading = false; + loading = true; newPassword = ''; + notificationClass = 'is-danger'; - constructor() { } + constructor( + private authService: AuthService, + private route: ActivatedRoute, + ) { } ngOnInit(): void { + this.route.params.subscribe(params => { + this.resetToken = params['token']; + + if (this.resetToken) { + this.errorTranslationKey = null; + } + + this.loading = false; + }); + } + + async performReset() { + if (!this.resetToken) { + this.errorTranslationKey = 'auth.passwordReset.error.PASSWORD_RESET_CODE_INVALID'; + } + + this.loading = true; + this.notificationClass = 'is-danger'; + + try { + const { status } = await firstValueFrom(this.authService.resetPassword(this.resetToken, this.newPassword)); + + if (status === 'PASSWORD_RESET_SUCCESS') { + this.notificationClass = 'is-success'; + this.errorTranslationKey = 'auth.passwordReset.success'; + this.newPassword = ''; + } + } catch (e: any) { + if ((e.error || {}).errors) { + this.errorTranslationKey = e.error.errors.flatMap(error => error.defaultMessage.split(',')).join('\n'); + } else if (e.error.status) { + this.errorTranslationKey = `auth.passwordReset.error.${e.error.status.toUpperCase()}`; + } + } finally { + this.loading = false; + } } } diff --git a/src/app/user/settings/settings.component.html b/src/app/user/settings/settings.component.html index 9e8a985f..db8c6b14 100644 --- a/src/app/user/settings/settings.component.html +++ b/src/app/user/settings/settings.component.html @@ -131,7 +131,11 @@

{{'user.settings.general' | translate}}

- +

Clicking this button will send you an email to reset your password, if you did not have a password set previously this will set it.

diff --git a/src/app/user/settings/settings.component.ts b/src/app/user/settings/settings.component.ts index 75bc9dd4..ed3b0da4 100644 --- a/src/app/user/settings/settings.component.ts +++ b/src/app/user/settings/settings.component.ts @@ -11,6 +11,7 @@ import { PatreonStatusDto, RelationShip } from '../../../model/annoying-patreon- import DOMPurify from 'dompurify'; import { AuthService } from '../../../services/auth.service'; import { InitMFADto } from '../../../model/auth'; +import { firstValueFrom } from 'rxjs'; interface LangType { value: string; @@ -36,6 +37,7 @@ export class SettingsComponent implements OnInit { public deactivateConfirm = false; public deleteConfirm = false; public deleteUsername: string; + pwResetButtonDisabled = false; constructor(private userService: UserService, private authService: AuthService, @@ -209,6 +211,36 @@ export class SettingsComponent implements OnInit { }); } + async requestNewPassword(): Promise { + if (!this.user.emailVerified) { + this.translateService.get('auth.emailVerificationRequired').subscribe((res: string) => { + alert(res); + }); + + return; + } + + this.loading = true; + + try { + const { status } = await firstValueFrom(this.authService.requestPasswordReset(this.user.mail)); + + if (status === 'PASSWORD_RESET_SENT') { + this.pwResetButtonDisabled = true; + this.translateService.get('auth.passwordReset.requested').subscribe((res: string) => { + this.showSuccessToast(res); + }); + } + + console.log(status); + } catch (e: any) { + console.log(e.error); + alert(`Something went wrong: ${JSON.stringify(e.error)}`); + } finally { + this.loading = false; + } + } + handleMfaResult(result: boolean): void { // true == mfa stored // false == mfa failed diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index a3103f38..ce633288 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -91,6 +91,13 @@ export class AuthService extends BaseService { return this.http.post<{ status: string }>(this.v2Url('password-reset/request'), { email }); } + resetPassword(token: String, newPassword: String) { + return this.http.post<{ status: string }>(this.v2Url('password-reset'), { + token, + password: newPassword, + }); + } + initMfaSettings(): Observable { return this.http.put(this.v2Url('mfa/init'), null); }