Strongest password policy

This commit is contained in:
Jose Alberto Hernandez
2024-05-06 21:09:31 -06:00
committed by Jose Alberto Hernandez
parent 9b17a6c4f8
commit 8fdf8fb10c
35 changed files with 283 additions and 79 deletions
@@ -45,7 +45,7 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
/** Selected GL Account. */
glAccount: GLAccountNode;
/** Flag to check if tree is expanded or collapsed. */
isTreeExpanded: boolean = true;
isTreeExpanded = true;
/** Paginator for chart of accounts table. */
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@@ -182,9 +182,9 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
this.router.navigate(['/accounting']);
}
/**
/**
* Expand and Collapse the tree
*/
*/
toggleExpandCollapse() {
this.isTreeExpanded = this.treeControlService.toggleExpandCollapse(this.nestedTreeControl, this.isTreeExpanded);
}
@@ -12,7 +12,8 @@
<mat-label> {{"labels.inputs.User Name" | translate}} </mat-label>
<input matInput required formControlName="username">
<mat-error *ngIf="createSelfServiceForm.controls.username.hasError('required')">
{{"labels.inputs.User Name" | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
{{"labels.inputs.User Name" | translate}} {{"labels.commons.is" | translate}}
<strong>{{"labels.commons.required" | translate}}</strong>
</mat-error>
</mat-form-field>
@@ -20,7 +21,8 @@
<mat-label> {{"labels.inputs.First Name" | translate}} </mat-label>
<input matInput required formControlName="firstname">
<mat-error *ngIf="createSelfServiceForm.controls.firstname.hasError('required')">
{{"labels.inputs.First Name" | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
{{"labels.inputs.First Name" | translate}} {{"labels.commons.is" | translate}}
<strong>{{"labels.commons.required" | translate}}</strong>
</mat-error>
</mat-form-field>
@@ -28,7 +30,8 @@
<mat-label> {{"labels.inputs.Last Name" | translate}} </mat-label>
<input matInput required formControlName="lastname">
<mat-error *ngIf="createSelfServiceForm.controls.lastname.hasError('required')">
{{"labels.inputs.Last Name" | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
{{"labels.inputs.Last Name" | translate}} {{"labels.commons.is" | translate}}
<strong>{{"labels.commons.required" | translate}}</strong>
</mat-error>
</mat-form-field>
@@ -36,10 +39,12 @@
<mat-label> {{"labels.inputs.Email" | translate}} </mat-label>
<input matInput required formControlName="email">
<mat-error *ngIf="createSelfServiceForm.controls.email.hasError('required')">
{{"labels.inputs.Email" | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
{{"labels.inputs.Email" | translate}} {{"labels.commons.is" | translate}}
<strong>{{"labels.commons.required" | translate}}</strong>
</mat-error>
<mat-error *ngIf="createSelfServiceForm.controls.email.hasError('email')">
{{"labels.inputs.Email should be a" | translate}} <strong>{{"labels.inputs.valid" | translate}}</strong> {{"labels.inputs.email" | translate}}.
{{"labels.inputs.Email should be a" | translate}} <strong>{{"labels.inputs.valid" |
translate}}</strong> {{"labels.inputs.email" | translate}}.
</mat-error>
</mat-form-field>
@@ -53,15 +58,30 @@
{{"labels.inputs.Override Password Expire Policy" | translate}} ?
</mat-checkbox>
<i class="fa fa-question-circle fa fa-align-left" title="Determines if passwords do not expire for this user even if global configuration for password expiry is enabled"></i>
<i class="fa fa-question-circle fa fa-align-left"
title="Determines if passwords do not expire for this user even if global configuration for password expiry is enabled"></i>
</div>
<mat-form-field fxFlex="48%" *ngIf="!hidePasswordField">
<mat-label> {{"labels.inputs.Password" | translate}} </mat-label>
<input matInput required formControlName="password" type="password">
<mat-label>{{ 'labels.inputs.Password' | translate }}</mat-label>
<input matInput formControlName="password" type="password">
<mat-error *ngIf="createSelfServiceForm.controls.password.hasError('required')">
{{"labels.inputs.Password" | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
{{ 'labels.inputs.Password' | translate }} <strong>{{'labels.commons.is required' | translate }}</strong>
</mat-error>
<mat-error *ngIf="createSelfServiceForm.controls.password.hasError('minlength')">
{{'labels.commons.Password should be at least' | translate }} <strong>{{'labels.commons.8 characters long' | translate }}</strong>
</mat-error>
<mat-error *ngIf="createSelfServiceForm.controls.password.hasError('maxlength')">
{{'labels.commons.Password should not be more than' | translate }}
<strong>{{'labels.commons.50 characters long' | translate }}</strong>
</mat-error>
<mat-error
*ngIf="createSelfServiceForm.controls.password.hasError('pattern') && !(createSelfServiceForm.controls.password.hasError('minlength') || createSelfServiceForm.controls.password.hasError('maxlength'))">
{{'labels.commons.Password should include a' | translate }}
<strong>{{'labels.commons.numeral' | translate }}</strong> {{'labels.commons.and at' | translate }}
<strong>{{'labels.commons.least one uppercase' | translate }}</strong>
,<strong>{{'labels.commons.lowercase and special character' | translate }}</strong>
</mat-error>
</mat-form-field>
@@ -69,10 +89,12 @@
<mat-label> {{"labels.inputs.Repeat Password" | translate}} </mat-label>
<input matInput required formControlName="repeatPassword" type="password">
<mat-error *ngIf="createSelfServiceForm.controls.repeatPassword.hasError('required')">
{{"labels.inputs.Repeat password" | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
{{"labels.inputs.Repeat password" | translate}} {{"labels.commons.is" | translate}}
<strong>{{"labels.commons.required" | translate}}</strong>
</mat-error>
<mat-error *ngIf="createSelfServiceForm.controls.repeatPassword.hasError('notequal')">
{{"labels.inputs.Passwords should be" | translate}} <strong>{{"labels.inputs.matched" | translate}}</strong>
{{"labels.inputs.Passwords should be" | translate}} <strong>{{"labels.inputs.matched" |
translate}}</strong>
</mat-error>
</mat-form-field>
@@ -84,9 +106,12 @@
</div>
<mat-card-actions fxLayoutGap="5px" fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center">
<button type="button" mat-raised-button [routerLink]="['../../']">{{"labels.buttons.Cancel" | translate}}</button>
<button mat-raised-button color="primary" [disabled]="!createSelfServiceForm.valid">{{"labels.buttons.Activate Self Service User" | translate}}</button>
<i class="fa fa-question-circle fa-2x" title="Activate Self Service User Help"></i>
<button type="button" mat-raised-button [routerLink]="['../../']">{{"labels.buttons.Cancel" |
translate}}</button>
<button mat-raised-button color="primary"
[disabled]="!createSelfServiceForm.valid">{{"labels.buttons.Activate Self Service User" |
translate}}</button>
<i class="fa fa-question-circle fa-2x" title="Activate Self Service User Help"></i>
</mat-card-actions>
</mat-card-content>
@@ -95,4 +120,4 @@
</mat-card>
</div>
</div>
@@ -6,6 +6,7 @@ import { Subscription } from 'rxjs';
/** Client Services. */
import { ClientsService } from 'app/clients/clients.service';
import { PasswordsUtility } from 'app/core/utils/passwords-utility';
@Component({
selector: 'mifosx-create-self-service-user',
@@ -21,7 +22,8 @@ export class CreateSelfServiceUserComponent implements OnInit {
constructor(private formBuilder: UntypedFormBuilder,
private route: ActivatedRoute,
private clientService: ClientsService,
private router: Router) {
private router: Router,
private passwordsUtility: PasswordsUtility) {
this.route.data.subscribe((data: { clientActionData: any}) => {
this.clientData = data.clientActionData;
});
@@ -43,8 +45,8 @@ export class CreateSelfServiceUserComponent implements OnInit {
this.createSelfServiceForm.removeControl('repeatPassword');
} else {
this.hidePasswordField = false;
this.createSelfServiceForm.addControl('password', new UntypedFormControl('', [Validators.required]));
this.createSelfServiceForm.addControl('repeatPassword', new UntypedFormControl('', [Validators.required, this.confirmPassword('password')]));
this.createSelfServiceForm.addControl('password', new UntypedFormControl('', this.passwordsUtility.getPasswordValidators()));
this.createSelfServiceForm.addControl('repeatPassword', new UntypedFormControl('', [Validators.required, this.passwordsUtility.confirmPassword('password')]));
}
});
}
@@ -83,24 +85,4 @@ export class CreateSelfServiceUserComponent implements OnInit {
});
}
/**
* Confirm Change Password of Users
* @param controlNameToCompare Form Control Name to be compared.
*/
confirmPassword(controlNameToCompare: string): ValidatorFn {
return (c: AbstractControl): ValidationErrors|null => {
if (c.value == null || c.value.length === 0) {
return null;
}
const controlToCompare = c.root.get(controlNameToCompare);
if (controlToCompare) {
const subscription: Subscription = controlToCompare.valueChanges.subscribe(() => {
c.updateValueAndValidity();
subscription.unsubscribe();
});
}
return controlToCompare && controlToCompare.value !== c.value ? {'notequal': true} : null;
};
}
}
@@ -121,7 +121,9 @@
<ng-container matColumnDef="Loan Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Loan Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Original Loan">
@@ -195,7 +197,9 @@
<ng-container matColumnDef="Loan Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Loan Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Original Loan">
@@ -260,7 +264,9 @@
<ng-container matColumnDef="Saving Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Savings Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Last Active">
@@ -320,7 +326,9 @@
<ng-container matColumnDef="Saving Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Saving Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Closed Date">
@@ -415,7 +423,9 @@
<ng-container matColumnDef="Saving Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Fixed Deposit Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Closed Date">
@@ -458,7 +468,9 @@
<ng-container matColumnDef="Saving Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Recurring Deposit Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Last Active">
@@ -515,7 +527,9 @@
<ng-container matColumnDef="Saving Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Recurring Deposit Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Closed Date">
@@ -556,7 +570,9 @@
<ng-container matColumnDef="Share Account">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Share Product" | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.productName}} </td>
<td mat-cell *matCellDef="let element">
<mifosx-long-text textValue="{{element.productName}}" chars="35"></mifosx-long-text>
</td>
</ng-container>
<ng-container matColumnDef="Approved Shares">
+37
View File
@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
import { Subscription } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class PasswordsUtility {
// password regex pattern
public static PASSWORD_REGEX = '^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*[#$@$!%*?&])[A-Za-z\d#$@$!%*?&].{8,}$';
public getPasswordValidators(): ValidatorFn[] {
return [Validators.required, Validators.pattern(PasswordsUtility.PASSWORD_REGEX), Validators.maxLength(50), Validators.minLength(8)];
}
/**
* Confirm Change Password of Users
* @param controlNameToCompare Form Control Name to be compared.
*/
public confirmPassword(controlNameToCompare: string): ValidatorFn {
return (c: AbstractControl): ValidationErrors|null => {
if (c.value == null || c.value.length === 0) {
return null;
}
const controlToCompare = c.root.get(controlNameToCompare);
if (controlToCompare) {
const subscription: Subscription = controlToCompare.valueChanges.subscribe(() => {
c.updateValueAndValidity();
subscription.unsubscribe();
});
}
return controlToCompare && controlToCompare.value !== c.value ? {'notequal': true} : null;
};
}
}
@@ -20,8 +20,9 @@
<h3>
<i class="fa fa-stop" matTooltip="{{'labels.status.' + loanDetailsData.status.value | translate}}"
[ngClass]="loanDetailsData.inArrears?'status-active-overdue':( iconLoanStatusColor() | statusLookup)"></i>
<span class="m-r-10">{{'labels.heading.Loan Product' | translate}}:</span> {{loanDetailsData.loanProductName}}
<mifosx-account-number accountNo="{{loanDetailsData.accountNo}}"></mifosx-account-number>
<span class="m-r-5">{{'labels.heading.Loan Product' | translate}} :</span>
<span class="m-r-5"><mifosx-long-text textValue="{{loanDetailsData.loanProductName}}"></mifosx-long-text></span>
<mifosx-account-number accountNo="{{loanDetailsData.accountNo}}" display="left"></mifosx-account-number>
</h3>
<span class="loans-overview">
<span class="m-r-10">{{'labels.text.' + entityType | translate}} {{"labels.inputs.name" | translate}} :</span> {{loanDetailsData.clientName ||
@@ -26,8 +26,17 @@
</span>
<mat-label>{{'labels.inputs.Confirm Password' | translate}}</mat-label>
<input type="password" matInput required formControlName="repeatPassword">
<mat-error *ngIf="resetPasswordForm.controls.repeatPassword.hasError('required')">
{{'labels.inputs.Confirm Password' | translate}} <strong>{{'labels.commons.is required' | translate}}</strong>
<mat-error *ngIf="resetPasswordForm.controls.password.hasError('required')">
{{ 'labels.inputs.Password' | translate }} <strong>{{'labels.commons.is required' | translate }}</strong>
</mat-error>
<mat-error *ngIf="resetPasswordForm.controls.password.hasError('minlength')">
{{'labels.commons.Password should be at least' | translate }} <strong>{{'labels.commons.8 characters long' | translate }}</strong>
</mat-error>
<mat-error *ngIf="resetPasswordForm.controls.password.hasError('maxlength')">
{{'labels.commons.Password should not be more than' | translate }} <strong>{{'labels.commons.50 characters long' | translate }}</strong>
</mat-error>
<mat-error *ngIf="resetPasswordForm.controls.password.hasError('pattern') && !(resetPasswordForm.controls.password.hasError('minlength') || resetPasswordForm.controls.password.hasError('maxlength'))">
{{'labels.commons.Password should include a' | translate }} <strong>{{'labels.commons.numeral' | translate }}</strong> {{'labels.commons.and at' | translate }} <strong>{{'labels.commons.least one uppercase' | translate }}</strong> ,<strong>{{'labels.commons.lowercase and special character' | translate }}</strong>
</mat-error>
</mat-form-field>
@@ -10,6 +10,7 @@ import { AuthenticationService } from '../../core/authentication/authentication.
/** Custom Validators */
import { confirmPasswordValidator } from './confirm-password.validator';
import { PasswordsUtility } from 'app/core/utils/passwords-utility';
/**
* Reset password component.
@@ -33,7 +34,8 @@ export class ResetPasswordComponent implements OnInit {
* @param {AuthenticationService} authenticationService Authentication Service.
*/
constructor(private formBuilder: UntypedFormBuilder,
private authenticationService: AuthenticationService) { }
private authenticationService: AuthenticationService,
private passwordsUtility: PasswordsUtility) { }
/**
* Creates reset password form.
@@ -66,7 +68,7 @@ export class ResetPasswordComponent implements OnInit {
*/
private createResetPasswordForm() {
this.resetPasswordForm = this.formBuilder.group({
'password': ['', Validators.required],
'password': ['', this.passwordsUtility.getPasswordValidators()],
'repeatPassword': ['', Validators.required]
}, { validator: confirmPasswordValidator });
}
@@ -45,7 +45,7 @@ export class OfficesComponent implements OnInit, AfterViewInit {
/** Office data tables. */
dataTablesData: any;
/** Flag to check if tree is expanded or collapsed. */
isTreeExpanded: boolean = true;
isTreeExpanded = true;
/** Paginator for offices table. */
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@@ -190,9 +190,9 @@ export class OfficesComponent implements OnInit, AfterViewInit {
this.router.navigate(['/organization']);
}
/**
/**
* Expand and Collapse the tree
*/
*/
toggleExpandCollapse() {
this.isTreeExpanded = this.treeControlService.toggleExpandCollapse(this.nestedTreeControl, this.isTreeExpanded);
}
+7 -3
View File
@@ -13,6 +13,7 @@ import { FormatNumberPipe } from './format-number.pipe';
import { YesnoPipe } from './yesno.pipe';
import { PrettyPrintPipe } from './pretty-print.pipe';
import { TranslateCatalogPipe } from './translate-catalog.pipe';
import { TruncateTextPipe } from './truncate-text.pipe';
@NgModule({
imports: [
@@ -30,7 +31,8 @@ import { TranslateCatalogPipe } from './translate-catalog.pipe';
FormatNumberPipe,
YesnoPipe,
PrettyPrintPipe,
TranslateCatalogPipe],
TranslateCatalogPipe,
TruncateTextPipe],
providers: [StatusLookupPipe,
AccountsFilterPipe,
ChargesFilterPipe,
@@ -43,7 +45,8 @@ import { TranslateCatalogPipe } from './translate-catalog.pipe';
FormatNumberPipe,
YesnoPipe,
PrettyPrintPipe,
TranslateCatalogPipe],
TranslateCatalogPipe,
TruncateTextPipe],
exports: [StatusLookupPipe,
AccountsFilterPipe,
ChargesFilterPipe,
@@ -56,6 +59,7 @@ import { TranslateCatalogPipe } from './translate-catalog.pipe';
FormatNumberPipe,
YesnoPipe,
PrettyPrintPipe,
TranslateCatalogPipe]
TranslateCatalogPipe,
TruncateTextPipe]
})
export class PipesModule { }
+21
View File
@@ -0,0 +1,21 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncateText'
})
export class TruncateTextPipe implements PipeTransform {
transform(value: string, chars: number): string {
if (value.length <= 40) {
return value;
}
let truncatedText = value.substring(0, 30);
if (chars) {
truncatedText = value.substring(0, chars);
}
return truncatedText;
}
}
@@ -34,7 +34,7 @@
<mat-label>{{'labels.inputs.Debit Account Type' | translate}}</mat-label>
<mat-select formControlName="debitAccountType">
<mat-option *ngFor="let debitAccountType of debitAccountTypeData" [value]="debitAccountType.id">
{{ 'labels.inputs.accounting.' + debitAccountType.value | translate }}
{{ debitAccountType.value | translateCatalog }}
</mat-option>
</mat-select>
</mat-form-field>
@@ -48,7 +48,7 @@
<mat-label>{{'labels.inputs.Credit Account Type' | translate}}</mat-label>
<mat-select formControlName="creditAccountType">
<mat-option *ngFor="let creditAccountType of creditAccountTypeData" [value]="creditAccountType.id">
{{ 'labels.inputs.accounting.' + creditAccountType.value | translate }}
{{ creditAccountType.value | translateCatalog }}
</mat-option>
</mat-select>
</mat-form-field>
@@ -50,7 +50,7 @@
</div>
<div fxFlex="50%" *ngIf="taxComponentData.creditAccountType">
{{ 'labels.inputs.accounting.' + taxComponentData.creditAccountType.value | translate }}
{{ taxComponentData.creditAccountType.value | translateCatalog }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="taxComponentData.creditAccount">
@@ -19,8 +19,9 @@
[matTooltip]="savingsAccountData.status.value" *ngIf="!savingsAccountData.subStatus.block"></i>
<i class="fa fa-stop" [ngClass]="savingsAccountData.subStatus.value | statusLookup"
[matTooltip]="savingsAccountData.subStatus.value" *ngIf="savingsAccountData.subStatus.block"></i>
{{'labels.inputs.Savings Product' | translate}} : {{savingsAccountData.savingsProductName}}<span class="m-l-10">
<mifosx-account-number accountNo="{{savingsAccountData.accountNo}}"></mifosx-account-number></span>
<span class="m-r-5">{{'labels.inputs.Savings Product' | translate}} :</span>
<span class="m-r-5"><mifosx-long-text textValue="{{savingsAccountData.savingsProductName}}"></mifosx-long-text></span>
<mifosx-account-number accountNo="{{savingsAccountData.accountNo}}" display="left"></mifosx-account-number>
</h3>
<span class="account-overview">
{{'labels.text.' + entityType | translate}} {{"labels.inputs.name" | translate}}: {{savingsAccountData.clientName ||
@@ -51,6 +51,9 @@ export class SearchPageComponent {
case 'CLIENT':
this.router.navigate(['clients', entity.entityId, 'general']);
break;
case 'CLIENTIDENTIFIER':
this.router.navigate(['clients', entity.parentId, 'general']);
break;
case 'CENTER':
this.router.navigate(['centers', entity.entityId]);
break;
@@ -3,6 +3,7 @@ import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { UntypedFormBuilder, Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
import { Subscription } from 'rxjs';
import { PasswordsUtility } from 'app/core/utils/passwords-utility';
/**
* Change Password Dialog component.
@@ -23,7 +24,8 @@ export class ChangePasswordDialogComponent implements OnInit {
*/
constructor(public dialogRef: MatDialogRef<ChangePasswordDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formBuilder: UntypedFormBuilder) { }
private formBuilder: UntypedFormBuilder,
private passwordsUtility: PasswordsUtility) { }
ngOnInit() {
this.createChangePasswordForm();
@@ -32,7 +34,7 @@ export class ChangePasswordDialogComponent implements OnInit {
/** Change Password form */
createChangePasswordForm() {
this.changePasswordForm = this.formBuilder.group({
'password': ['', [Validators.required, Validators.pattern('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*[#$@$!%*?&])[A-Za-z\d#$@$!%*?&].{8,}$'), Validators.maxLength(50), Validators.minLength(8)]],
'password': ['', this.passwordsUtility.getPasswordValidators()],
'repeatPassword': ['', [Validators.required, this.confirmPassword('password')]]
});
}
@@ -0,0 +1,5 @@
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()" *ngIf="!emptyValue">
<span class="m-l-3" *ngIf="isLongValue()"><fa-icon icon="eye" size="sm" [title]="textValue"></fa-icon></span>
<span class="m-l-5" *ngIf="isLongValue()">{{ textValue | truncateText:chars }}...</span>
<span class="m-l-5" *ngIf="!isLongValue()">{{ textValue }}</span>
</span>
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LongTextComponent } from './long-text.component';
describe('LongTextComponent', () => {
let component: LongTextComponent;
let fixture: ComponentFixture<LongTextComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LongTextComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(LongTextComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,37 @@
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'mifosx-long-text',
templateUrl: './long-text.component.html',
styleUrls: ['./long-text.component.scss']
})
export class LongTextComponent implements OnInit {
@Input() textValue: string;
@Input() chars = 30;
iconVisible = false;
displayL = false;
displayR = true;
emptyValue = false;
constructor() { }
ngOnInit(): void {
this.emptyValue = (!this.textValue || this.textValue === '');
}
isLongValue(): boolean {
if (this.textValue == null) {
return false;
}
return (this.textValue.length > 25);
}
mouseEnter() {
this.iconVisible = true;
}
mouseLeave() {
this.iconVisible = false;
}
}
+5 -2
View File
@@ -47,6 +47,7 @@ import { GlAccountSelectorComponent } from './accounting/gl-account-selector/gl-
import { GlAccountDisplayComponent } from './accounting/gl-account-display/gl-account-display.component';
import { ViewSavingsAccountingDetailsComponent } from './accounting/view-savings-accounting-details/view-savings-accounting-details.component';
import { ThemeToggleComponent } from './theme-toggle/theme-toggle.component';
import { LongTextComponent } from './long-text/long-text.component';
/**
* Shared Module
@@ -100,7 +101,8 @@ import { ThemeToggleComponent } from './theme-toggle/theme-toggle.component';
GlAccountSelectorComponent,
GlAccountDisplayComponent,
ViewSavingsAccountingDetailsComponent,
ThemeToggleComponent
ThemeToggleComponent,
LongTextComponent
],
exports: [
FileUploadComponent,
@@ -132,7 +134,8 @@ import { ThemeToggleComponent } from './theme-toggle/theme-toggle.component';
GlAccountSelectorComponent,
GlAccountDisplayComponent,
ViewSavingsAccountingDetailsComponent,
ThemeToggleComponent
ThemeToggleComponent,
LongTextComponent
]
})
export class SharedModule { }
@@ -67,6 +67,15 @@
<mat-error *ngIf="userForm.controls.password.hasError('required')">
{{'labels.inputs.Password' | translate}} {{"labels.commons.is" | translate}} <strong>{{"labels.commons.required" | translate}}</strong>
</mat-error>
<mat-error *ngIf="userForm.controls.password.hasError('minlength')">
{{'labels.commons.Password should be at least' | translate }} <strong>{{'labels.commons.8 characters long' | translate }}</strong>
</mat-error>
<mat-error *ngIf="userForm.controls.password.hasError('maxlength')">
{{'labels.commons.Password should not be more than' | translate }} <strong>{{'labels.commons.50 characters long' | translate }}</strong>
</mat-error>
<mat-error *ngIf="userForm.controls.password.hasError('pattern') && !(userForm.controls.password.hasError('minlength') || userForm.controls.password.hasError('maxlength'))">
{{'labels.commons.Password should include a' | translate }} <strong>{{'labels.commons.numeral' | translate }}</strong> {{'labels.commons.and at' | translate }} <strong>{{'labels.commons.least one uppercase' | translate }}</strong> ,<strong>{{'labels.commons.lowercase and special character' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="!userForm.controls.sendPasswordToEmail.value">
@@ -79,7 +88,7 @@
<p fxFlex="98%" class="reset-password-error" *ngIf="userForm.errors?.passwordsDoNotMatch &&
(!userForm.controls.password.hasError('required') && !userForm.controls.repeatPassword.hasError('required'))">
{{'labels.inputs.Passwords' | translate}} <strong>{{"labels.commons.do not match' | translate}}</strong>
{{'labels.inputs.Passwords' | translate}} <strong>{{'labels.commons.do not match' | translate}}</strong>
</p>
<mat-form-field fxFlex="48%">
@@ -8,13 +8,12 @@ import { MatDialog } from '@angular/material/dialog';
/** Custom Services */
import { UsersService } from '../users.service';
import { PopoverService } from '../../configuration-wizard/popover/popover.service';
import { ConfigurationWizardService } from '../../configuration-wizard/configuration-wizard.service';
/** Custom Validators */
import { confirmPasswordValidator } from '../../login/reset-password/confirm-password.validator';
/** Custom Dialog Component */
import { ContinueSetupDialogComponent } from '../../configuration-wizard/continue-setup-dialog/continue-setup-dialog.component';
import { PasswordsUtility } from 'app/core/utils/passwords-utility';
import { confirmPasswordValidator } from 'app/login/reset-password/confirm-password.validator';
import { ConfigurationWizardService } from 'app/configuration-wizard/configuration-wizard.service';
import { ContinueSetupDialogComponent } from 'app/configuration-wizard/continue-setup-dialog/continue-setup-dialog.component';
/**
* Create user component.
@@ -55,7 +54,8 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
private router: Router,
private popoverService: PopoverService,
private configurationWizardService: ConfigurationWizardService,
public dialog: MatDialog) {
private dialog: MatDialog,
private passwordsUtility: PasswordsUtility) {
this.route.data.subscribe((data: {
usersTemplate: any
}) => {
@@ -112,8 +112,8 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
this.userForm.removeControl('repeatPassword');
this.userForm.get('email').setValidators([Validators.required, Validators.email]);
} else {
this.userForm.addControl('password', new UntypedFormControl('', Validators.required));
this.userForm.addControl('repeatPassword', new UntypedFormControl('', Validators.required));
this.userForm.addControl('password', new UntypedFormControl('', this.passwordsUtility.getPasswordValidators()));
this.userForm.addControl('repeatPassword', new UntypedFormControl('', [Validators.required, this.passwordsUtility.confirmPassword('password')]));
this.userForm.get('email').setValidators([Validators.email]);
}
this.userForm.get('email').updateValueAndValidity();
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "ČTVRTEK",
"FRIDAY": "PÁTEK",
"SATURDAY": "SOBOTA",
"Interest posting": "Zveřejnění zájmu",
"Amount on hold": "Částka na počkání",
"Invalid": "Neplatný"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "DONNERSTAG",
"FRIDAY": "FREITAG",
"SATURDAY": "SAMSTAG",
"Interest posting": "Zinsbuchung",
"Amount on hold": "Zurückgestellter Betrag",
"Invalid": "Ungültig"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "THURSDAY",
"FRIDAY": "FRIDAY",
"SATURDAY": "SATURDAY",
"Interest posting": "Interest posting",
"Amount on hold": "Amount on hold",
"Invalid": "Invalid"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "JUEVES",
"FRIDAY": "VIERNES",
"SATURDAY": "SÁBADO",
"Interest posting": "Intereses",
"Amount on hold": "Retención",
"Invalid": "Inválido"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "JEUDI",
"FRIDAY": "VENDREDI",
"SATURDAY": "SAMEDI",
"Interest posting": "Publication d'intérêt",
"Amount on hold": "Montant retenu",
"Invalid": "Invalide"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "GIOVEDÌ",
"FRIDAY": "VENERDÌ",
"SATURDAY": "SABATO",
"Interest posting": "Pubblicazione di interessi",
"Amount on hold": "Importo sospeso",
"Invalid": "Non valido"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "목요일",
"FRIDAY": "금요일",
"SATURDAY": "토요일",
"Interest posting": "관심 게시",
"Amount on hold": "보류 금액",
"Invalid": "유효하지 않은"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "KETVIRTADIENIS",
"FRIDAY": "PENKTADIENIS",
"SATURDAY": "ŠEŠTADIENIS",
"Interest posting": "Interesų skelbimas",
"Amount on hold": "Sulaikyta suma",
"Invalid": "Neteisinga"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "CETURTDIENA",
"FRIDAY": "PIEKTDIENA",
"SATURDAY": "SESTDIENA",
"Interest posting": "Interešu publicēšana",
"Amount on hold": "Aizturētā summa",
"Invalid": "Nederīgs"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "बिहीबार",
"FRIDAY": "शुक्रबार",
"SATURDAY": "शनिबार",
"Interest posting": "चासो पोस्टिंग",
"Amount on hold": "होल्डमा रहेको रकम",
"Invalid": "अवैध"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "QUINTA-FEIRA",
"FRIDAY": "SEXTA-FEIRA",
"SATURDAY": "SÁBADO",
"Interest posting": "Postagem de interesse",
"Amount on hold": "Valor retido",
"Invalid": "Inválido"
},
"commons": {
+2
View File
@@ -644,6 +644,8 @@
"THURSDAY": "ALHAMISI",
"FRIDAY": "IJUMAA",
"SATURDAY": "JUMAMOSI",
"Interest posting": "Nia ya kuchapisha",
"Amount on hold": "Kiasi kilichohifadhiwa",
"Invalid": "Batili"
},
"commons": {