From 0d0824b57c2ae051e0f4a320f5e6969bc18ba46f Mon Sep 17 00:00:00 2001 From: Martin Kostka Date: Fri, 3 Sep 2021 13:12:02 +0200 Subject: [PATCH] feat(user-profile): change password * added option to change password on selected namespace(if supported) * added shared dialog for changing the password --- apps/user-profile/src/assets/i18n/cs.json | 15 +++++ apps/user-profile/src/assets/i18n/en.json | 19 +++++- .../password-reset.component.html | 8 ++- .../password-reset.component.ts | 21 +++++- .../change-password-dialog.component.css | 8 +++ .../change-password-dialog.component.html | 46 +++++++++++++ .../change-password-dialog.component.ts | 65 +++++++++++++++++++ .../dialogs/src/lib/perun-dialogs.module.ts | 4 +- 8 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.css create mode 100644 libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.html create mode 100644 libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.ts diff --git a/apps/user-profile/src/assets/i18n/cs.json b/apps/user-profile/src/assets/i18n/cs.json index 9c0ec1ef6..0ef604705 100644 --- a/apps/user-profile/src/assets/i18n/cs.json +++ b/apps/user-profile/src/assets/i18n/cs.json @@ -327,6 +327,7 @@ "PASSWORD_RESET": { "TITLE": "Změna hesla", "CHANGE_PASSWORD": "Změnit heslo", + "RESET_PASSWORD": "Resetovat heslo", "NAMESPACE": "Jmenný prostor", "LOGIN": "Přihlašovací jméno", "NOT_SUPPORTED": "Zména hesla není podporována ve vašich jmených prostorech" @@ -350,6 +351,20 @@ "CANCEL": "Zrušit", "SEND": "Poslat", "SUCCESS": "Chyba byla nahlášena a dostala lístek s číslem: " + }, + "CHANGE_PASSWORD_DIALOG": { + "TITLE": "Změna hesla", + "CANCEL": "Zrušit", + "CHANGE": "Potvrdit", + "OLD_PASSWORD": "Staré heslo", + "NEW_PASSWORD": "Nové heslo", + "NEW_PASSWORD_AGAIN": "Znovu zadejte nové heslo", + "PWD_DONT_MATCH": "Hesla se neshodují.", + "PWD_WEAK": "Heslo nesplňuje požadavky.", + "PWD_SHORT": "Heslo je příliš krátké.", + "FIELD_EMPTY": "Tohle políčko musí být vyplněné.", + "PASSWORD_INFO": "Heslo musí:\n - obsahovat pouze tisknutelné znaky bez diakritiky \n - být alespoň 10 znaků dlouhé\n - obsahovat nejméně 3 ze 4 skupin znaků:\n - malá písmena\n - velká písmena\n - čísla\n - speciální znaky", + "SUCCESS": "Heslo bylo úspěšně změněno" } }, "ORGANIZATIONS": { diff --git a/apps/user-profile/src/assets/i18n/en.json b/apps/user-profile/src/assets/i18n/en.json index 340ba3a38..4e156d70b 100644 --- a/apps/user-profile/src/assets/i18n/en.json +++ b/apps/user-profile/src/assets/i18n/en.json @@ -20,7 +20,7 @@ "PREFERRED_UNIX_GROUP_NAMES": "Preferred unix group names", "SAMBA_PASSWORD": "Samba password", "SSH_KEYS": "SSH keys", - "PASSWORD_RESET": "Password reset", + "PASSWORD_RESET": "Change password", "AUTHENTICATION": "Authentication" }, "ORGANIZATIONS": { @@ -368,8 +368,9 @@ "SUCCESS": "User external source successfully removed" }, "PASSWORD_RESET": { - "TITLE": "Password reset", + "TITLE": "Change password", "CHANGE_PASSWORD": "Change password", + "RESET_PASSWORD": "Reset password", "NAMESPACE": "Namespace", "LOGIN": "Login", "NOT_SUPPORTED": "Password reset is not supported for your current namespaces" @@ -421,6 +422,20 @@ "CANCEL": "Cancel", "SEND": "Send", "SUCCESS": "Issue report was sent and got ticket number: " + }, + "CHANGE_PASSWORD_DIALOG": { + "TITLE": "Change password", + "CANCEL": "Cancel", + "CHANGE": "Confirm", + "OLD_PASSWORD": "Old password", + "NEW_PASSWORD": "New password", + "NEW_PASSWORD_AGAIN": "Re-type new password", + "PWD_DONT_MATCH": "Passwords do not match", + "PWD_WEAK": "Password does not meet the requirements", + "PWD_SHORT": "Password is too short", + "FIELD_EMPTY": "This field cannot be empty", + "PASSWORD_INFO": "Password must:\n - contain only printing non-accented characters\n - be at least 10 characters long\n - consist of at least 3 of 4 character groups:\n - lower-case letters\n - upper-case letters\n - digits\n - special characters", + "SUCCESS": "Password has been changed successfully," } }, "ORGANIZATIONS": { diff --git a/libs/perun/components/src/lib/password-reset/password-reset.component.html b/libs/perun/components/src/lib/password-reset/password-reset.component.html index a4d8faaed..2764290f4 100644 --- a/libs/perun/components/src/lib/password-reset/password-reset.component.html +++ b/libs/perun/components/src/lib/password-reset/password-reset.component.html @@ -13,10 +13,16 @@

{{'SHARED_LIB.PERUN.COMPONENTS.PASSWORD_RESET.TITLE' | {{'SHARED_LIB.PERUN.COMPONENTS.PASSWORD_RESET.LOGIN' | customTranslate | translate}} {{login.value}} + + + + + + - + diff --git a/libs/perun/components/src/lib/password-reset/password-reset.component.ts b/libs/perun/components/src/lib/password-reset/password-reset.component.ts index 58849d51c..64227c100 100644 --- a/libs/perun/components/src/lib/password-reset/password-reset.component.ts +++ b/libs/perun/components/src/lib/password-reset/password-reset.component.ts @@ -2,6 +2,9 @@ import { Component, OnInit } from '@angular/core'; import { Attribute, AttributesManagerService} from '@perun-web-apps/perun/openapi'; import { StoreService } from '@perun-web-apps/perun/services'; import { MatTableDataSource } from '@angular/material/table'; +import { MatDialog } from '@angular/material/dialog'; +import { getDefaultDialogConfig } from '@perun-web-apps/perun/utils'; +import { ChangePasswordDialogComponent } from '../../../../dialogs/src/lib/change-password-dialog/change-password-dialog.component'; @Component({ selector: 'perun-web-apps-password-reset', @@ -15,11 +18,12 @@ export class PasswordResetComponent implements OnInit { nameSpaces: string[] = []; logins: Attribute[] = []; - displayedColumns: string[] = ['namespace', 'value', 'change']; + displayedColumns: string[] = ['namespace', 'value', 'reset', 'change']; dataSource: MatTableDataSource; constructor(private attributesManagerService: AttributesManagerService, - private store: StoreService) { + private store: StoreService, + private dialog: MatDialog) { } ngOnInit(): void { @@ -36,8 +40,19 @@ export class PasswordResetComponent implements OnInit { }); } - changePassword(login: string) { + resetPassword(login: string) { const url = this.store.get('pwd_reset_base_url'); location.href = `${url}?login-namespace=${login}`; } + + changePassword(login){ + const config = getDefaultDialogConfig(); + config.width = '600px'; + config.data = { + login: login.value, + namespace: login.friendlyName.split(':')[1] + }; + + this.dialog.open(ChangePasswordDialogComponent, config); + } } diff --git a/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.css b/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.css new file mode 100644 index 000000000..34fa7e1c3 --- /dev/null +++ b/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.css @@ -0,0 +1,8 @@ +.display-flex { + display: flex; + flex-direction: column; +} + +.white-space-pre { + white-space: pre; +} diff --git a/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.html b/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.html new file mode 100644 index 000000000..ac0ae71d0 --- /dev/null +++ b/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.html @@ -0,0 +1,46 @@ +

{{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.TITLE' | translate}}

+
+
+
+ + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.OLD_PASSWORD' | translate}} + + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.FIELD_EMPTY' | translate}} + + + + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.NEW_PASSWORD' | translate}} + + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.FIELD_EMPTY' | translate}} + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.PWD_WEAK' | translate}} + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.PWD_SHORT' | translate}} + + + + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.NEW_PASSWORD_AGAIN' | translate}} + + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.FIELD_EMPTY' | translate}} + {{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.PWD_DONT_MATCH' | translate}} + + +

{{'SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.PASSWORD_INFO' | translate}}

+
+
+ +
+ +
+
+ + +
+
diff --git a/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.ts b/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.ts new file mode 100644 index 000000000..4e2985712 --- /dev/null +++ b/libs/perun/dialogs/src/lib/change-password-dialog/change-password-dialog.component.ts @@ -0,0 +1,65 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { UsersManagerService } from '@perun-web-apps/perun/openapi'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { CustomValidators } from '@perun-web-apps/perun/utils'; +import { NotificatorService } from '@perun-web-apps/perun/services'; +import { TranslateService } from '@ngx-translate/core'; + +export interface ChangePasswordDialogData { + namespace: string; + login: string; +} + +@Component({ + selector: 'perun-web-apps-change-password-dialog', + templateUrl: './change-password-dialog.component.html', + styleUrls: ['./change-password-dialog.component.css'] +}) +export class ChangePasswordDialogComponent implements OnInit { + + formGroup: FormGroup; + oldPwd: AbstractControl; + newPwd: AbstractControl; + newPwdAgain: AbstractControl; + successMessage: string; + loading: boolean; + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) private data: ChangePasswordDialogData, + private _formBuilder: FormBuilder, + private usersManagerService: UsersManagerService, + private notificator: NotificatorService, + private translate: TranslateService) { + translate.get('SHARED_LIB.PERUN.COMPONENTS.CHANGE_PASSWORD_DIALOG.SUCCESS').subscribe(m => this.successMessage = m); + } + + ngOnInit(): void { + this.formGroup = this._formBuilder.group({ + oldPasswordCtrl: ['', Validators.required], + passwordCtrl: ['', Validators.compose([ + CustomValidators.patternValidator([/\d/, /[A-Z]/, /[a-z]/, /[$&+,:;=?@#|'<>.^*()%!-]/]), + Validators.minLength(10)]) + ], + passwordAgainCtrl: [''] + }, { + validator: CustomValidators.passwordMatchValidator + }); + this.oldPwd = this.formGroup.get('oldPasswordCtrl'); + this.newPwd = this.formGroup.get('passwordCtrl'); + this.newPwdAgain = this.formGroup.get('passwordAgainCtrl'); + } + + close() { + this.dialogRef.close(false); + } + + changePassword() { + this.loading = true; + this.usersManagerService.changePasswordForLogin(this.data.login, this.data.namespace, this.newPwd.value, this.oldPwd.value, true).subscribe(() => { + this.notificator.showSuccess(this.successMessage); + this.loading = false; + this.dialogRef.close(true); + }); + } +} diff --git a/libs/perun/dialogs/src/lib/perun-dialogs.module.ts b/libs/perun/dialogs/src/lib/perun-dialogs.module.ts index 5cdebfa75..1f14d90c6 100644 --- a/libs/perun/dialogs/src/lib/perun-dialogs.module.ts +++ b/libs/perun/dialogs/src/lib/perun-dialogs.module.ts @@ -37,6 +37,7 @@ import { ChangeGroupExpirationDialogComponent } from './change-group-expiration- import { ChangeVoExpirationDialogComponent } from './change-vo-expiration-dialog/change-vo-expiration-dialog.component'; import { ChangeSponsorshipExpirationDialogComponent } from './change-sponsorship-expiration-dialog/change-sponsorship-expiration-dialog.component'; import { ChangeGroupResourceAssigmentDialogComponent } from './change-group-resource-assigment-dialog/change-group-resource-assigment-dialog.component'; +import { ChangePasswordDialogComponent } from './change-password-dialog/change-password-dialog.component'; @NgModule({ imports: [ @@ -80,7 +81,8 @@ import { ChangeGroupResourceAssigmentDialogComponent } from './change-group-reso ChangeGroupExpirationDialogComponent, ChangeVoExpirationDialogComponent, ChangeSponsorshipExpirationDialogComponent, - ChangeGroupResourceAssigmentDialogComponent + ChangeGroupResourceAssigmentDialogComponent, + ChangePasswordDialogComponent ], exports: [ ChangeExpirationDialogComponent,