Adds functionality for user to change their password when they are logged into the site.

pull/90/head
Chris Veilleux 2022-08-05 15:43:20 -05:00
parent 89c5917ed7
commit b8de3f2d0b
8 changed files with 187 additions and 3 deletions

View File

@ -26,10 +26,12 @@ import { Account } from '@account/models/account.model';
import { environment } from '../../../environments/environment';
import { MembershipType } from '@account/models/membership.model';
import { handleError } from '@account/app/app.service';
import { AbstractControl } from '@angular/forms';
// URLs for the http requests
const ACCOUNT_URL = '/api/account';
const CHANGE_PASSWORD_URL = '/api/password-change';
const MEMBERSHIP_URL = '/api/memberships';
@ -80,4 +82,9 @@ export class ProfileService {
deleteAccount() {
return this.http.delete(ACCOUNT_URL);
}
changePassword(passwordControl: AbstractControl) {
const codedPassword = btoa(passwordControl.value);
return this.http.put(CHANGE_PASSWORD_URL, {password: codedPassword});
}
}

View File

@ -21,6 +21,6 @@
</mat-card-content>
<mat-card-actions>
<a mat-button>CHANGE EMAIL ADDRESS</a>
<a mat-button>CHANGE PASSWORD</a>
<a mat-button [href]="changePasswordUrl">CHANGE PASSWORD</a>
</mat-card-actions>
</mat-card>

View File

@ -21,6 +21,7 @@ import { Component, Input } from '@angular/core';
import { faAddressCard, IconDefinition } from '@fortawesome/free-solid-svg-icons';
import { Account } from '@account/models/account.model';
import { environment } from '@account/environments/environment';
@Component({
selector: 'account-login-edit',
@ -30,6 +31,7 @@ import { Account } from '@account/models/account.model';
export class LoginComponent {
@Input() account: Account;
public loginIcon: IconDefinition = faAddressCard;
public changePasswordUrl = environment.mycroftUrls.account + '/password-change';
constructor() { }
}

View File

@ -0,0 +1,29 @@
<mat-card>
<mat-card-header>
<fa-icon mat-card-avatar [icon]="changePasswordIcon"></fa-icon>
<mat-card-title>Change your password</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-form-field appearance="outline">
<mat-label>New Password</mat-label>
<input matInput required [type]="showPassword ? 'text' : 'password'" [formControl]="passwordControl">
<mat-error *ngIf="passwordControl.hasError('required')">
Password is required
</mat-error>
</mat-form-field>
<button mat-icon-button (click)="showHidePassword()">
<fa-icon [icon]="showPassword ? showIcon : hideIcon"></fa-icon>
</button>
</mat-card-content>
<mat-card-actions>
<button
mat-button
id="submit-button"
[disabled]="passwordControl.invalid"
(click)="onChangePassword()"
>
SUBMIT
</button>
<button mat-button id="cancel-button" (click)="onCancel()">CANCEL</button>
</mat-card-actions>
</mat-card>

View File

@ -0,0 +1,53 @@
// *****************************************************************************
// SPDX-License-Identifier: Apache-2.0
//
//
// Copyright (c) Mycroft AI Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing permissions
// and limitations under the License.
// *****************************************************************************
@use "@angular/material" as mat;
@use "components/buttons" as buttons;
@use "components/cards" as cards;
@use 'mycroft-theme' as theme;
mat-card {
@include cards.selene-card;
margin-left: auto;
margin-right: auto;
margin-top: 48px;
mat-card-content {
padding: 16px;
button {
margin-top: -8px;
fa-icon {
font-size: 20px;
color: mat.get-color-from-palette(theme.$mycroft-primary, 500);
margin-left: 8px;
}
}
mat-form-field {
width: 240px;
}
}
mat-card-actions {
#cancel-button {
background-color: white;
color: mat.get-color-from-palette(theme.$mycroft-accent, 800);
}
}
}

View File

@ -0,0 +1,86 @@
/*! *****************************************************************************
SPDX-License-Identifier: Apache-2.0
Copyright (c) Mycroft AI Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UntypedFormControl, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
import {faEye, faEyeSlash, faUserSecret, IconDefinition } from '@fortawesome/free-solid-svg-icons';
import { ProfileService } from '@account/http/profile.service';
import { SnackbarComponent } from 'shared';
const fiveSeconds = 5000;
@Component({
selector: 'account-change-password',
templateUrl: './change-password.component.html',
styleUrls: ['./change-password.component.scss']
})
export class ChangePasswordComponent implements OnInit {
public changePasswordIcon: IconDefinition = faUserSecret;
public hideIcon: IconDefinition = faEyeSlash;
public passwordControl = new UntypedFormControl(null, [Validators.required]);
public showIcon: IconDefinition = faEye;
public showPassword = false;
constructor(
private route: ActivatedRoute,
private profileService: ProfileService,
private snackbar: MatSnackBar,
private dialog: MatDialog,
private router: Router
) {
}
ngOnInit() {
}
onChangePassword() {
this.profileService.changePassword(this.passwordControl).subscribe({
next: () => { this.openSuccessSnackbar(); },
error: () => { this.openErrorSnackbar(); }
});
}
openErrorSnackbar() {
const config = new MatSnackBarConfig();
config.data = {type: 'error', message: 'An error occurred changing the password'};
this.snackbar.openFromComponent(SnackbarComponent, config);
}
openSuccessSnackbar() {
const config = new MatSnackBarConfig();
config.duration = fiveSeconds;
config.data = {type: 'success', message: 'Password successfully changed'};
const successSnackbar = this.snackbar.openFromComponent(SnackbarComponent, config);
successSnackbar.afterDismissed().subscribe(
() => { this.router.navigate(['/profile']); }
);
}
onCancel() {
this.router.navigate(['/profile']);
}
showHidePassword() {
this.showPassword = !this.showPassword;
}
}

View File

@ -19,10 +19,11 @@ and limitations under the License.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AccountResolverService } from '../../core/guards/account-resolver.service';
import { MembershipResolverService } from '../../core/guards/membership-resolver.service';
import { AccountResolverService } from '@account/app/core/guards/account-resolver.service';
import { MembershipResolverService } from '@account/app/core/guards/membership-resolver.service';
import { EditComponent } from './pages/edit/edit.component';
import { NewComponent } from './pages/new/new.component';
import { ChangePasswordComponent } from '@account/app/modules/profile/pages/change-password/change-password.component';
const profileRoutes: Routes = [
{
@ -39,6 +40,10 @@ const profileRoutes: Routes = [
account: AccountResolverService,
membershipTypes: MembershipResolverService
}
},
{
path: 'password-change',
component: ChangePasswordComponent
}
];

View File

@ -36,6 +36,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { NgxStripeModule } from 'ngx-stripe';
import { AgreementsComponent } from './components/cards/agreements/agreements.component';
import { ChangePasswordComponent } from './pages/change-password/change-password.component';
import { DeleteComponent } from './components/cards/delete/delete.component';
import { EditComponent } from './pages/edit/edit.component';
import { environment} from '../../../environments/environment';
@ -56,6 +57,7 @@ import { MembershipStepComponent } from './components/views/membership-step/memb
declarations: [
// Profile view and edit
AgreementsComponent,
ChangePasswordComponent,
DeleteComponent,
EditComponent,
LoginComponent,