(this.baseUrl + 'account/forgot-password?email=' + encodeURIComponent(email), {}, {responseType: 'text' as 'json'});
+ }
+
+ confirmResetPasswordEmail(model: {email: string, token: string, password: string}) {
+ return this.httpClient.post(this.baseUrl + 'account/confirm-password-reset', model);
+ }
+
resetPassword(username: string, password: string) {
return this.httpClient.post(this.baseUrl + 'account/reset-password', {username, password}, {responseType: 'json' as 'text'});
}
diff --git a/UI/Web/src/app/_services/member.service.ts b/UI/Web/src/app/_services/member.service.ts
index 1c7820e8a..5ba08dca4 100644
--- a/UI/Web/src/app/_services/member.service.ts
+++ b/UI/Web/src/app/_services/member.service.ts
@@ -25,7 +25,7 @@ export class MemberService {
}
deleteMember(username: string) {
- return this.httpClient.delete(this.baseUrl + 'users/delete-user?username=' + username);
+ return this.httpClient.delete(this.baseUrl + 'users/delete-user?username=' + encodeURIComponent(username));
}
hasLibraryAccess(libraryId: number) {
diff --git a/UI/Web/src/app/admin/manage-users/manage-users.component.html b/UI/Web/src/app/admin/manage-users/manage-users.component.html
index 76cdd8747..4a591b850 100644
--- a/UI/Web/src/app/admin/manage-users/manage-users.component.html
+++ b/UI/Web/src/app/admin/manage-users/manage-users.component.html
@@ -56,7 +56,7 @@
{{member.lastActive | date: 'short'}}
- Sharing: {{formatLibraries(member)}}
+ Sharing: {{formatLibraries(member)}}
Roles:
None
diff --git a/UI/Web/src/app/admin/manage-users/manage-users.component.ts b/UI/Web/src/app/admin/manage-users/manage-users.component.ts
index 1dc25ce53..bfb534670 100644
--- a/UI/Web/src/app/admin/manage-users/manage-users.component.ts
+++ b/UI/Web/src/app/admin/manage-users/manage-users.component.ts
@@ -167,4 +167,5 @@ export class ManageUsersComponent implements OnInit, OnDestroy {
getRoles(member: Member) {
return member.roles.filter(item => item != 'Pleb');
}
+
}
diff --git a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html
new file mode 100644
index 000000000..9046a1fbe
--- /dev/null
+++ b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html
@@ -0,0 +1,28 @@
+
+ Password Reset
+
+ Enter the email of your account. We will send you an email
+
+
+
diff --git a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.scss b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts
new file mode 100644
index 000000000..2fdcbc910
--- /dev/null
+++ b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts
@@ -0,0 +1,50 @@
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormControl, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { ToastrService } from 'ngx-toastr';
+import { AccountService } from 'src/app/_services/account.service';
+
+@Component({
+ selector: 'app-confirm-reset-password',
+ templateUrl: './confirm-reset-password.component.html',
+ styleUrls: ['./confirm-reset-password.component.scss']
+})
+export class ConfirmResetPasswordComponent implements OnInit {
+
+ token: string = '';
+ registerForm: FormGroup = new FormGroup({
+ email: new FormControl('', [Validators.required, Validators.email]),
+ password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]),
+ });
+
+ constructor(private route: ActivatedRoute, private router: Router, private accountService: AccountService, private toastr: ToastrService) {
+ const token = this.route.snapshot.queryParamMap.get('token');
+ const email = this.route.snapshot.queryParamMap.get('email');
+ if (token == undefined || token === '' || token === null) {
+ // This is not a valid url, redirect to login
+ this.toastr.error('Invalid reset password url');
+ this.router.navigateByUrl('login');
+ return;
+ }
+
+ this.token = token;
+ this.registerForm.get('email')?.setValue(email);
+
+ }
+
+ ngOnInit(): void {
+ }
+
+ submit() {
+ const model = this.registerForm.getRawValue();
+ model.token = this.token;
+ this.accountService.confirmResetPasswordEmail(model).subscribe(() => {
+ this.toastr.success("Password reset");
+ this.router.navigateByUrl('login');
+ }, err => {
+ console.log(err);
+ });
+ }
+
+
+}
diff --git a/UI/Web/src/app/registration/register/register.component.html b/UI/Web/src/app/registration/register/register.component.html
index d6e4c987d..c87826e68 100644
--- a/UI/Web/src/app/registration/register/register.component.html
+++ b/UI/Web/src/app/registration/register/register.component.html
@@ -1,10 +1,3 @@
-
Register
diff --git a/UI/Web/src/app/registration/register/register.component.ts b/UI/Web/src/app/registration/register/register.component.ts
index 9cf3f4443..76ac3d87d 100644
--- a/UI/Web/src/app/registration/register/register.component.ts
+++ b/UI/Web/src/app/registration/register/register.component.ts
@@ -38,8 +38,6 @@ export class RegisterComponent implements OnInit {
this.accountService.register(model).subscribe((user) => {
this.toastr.success('Account registration complete');
this.router.navigateByUrl('login');
- }, err => {
- // TODO: Handle errors
});
}
diff --git a/UI/Web/src/app/registration/registration.module.ts b/UI/Web/src/app/registration/registration.module.ts
index 1e1f89c38..873c512f7 100644
--- a/UI/Web/src/app/registration/registration.module.ts
+++ b/UI/Web/src/app/registration/registration.module.ts
@@ -8,6 +8,8 @@ import { SplashContainerComponent } from './splash-container/splash-container.co
import { RegisterComponent } from './register/register.component';
import { AddEmailToAccountMigrationModalComponent } from './add-email-to-account-migration-modal/add-email-to-account-migration-modal.component';
import { ConfirmMigrationEmailComponent } from './confirm-migration-email/confirm-migration-email.component';
+import { ResetPasswordComponent } from './reset-password/reset-password.component';
+import { ConfirmResetPasswordComponent } from './confirm-reset-password/confirm-reset-password.component';
@@ -17,7 +19,9 @@ import { ConfirmMigrationEmailComponent } from './confirm-migration-email/confir
SplashContainerComponent,
RegisterComponent,
AddEmailToAccountMigrationModalComponent,
- ConfirmMigrationEmailComponent
+ ConfirmMigrationEmailComponent,
+ ResetPasswordComponent,
+ ConfirmResetPasswordComponent
],
imports: [
CommonModule,
diff --git a/UI/Web/src/app/registration/registration.router.module.ts b/UI/Web/src/app/registration/registration.router.module.ts
index 688b43d70..f87951c25 100644
--- a/UI/Web/src/app/registration/registration.router.module.ts
+++ b/UI/Web/src/app/registration/registration.router.module.ts
@@ -2,7 +2,9 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ConfirmEmailComponent } from './confirm-email/confirm-email.component';
import { ConfirmMigrationEmailComponent } from './confirm-migration-email/confirm-migration-email.component';
+import { ConfirmResetPasswordComponent } from './confirm-reset-password/confirm-reset-password.component';
import { RegisterComponent } from './register/register.component';
+import { ResetPasswordComponent } from './reset-password/reset-password.component';
const routes: Routes = [
{
@@ -16,6 +18,14 @@ const routes: Routes = [
{
path: 'register',
component: RegisterComponent,
+ },
+ {
+ path: 'reset-password',
+ component: ResetPasswordComponent
+ },
+ {
+ path: 'confirm-reset-password',
+ component: ConfirmResetPasswordComponent
}
];
diff --git a/UI/Web/src/app/registration/reset-password/reset-password.component.html b/UI/Web/src/app/registration/reset-password/reset-password.component.html
new file mode 100644
index 000000000..ed3eaedc8
--- /dev/null
+++ b/UI/Web/src/app/registration/reset-password/reset-password.component.html
@@ -0,0 +1,24 @@
+
+ Password Reset
+
+ Enter the email of your account. We will send you an email
+
+
+
diff --git a/UI/Web/src/app/registration/reset-password/reset-password.component.scss b/UI/Web/src/app/registration/reset-password/reset-password.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/UI/Web/src/app/registration/reset-password/reset-password.component.ts b/UI/Web/src/app/registration/reset-password/reset-password.component.ts
new file mode 100644
index 000000000..4080b4f63
--- /dev/null
+++ b/UI/Web/src/app/registration/reset-password/reset-password.component.ts
@@ -0,0 +1,31 @@
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormControl, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { ToastrService } from 'ngx-toastr';
+import { AccountService } from 'src/app/_services/account.service';
+
+@Component({
+ selector: 'app-reset-password',
+ templateUrl: './reset-password.component.html',
+ styleUrls: ['./reset-password.component.scss']
+})
+export class ResetPasswordComponent implements OnInit {
+
+ registerForm: FormGroup = new FormGroup({
+ email: new FormControl('', [Validators.required, Validators.email]),
+ });
+
+ constructor(private route: ActivatedRoute, private router: Router, private accountService: AccountService, private toastr: ToastrService) {}
+
+ ngOnInit(): void {
+ }
+
+ submit() {
+ const model = this.registerForm.get('email')?.value;
+ this.accountService.requestResetPasswordEmail(model).subscribe((resp: string) => {
+ this.toastr.info(resp);
+ this.router.navigateByUrl('login');
+ });
+ }
+
+}
diff --git a/UI/Web/src/app/registration/splash-container/splash-container.component.scss b/UI/Web/src/app/registration/splash-container/splash-container.component.scss
index ac14abbc4..40255e600 100644
--- a/UI/Web/src/app/registration/splash-container/splash-container.component.scss
+++ b/UI/Web/src/app/registration/splash-container/splash-container.component.scss
@@ -1,5 +1,7 @@
@use "../../../theme/colors";
+
+
.login {
display: flex;
align-items: center;
@@ -72,6 +74,15 @@
box-shadow: 0 0 0 0.2rem rgb(68 79 117 / 50%);
}
}
+
+ ::ng-deep input {
+ background-color: #fff !important;
+ color: black;
+ }
+
+ ::ng-deep a {
+ color: white;
+ }
}
.invalid-feedback {
@@ -79,7 +90,3 @@
color: #343c59;
}
-input {
- background-color: #fff !important;
- color: black;
-}
\ No newline at end of file
diff --git a/UI/Web/src/app/user-login/user-login.component.html b/UI/Web/src/app/user-login/user-login.component.html
index c595203c1..badfde742 100644
--- a/UI/Web/src/app/user-login/user-login.component.html
+++ b/UI/Web/src/app/user-login/user-login.component.html
@@ -13,6 +13,10 @@
+
+