Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internationalized Change Password dialog #3747

Merged
merged 2 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public IActionResult PostChangePassword([FromBody] ChangePassword changePass)
new PasswordResponse()
{
IsValid = false,
Message = "Current password is invalid.<br>Correct it or request a new temporary password."
Message = "current invalid"
});
}

Expand All @@ -153,7 +153,7 @@ public IActionResult PostChangePassword([FromBody] ChangePassword changePass)
!respComplex.PasswordContainsSpecial || !respComplex.PasswordNotReused)
{
respComplex.IsValid = false;
respComplex.Message = "New password does not satisfy all password policy requirements.";
respComplex.Message = "rules not satisfied";
return Ok(respComplex);
}

Expand Down
4 changes: 2 additions & 2 deletions CSETWebNg/src/app/dialogs/alert/alert.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-------------------------->
<div class="alert-dialog d-flex flex-column justify-content-center flex-11a">
<div class="alert-dialog d-flex flex-column justify-content-center flex-11a" *transloco="let t">
<div class="mat-dialog-header p-3 d-flex justify-content-start align-items-center flex-00a">
<span [ngClass]="iconClass" class="fs-base-6 mr-3"></span>
<span>{{ data.title | titlecase }}</span>
Expand All @@ -34,7 +34,7 @@
</div>

<mat-dialog-actions class="p-3 mb-0 d-flex justify-content-start flex-00a">
<button class="btn btn-secondary" (click)="close()">OK</button>
<button class="btn btn-secondary" (click)="close()">{{t('buttons.ok')}}</button>
</mat-dialog-actions>

</div>
Original file line number Diff line number Diff line change
Expand Up @@ -20,74 +20,73 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-------------------------->
<div class="d-flex flex-column justify-content-center flex-11a">
<div class="d-flex flex-column justify-content-center flex-11a" *transloco="let t">
<div class="mat-dialog-header p-3 d-flex justify-content-start align-items-center flex-00a">
<span class="mr-3 fs-base-6 cset-icons-key"></span>
<div>Change Password</div>
<div>{{ t('change password.dialog title') }}</div>
</div>
<mat-dialog-content class="p-3 pr-0 oy-auto d-flex flex-column flex-11a">
<div class="alert alert-default">
<ul class="list-group list-group-flush">
<li class="list-group-item"><span *ngIf="passwordResponse.passwordLengthMet"><i
class='fa-solid fa-square-check'></i></span><span *ngIf="!passwordResponse.passwordLengthMet"><i
class='fa-solid fa-square-xmark'></i></span> &nbsp;Length between {{passwordResponse.passwordLengthMin}}
and {{passwordResponse.passwordLengthMax}} characters</li>
class='fa-solid fa-square-check mr-2'></i></span><span *ngIf="!passwordResponse.passwordLengthMet"><i
class='fa-solid fa-square-xmark mr-2'></i></span>{{ t('change password.rules.length between', {lengthMin:
passwordResponse.passwordLengthMin, lengthMax: passwordResponse.passwordLengthMax}) }}</li>
<li class="list-group-item"><span *ngIf="passwordResponse.passwordContainsNumbers"><i
class='fa-solid fa-square-check'></i></span><span *ngIf="!passwordResponse.passwordContainsNumbers"><i
class='fa-solid fa-square-xmark'></i></span> &nbsp;Must contain at least 2 numbers</li>
class='fa-solid fa-square-check mr-2'></i></span><span *ngIf="!passwordResponse.passwordContainsNumbers"><i
class='fa-solid fa-square-xmark mr-2'></i></span>{{ t('change password.rules.required numbers') }}</li>
<li class="list-group-item"><span *ngIf="passwordResponse.passwordContainsLower"><i
class='fa-solid fa-square-check'></i></span><span *ngIf="!passwordResponse.passwordContainsLower"><i
class='fa-solid fa-square-xmark'></i></span> &nbsp;Must contain at least 1 lowercase letter</li>
class='fa-solid fa-square-check mr-2'></i></span><span *ngIf="!passwordResponse.passwordContainsLower"><i
class='fa-solid fa-square-xmark mr-2'></i></span>{{ t('change password.rules.required lowercase') }}</li>
<li class="list-group-item"><span *ngIf="passwordResponse.passwordContainsUpper"><i
class='fa-solid fa-square-check'></i></span><span *ngIf="!passwordResponse.passwordContainsUpper"><i
class='fa-solid fa-square-xmark'></i></span> &nbsp;Must contain at least 1 uppercase letter</li>
class='fa-solid fa-square-check mr-2'></i></span><span *ngIf="!passwordResponse.passwordContainsUpper"><i
class='fa-solid fa-square-xmark mr-2'></i></span>{{ t('change password.rules.required uppercase') }}</li>
<li class="list-group-item"><span *ngIf="passwordResponse.passwordContainsSpecial"><i
class='fa-solid fa-square-check'></i></span><span *ngIf="!passwordResponse.passwordContainsSpecial"><i
class='fa-solid fa-square-xmark'></i></span> &nbsp;Must contain at least 1 special character</li>
class='fa-solid fa-square-check mr-2'></i></span><span *ngIf="!passwordResponse.passwordContainsSpecial"><i
class='fa-solid fa-square-xmark mr-2'></i></span>{{ t('change password.rules.required special') }}</li>
<li class="list-group-item"><span *ngIf="passwordResponse.passwordNotReused"><i
class='fa-solid fa-square-check'></i></span><span *ngIf="!passwordResponse.passwordNotReused"><i
class='fa-solid fa-square-xmark'></i></span> &nbsp;Must not re-use previous
{{passwordResponse.numberOfHistoricalPasswords}} passwords</li>
class='fa-solid fa-square-check mr-2'></i></span><span *ngIf="!passwordResponse.passwordNotReused"><i
class='fa-solid fa-square-xmark mr-2'></i></span>{{ t('change password.rules.previous count', {count:
passwordResponse.numberOfHistoricalPasswords}) }}</li>
</ul>
</div>
<div class="alert alert-danger" *ngIf="message?.length > 0" [innerHTML]="message"></div>

