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

user: password validator #915

Merged
merged 1 commit into from
Feb 6, 2023
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
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"easymde": "^2.18.0",
"font-awesome": "^4.7.0",
"issn": "^1.0.6",
"js-generate-password": "^0.1.7",
"lodash-es": "^4.17.21",
"luxon": "^3.1.1",
"marked": "^4.1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ <h4 id="dialog-sizes-name2" class="modal-title pull-left" translate>Personal inf
(search)="searchValueUpdated($event)" class="form-inline mr-3" [focus]="false" [displayLabel]="false">
</ng-core-search-input>
</form>
<button type="button" id="editor-delete-button" class="btn btn-outline-danger btn-sm mr-1"
<button type="button" id="user-editor-delete-button" class="btn btn-outline-danger btn-sm mr-1"
Garfield-fr marked this conversation as resolved.
Show resolved Hide resolved
(click)="bsModalRef.hide()">
<i class="fa fa-times"></i>
{{ 'Cancel' | translate }}
</button>
<button type="submit" id="editor-save-button" class="btn btn-primary btn-sm">
<button type="submit" id="user-editor-save-button" class="btn btn-primary btn-sm">
<i class="fa fa-save"></i>
{{ 'Save' | translate }}
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

import { Component, OnInit } from '@angular/core';
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { FormlyFieldConfig } from '@ngx-formly/core';
import { FormlyJsonschema } from '@ngx-formly/core/json-schema';
import { TranslateService } from '@ngx-translate/core';
Expand Down Expand Up @@ -54,6 +54,9 @@ export class UserIdEditorComponent implements OnInit {
/** Formly fields configuration populate by the JSONSchema */
fields: FormlyFieldConfig[];

/** Password field */
passwordField: FormlyFieldConfig;

/**
* Constructor
*
Expand Down Expand Up @@ -106,6 +109,12 @@ export class UserIdEditorComponent implements OnInit {
}
field.asyncValidators.uniqueUsername = this.getUniqueValidator('username');
}
if (field.key === 'password') {
if (!this.userID) {
field.templateOptions.required = true;
}
this.passwordField = field;
}
// remove Message suffix to the message validation key
// (required for backend translations)
if (field.validation) {
Expand Down Expand Up @@ -142,6 +151,7 @@ export class UserIdEditorComponent implements OnInit {
searchValueUpdated(query: (string | null)): void {
if (!query) {
this.loadedUserID = null;
this.passwordField.templateOptions.required = true;
this.form.reset();
this.model = {};
return;
Expand Down Expand Up @@ -179,6 +189,7 @@ export class UserIdEditorComponent implements OnInit {
this._translateService.instant('The personal data has been successfully linked to this patron.')
);
this.loadedUserID = model.id;
this.passwordField.templateOptions.required = false;
this.form.reset();
return this.model = model.metadata ? model.metadata : null;
}),
Expand Down
13 changes: 12 additions & 1 deletion projects/public-search/src/app/api/user-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ApiService } from '@rero/ng-core';
import { Observable } from 'rxjs';

@Injectable({
Expand All @@ -27,7 +28,10 @@ export class UserApiService {
* Constructor
* @param _httpClient - HttpClient
*/
constructor(private _httpClient: HttpClient) { }
constructor(
private _httpClient: HttpClient,
private _apiService: ApiService
) { }

/**
* Update password
Expand All @@ -37,6 +41,13 @@ export class UserApiService {
updatePassword(data: IPassword): Observable<any> {
return this._httpClient.post('/api/change-password', data);
}

validatePassword(password: string): Observable<any> {
return this._httpClient.post(
this._apiService.getEndpointByType('user/password/validate'),
{ 'password': password }
);
}
}

interface IPassword {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* RERO ILS UI
* Copyright (C) 2022 RERO
* Copyright (C) 2022-2023 RERO
Garfield-fr marked this conversation as resolved.
Show resolved Hide resolved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -16,14 +16,14 @@
*/
import { DOCUMENT } from '@angular/common';
import { Component, ElementRef, Inject, Input } from '@angular/core';
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FormlyFieldConfig } from '@ngx-formly/core';
import { TranslateService } from '@ngx-translate/core';
import { AppSettingsService } from '@rero/shared';
import { ToastrService } from 'ngx-toastr';
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { catchError, debounceTime, map } from 'rxjs/operators';
import { UserApiService } from '../../api/user-api.service';

export function fieldPasswordMatchValidator(control: AbstractControl) {
Expand Down Expand Up @@ -81,9 +81,12 @@ export class PatronProfilePasswordComponent {
type: 'password',
label: 'New password',
required: true,
minLength: 6,
minLength: 8,
Garfield-fr marked this conversation as resolved.
Show resolved Hide resolved
maxLength: 128
},
asyncValidators: {
'validatePassword': this.validatePassword()
}
},
{
key: 'confirmPassword',
Expand All @@ -92,7 +95,7 @@ export class PatronProfilePasswordComponent {
type: 'password',
label: 'Confirm new password',
required: true,
minLength: 6,
minLength: 8,
maxLength: 128,
}
}
Expand All @@ -106,6 +109,9 @@ export class PatronProfilePasswordComponent {
new_password_confirm: 'confirmPassword'
};

/** Error message for password validator */
private _validatePasswordMessage: string = '';

/**
* Constructor
*
Expand Down Expand Up @@ -159,6 +165,27 @@ export class PatronProfilePasswordComponent {
});
}

/** Async validator for the password validator */
validatePassword(): any {
return {
expression: (control: UntypedFormControl) => {
const value = control.value;
if (value == null || value.length === 0) {
return of(true);
}
return this._userApiService.validatePassword(value).pipe(
debounceTime(500),
map(() => of(true)),
catchError((response) => {
this._validatePasswordMessage = response.error.message;
return of(false);
})
);
},
message: () => this._translateService.instant(this._validatePasswordMessage)
};
}

/** Cancel action on form */
cancel(): void {
this._redirect();
Expand Down