2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 import {environment} from "../../../../environments/environment";
20 import {ErrorResult} from "../../../model/error-result";
21 import {UserInfo} from "../../../model/user-info";
30 } from "@angular/forms";
31 import {User} from "../../../model/user";
32 import {of, timer} from "rxjs";
33 import {catchError, map, switchMap} from "rxjs/operators";
34 import { UserService } from 'src/app/services/user.service';
36 export class ManageUsersBaseComponent {
38 editProperties = ['user_id', 'full_name', 'email', 'locked', 'password_change_required',
39 'password', 'confirm_password', 'validated'];
40 minUserIdSize = environment.application.minUserIdLength;
41 success: boolean = false;
42 error: boolean = false;
43 errorResult: ErrorResult;
48 userForm = this.fb.group({
49 user_id: ['', [Validators.required, Validators.minLength(this.minUserIdSize), whitespaceValidator()], this.userUidExistsValidator()],
50 full_name: ['', Validators.required],
51 email: ['', [Validators.required, Validators.email]],
53 password_change_required: [true],
55 confirm_password: [''],
58 validator: MustMatch('password', 'confirm_password')
61 constructor(public userService: UserService, public fb: FormBuilder) {
62 this.formInitialValues=this.userForm.value
66 public copyFromForm(properties: string[]): User {
67 let user: any = new User();
68 for (let prop of properties) {
69 user[prop] = this.userForm.get(prop).value;
71 console.log("User " + user);
75 public copyToForm(properties: string[], user: User): void {
77 for (let prop of properties) {
78 let propValue = user[prop] == null ? '' : user[prop];
79 propMap[prop] = propValue;
81 this.userForm.patchValue(propMap);
82 console.log("User " + user);
86 valid(field: string): string[] {
87 let formField = this.userForm.get(field);
88 if (formField.dirty || formField.touched) {
89 if (formField.valid) {
100 * Async validator with debounce time
103 userUidExistsValidator() {
105 return (ctrl: FormControl) => {
106 // debounceTimer() does not work here, as the observable is created with each keystroke
107 // but angular does unsubscribe on previous started async observables.
108 return timer(500).pipe(
109 switchMap((userid) => this.userService.userExists(ctrl.value)),
110 catchError(() => of(null)),
111 map(exists => (exists ? {userexists: true} : null))
116 forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
117 return (control: AbstractControl): { [key: string]: any } | null => {
118 const forbidden = nameRe.test(control.value);
119 return forbidden ? {forbiddenName: {value: control.value}} : null;
123 getAllErrors(formGroup: FormGroup, errors: string[] = []) : string[] {
124 Object.keys(formGroup.controls).forEach(field => {
125 const control = formGroup.get(field);
126 if (control instanceof FormControl && control.errors != null) {
127 let keys = Object.keys(control.errors).map(errorKey=>field+'.'+errorKey);
128 errors = errors.concat(keys);
129 } else if (control instanceof FormGroup) {
130 errors = errors.concat(this.getAllErrors(control));
136 getAttributeErrors(control:string):string[] {
137 return Object.keys(this.userForm.get(control).errors);
141 export function whitespaceValidator(): ValidatorFn {
142 return (control: AbstractControl): ValidationErrors | null => {
143 const hasWhitespace = /\s/g.test(control.value);
144 return hasWhitespace ? {containsWhitespace: {value: control.value}} : null;
147 export function MustMatch(controlName: string, matchingControlName: string) : ValidatorFn {
148 return (formGroup: FormGroup): ValidationErrors | null => {
149 const control = formGroup.controls[controlName];
150 const matchingControl = formGroup.controls[matchingControlName];
152 if (matchingControl.errors && !matchingControl.errors.mustMatch) {
153 // return if another validator has already found an error on the matchingControl
157 // set error on matchingControl if validation fails
158 if (control.value !== matchingControl.value) {
159 matchingControl.setErrors({mustMatch: true});
161 matchingControl.setErrors(null);