<form #fReg="ngForm" (ngSubmit)="onPasswordChangeClick(fReg)" class="pr-3">
<div class="form-group">
<div class="d-flex justify-content-between">
<label required for="currentPassword">Current Password</label>
<label required for="currentPassword">{{ t('change password.current password') }}</label>
<div *ngIf="!showPassword" class="show-hide-password" (click)="togglePasswordVisibility()">
Show Passwords<i class="fas fa-eye ml-1"></i>
{{ t('change password.show passwords') }}<i class="fas fa-eye ml-1"></i>
</div>
<div *ngIf="showPassword" class="show-hide-password" (click)="togglePasswordVisibility()">
Hide Passwords<i class="fas fa-eye-slash ml-1"></i>
{{ t('change password.hide passwords') }}<i class="fas fa-eye-slash ml-1"></i>
</div>
</div>
<input [type]="showPassword ? 'text' : 'password'" id="currentPassword" name="currentPassword"
class="form-control" required [(ngModel)]="cpwd.currentPassword">
</div>
<div class="form-group">
<label required for="password">New Password</label>
<label required for="password">{{ t('change password.new password') }}</label>
<input [type]="showPassword ? 'text' : 'password'" name="password" id="password" class="form-control"
(ngModelChange)="checkPassword($event)" [(ngModel)]="cpwd.newPassword" required>
</div>
<div class="form-group">
<label required for="confirmPassword">Confirm New Password</label>
<label required for="confirmPassword">{{ t('change password.confirm new password') }}</label>
<input [type]="showPassword ? 'text' : 'password'" class="form-control" id="confirmPassword"
name="confirmPassword" [(ngModel)]="cpwd.confirmPassword" appConfirmEqualValidator="password" required>
</div>

<mat-dialog-actions class="pt-0 mb-0 d-flex flex-column flex-00a">
<div class="alert alert-danger"
*ngIf="fReg.submitted && fReg.controls.confirmPassword.touched && fReg.controls.confirmPassword.errors?.notEqual">
Passwords do not match.</div>
<div class="alert alert-danger"
*ngIf="fReg.submitted && (fReg.controls.confirmPassword.errors?.required && fReg.controls.confirmPassword.errors?.required)">
New Password and Confirmation are required.</div>
<div class="d-flex justify-content-between flex-11a">
<button class="btn btn-primary m-0 mr-1">Change Password</button>
<button class="btn btn-secondary mr-1" (click)="cancel()">Cancel</button>
</div>
<div class="alert alert-danger"
*ngIf="fReg.submitted && fReg.controls.confirmPassword.touched && fReg.controls.confirmPassword.errors?.notEqual">
{{ t('change password.passwords do not match') }}</div>
<div class="alert alert-danger"
*ngIf="fReg.submitted && (fReg.controls.confirmPassword.errors?.required && fReg.controls.confirmPassword.errors?.required)">
{{ t('change password.new and confirmation required') }}</div>

<mat-dialog-actions class="p-3 pt-0 mb-0 d-flex justify-content-between flex-11a">
<button class="btn btn-primary m-0 mr-1">{{ t('buttons.change password') }}</button>
<button class="btn btn-secondary mr-1" (click)="cancel()">{{ t('buttons.cancel') }}</button>
</mat-dialog-actions>
</form>
</mat-dialog-content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { environment } from '../../../environments/environment';
import { ChangePassword } from '../../models/reset-pass.model';
import { AuthenticationService } from '../../services/authentication.service';
import { BehaviorSubject, Observable } from 'rxjs';
import { TranslocoService } from '@ngneat/transloco';

@Component({
selector: 'app-change-password',
Expand All @@ -48,7 +49,7 @@ export class ChangePasswordComponent implements OnInit {
private _passwordContainsNumbers: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public passwordContainsNumbers: Observable<boolean> = this._passwordContainsNumbers.asObservable();

msgChangeTempPw = 'Temporary password must be changed on first logon.';
msgChangeTempPw = this.tSvc.translate('change password.change temp on logon');
check = true;
passwordResponse: any = {
passwordLengthMin: 13,
Expand All @@ -64,6 +65,7 @@ export class ChangePasswordComponent implements OnInit {

constructor(private auth: AuthenticationService,
private router: Router,
public tSvc: TranslocoService,
public dialogRef: MatDialogRef<ChangePasswordComponent>,
private ref: ChangeDetectorRef,
private appRef: ApplicationRef,
Expand All @@ -76,12 +78,18 @@ export class ChangePasswordComponent implements OnInit {
this.warning = data.warning;
}

/**
*
*/
ngOnInit() {
if (this.warning) {
this.message = this.msgChangeTempPw;
}
}

/**
*
*/
onPasswordChangeClick(fReg: NgForm): void {
if (this.cpwd.newPassword !== this.cpwd.confirmPassword) {
return;
Expand All @@ -90,11 +98,12 @@ export class ChangePasswordComponent implements OnInit {
this.auth.changePassword(this.cpwd).subscribe(
(response: any) => {
this.passwordResponse = JSON.parse(response);

if (this.passwordResponse.isValid) {
this.dialogRef.close(true);
} else {
this.warning = true;
this.message = this.passwordResponse.message;
this.message = this.tSvc.translate('change password.' + this.passwordResponse.message);
this.ref.detectChanges();
}
},
Expand All @@ -105,6 +114,9 @@ export class ChangePasswordComponent implements OnInit {
});
}

/**
*
*/
checkPassword(event) {
var temp: ChangePassword = {
newPassword: event ?? '',
Expand All @@ -125,6 +137,9 @@ export class ChangePasswordComponent implements OnInit {
});
}

/**
*
*/
cancel() {
this.dialogRef.close();

Expand All @@ -135,6 +150,9 @@ export class ChangePasswordComponent implements OnInit {
}
}

/**
*
*/
togglePasswordVisibility() {
this.showPassword = !this.showPassword;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { filter } from 'rxjs/operators';
import { AuthenticationService } from '../../services/authentication.service';
import { ChangePasswordComponent } from "../../dialogs/change-password/change-password.component";
import { AlertComponent } from '../../dialogs/alert/alert.component';
import { TranslocoService } from '@ngneat/transloco';


@Component({
Expand All @@ -46,6 +47,7 @@ export class LandingPageTabsComponent implements OnInit, AfterViewInit {
constructor(
private route: ActivatedRoute,
private router: Router,
private tSvc: TranslocoService,
public authSvc: AuthenticationService,
public dialog: MatDialog
) { }
Expand Down Expand Up @@ -133,8 +135,8 @@ export class LandingPageTabsComponent implements OnInit, AfterViewInit {
if (passwordChangeSuccess) {
this.dialog.open(AlertComponent, {
data: {
messageText: 'Your password has been changed successfully.',
title: 'Password Changed',
messageText: this.tSvc.translate('change password.changed message'),
title: this.tSvc.translate('change password.changed dialog title'),
iconClass: 'cset-icons-check-circle'
}
});
Expand Down
26 changes: 25 additions & 1 deletion CSETWebNg/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@
"questions mode": "Questions Mode",
"requirements mode": "Requirements Mode",
"add document": "Add a document",
"copy text": "Copy Texzt"
"copy text": "Copy Text",
"change password": "Change Password"
},
"contact": {
"contacts": "Contacts",
Expand Down Expand Up @@ -784,6 +785,29 @@
"not valid email": "Not a valid email",
"emails do not match": "Emails do not match"
},
"change password": {
"dialog title": "Change Password",
"current password": "Current Password",
"show passwords": "Show Passwords",
"hide passwords": "Hide Passwords",
"new password": "New Password",
"confirm new password": "Confirm New Password",
"passwords do not match": "Passwords do not match",
"new and confirmation required": "New Password and Confirmation are required",
"change temp on logon": "Temporary password must be changed on first logon",
"current invalid": "Current password is invalid.<br>Correct it or request a new temporary password.",
"rules not satisfied": "New password does not satisfy all password policy requirements.",
"rules": {
"length between": "Length between {{lengthMin}} and {{lengthMax}} characters",
"required numbers": "Must contain at least 2 numbers",
"required lowercase": "Must contain at least 1 lowercase character",
"required uppercase": "Must contain at least 1 uppercase character",
"required special": "Must contain at least 1 special character",
"previous count": "Must not re-use previous {{count}} passwords"
},
"changed dialog title": "Password Changed",
"changed message": "Your password has been changed successfully"
},
"about": {
"about": "About",
"version": "Version",
Expand Down
26 changes: 25 additions & 1 deletion CSETWebNg/src/assets/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@
"questions mode": "Modo preguntas",
"requirements mode": "Modo requisitos",
"add document": "Agregar documento",
"copy text": "Copiar texto"
"copy text": "Copiar texto",
"change password": "Cambiar la contraseña"
},
"answer-options": {
"button-labels": {
Expand Down Expand Up @@ -782,6 +783,29 @@
"not valid email": "Email no es válido",
"emails do not match": "Los correos electrónicos no coinciden"
},
"change password": {
"dialog title": "Cambiar la contraseña",
"current password": "Contraseña actual",
"show passwords": "Mostrar contraseñas",
"hide passwords": "Ocultar contraseñas",
"new password": "Nueva contraseña",
"confirm new password": "Confirmar nueva contraseña",
"passwords do not match": "Las contraseñas no coinciden",
"new and confirmation required": "Se requiere nueva contraseña y confirmación",
"change temp on logon": "La contraseña temporal debe cambiarse en el primer inicio de sesión",
"current invalid": "La contraseña actual no es válida.<br>Corríjala o solicite una nueva contraseña temporal.",
"rules not satisfied": "La nueva contraseña no cumple con todos los requisitos de la política de contraseñas.",
"rules": {
"length between": "Longitud entre {{lengthMin}} y {{lengthMax}} caracteres",
"required numbers": "Debe contener al menos 2 números",
"required lowercase": "Debe contener al menos 1 carácter en minúscula",
"required uppercase": "Debe contener al menos 1 carácter en mayúscula",
"required special": "Debe contener al menos 1 carácter especial",
"previous count": "No se deben reutilizar {{count}} contraseñas anteriores"
},
"changed dialog title": "contraseña Cambiada",
"changed message": "tu contraseña ha sido cambiada exitosamente"
},
"about": {
"about": "Sobre",
"version": "Versión",
Expand Down
Loading
Loading