TSK-666 - Fields connected to LDAP should allow values from LDAP only

This commit is contained in:
Jose Ignacio Recuerda Cambil 2018-08-09 14:53:00 +02:00 committed by Martin Rojas Miguel Angel
parent d6a29e7bdd
commit 06f5c436a9
10 changed files with 166 additions and 93 deletions

View File

@ -147,9 +147,11 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
onSubmit() {
this.formsValidatorService.formSubmitAttempt = true;
if (this.formsValidatorService.validate(this.classificationForm, this.toogleValidationMap)) {
this.onSave();
}
this.formsValidatorService.validateFormInformation(this.classificationForm, this.toogleValidationMap).then(value => {
if (value) {
this.onSave();
}
});
}
private initProperties() {

View File

@ -1,5 +1,5 @@
import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon';
@ -21,12 +21,13 @@ import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { AlertService } from 'app/services/alert/alert.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
describe('AccessItemsComponent', () => {
let component: AccessItemsComponent;
let fixture: ComponentFixture<AccessItemsComponent>;
let workbasketService, debugElement, alertService;
let workbasketService, debugElement, alertService, accessIdsService, formsValidatorService;
beforeEach(done => {
@ -35,8 +36,7 @@ describe('AccessItemsComponent', () => {
declarations: [AccessItemsComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule],
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService, RequestInProgressService,
CustomFieldsService]
CustomFieldsService, AccessIdsService, FormsValidatorService]
})
};
configureTests(configure).then(testBed => {
@ -56,7 +56,12 @@ describe('AccessItemsComponent', () => {
)));
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(of(true)),
spyOn(alertService, 'triggerAlert').and.returnValue(of(true)),
debugElement = fixture.debugElement.nativeElement;
debugElement = fixture.debugElement.nativeElement;
accessIdsService = TestBed.get(AccessIdsService);
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new Array<string>(
'accessID1', 'accessID2'
)));
formsValidatorService = TestBed.get(FormsValidatorService);
component.ngOnChanges({
active: new SimpleChange(undefined, 'accessItems', true)
});
@ -90,12 +95,18 @@ describe('AccessItemsComponent', () => {
expect(debugElement.querySelectorAll('#table-access-items > tbody > tr').length).toBe(1);
});
it('should show alert successfull after saving', () => {
component.onSubmit();
expect(alertService.triggerAlert).toHaveBeenCalledWith(
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
});
it('should show alert successfull after saving', async(() => {
fixture.detectChanges();
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalledWith(
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
})
fixture.detectChanges();
}));
it('should keep accessItemsClone length to previous value after clearing the form.', () => {
expect(component.accessItemsClone.length).toBe(2);

View File

@ -67,7 +67,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
AccessItemsFormGroups.map(accessItemGroup => {
accessItemGroup.controls['accessId'].setValidators(Validators.required);
accessItemGroup.controls['accessId'].setValidators(Validators.required);
});
const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormGroups);
this.AccessItemsForm.setControl('accessItemsGroups', AccessItemsFormArray);
@ -85,7 +85,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
private requestInProgressService: RequestInProgressService,
private customFieldService: CustomFieldsService,
private formBuilder: FormBuilder,
private formsValidatorService: FormsValidatorService) {
private formsValidatorService: FormsValidatorService) {
}
ngOnChanges(changes: SimpleChanges): void {
@ -148,20 +148,12 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
}
onSubmit() {
let valid = true;
this.formsValidatorService.formSubmitAttempt = true;
for (let i = 0; i < this.accessItemsGroups.length; i++) {
if (this.accessItemsGroups.controls[i].invalid) {
const validationState = this.toogleValidationAccessIdMap.get(i);
validationState ? this.toogleValidationAccessIdMap.set(i, !validationState) : this.toogleValidationAccessIdMap.set(i, true);
valid = false;
}
}
if (!valid) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, `There are some empty fields which are required.`))
return false;
}
this.onSave();
this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService.validateFormAccess(this.accessItemsGroups, this.toogleValidationAccessIdMap).then(value => {
if (value) {
this.onSave();
}
});
}
checkAll(row: number, value: any) {

View File

@ -122,4 +122,4 @@
</div>
</form>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { WorkbasketInformationComponent } from './workbasket-information.component';
import { FormsModule } from '@angular/forms';
@ -20,6 +20,7 @@ import { AlertService } from 'app/services/alert/alert.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { configureTests } from 'app/app.test.configuration';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
@Component({
selector: 'taskana-dummy-detail',
@ -36,7 +37,7 @@ const routes: Routes = [
describe('WorkbasketInformationComponent', () => {
let component: WorkbasketInformationComponent;
let fixture: ComponentFixture<WorkbasketInformationComponent>;
let debugElement, workbasketService, alertService, savingWorkbasketService, requestInProgressService;
let debugElement, workbasketService, alertService, savingWorkbasketService, requestInProgressService, formsValidatorService;
beforeEach(done => {
const configure = (testBed: TestBed) => {
@ -47,7 +48,7 @@ describe('WorkbasketInformationComponent', () => {
HttpClientModule,
RouterTestingModule.withRoutes(routes)],
providers: [WorkbasketService, AlertService, SavingWorkbasketService, ErrorModalService, RequestInProgressService,
CustomFieldsService]
CustomFieldsService, FormsValidatorService]
})
};
@ -58,7 +59,9 @@ describe('WorkbasketInformationComponent', () => {
workbasketService = TestBed.get(WorkbasketService);
alertService = TestBed.get(AlertService);
savingWorkbasketService = TestBed.get(SavingWorkbasketService);
requestInProgressService = TestBed.get(RequestInProgressService);
requestInProgressService = TestBed.get(RequestInProgressService);
formsValidatorService = TestBed.get(FormsValidatorService);
spyOn(alertService, 'triggerAlert');
fixture.detectChanges();
@ -95,8 +98,7 @@ describe('WorkbasketInformationComponent', () => {
expect(component.workbasket.type).toEqual('GROUP');
});
it('should create a copy of workbasket when workbasket is selected', () => {
it('should create a copy of workbasket when workbasket is selected', () => {
expect(component.workbasketClone).toBeUndefined();
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
@ -107,29 +109,35 @@ describe('WorkbasketInformationComponent', () => {
expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId);
});
it('should reset requestInProgress after saving request is done', fakeAsync(() => {
it('should reset requestInProgress after saving request is done', () => {
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
fixture.detectChanges();
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(of(component.workbasket));
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(of(component.workbasket));
component.onSubmit();
expect(component.requestInProgress).toBeFalsy();
}));
});
it('should trigger triggerWorkBasketSaved method after saving request is done', () => {
it('should trigger triggerWorkBasketSaved method after saving request is done', async(() => {
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(of(component.workbasket));
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(of(component.workbasket));
fixture.detectChanges();
component.onSubmit();
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
});
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(of(component.workbasket));
fixture.detectChanges();
it('should post a new workbasket when no workbasketId is defined and update workbasket', () => {
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
})
}));
it('should post a new workbasket when no workbasketId is defined and update workbasket', async(() => {
const workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
@ -138,14 +146,18 @@ describe('WorkbasketInformationComponent', () => {
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }))));
fixture.detectChanges();
component.onSubmit();
expect(alertService.triggerAlert).toHaveBeenCalled();
expect(component.workbasket.workbasketId).toBe('someNewId');
});
fixture.detectChanges();
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalled();
expect(component.workbasket.workbasketId).toBe('someNewId');
})
}));
it('should post a new workbasket, new distribution targets and new access ' +
'items when no workbasketId is defined and action is copy', () => {
'items when no workbasketId is defined and action is copy', async(() => {
const workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
'modified', 'name', 'description', 'owner', 'custom1', 'custom2',
'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
@ -160,13 +172,17 @@ describe('WorkbasketInformationComponent', () => {
spyOn(savingWorkbasketService, 'triggerDistributionTargetSaving');
spyOn(savingWorkbasketService, 'triggerAccessItemsSaving');
fixture.detectChanges();
component.onSubmit();
expect(alertService.triggerAlert).toHaveBeenCalled();
expect(component.workbasket.workbasketId).toBe('someNewId');
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
expect(savingWorkbasketService.triggerAccessItemsSaving).toHaveBeenCalled();
});
fixture.detectChanges();
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalled();
expect(component.workbasket.workbasketId).toBe('someNewId');
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
expect(savingWorkbasketService.triggerAccessItemsSaving).toHaveBeenCalled();
})
}));
it('should trigger requestInProgress service true before and requestInProgress false after remove a workbasket', () => {
const workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
@ -177,7 +193,6 @@ describe('WorkbasketInformationComponent', () => {
spyOn(workbasketService, 'removeDistributionTarget').and.returnValue(of(''));
const requestInProgressServiceSpy = spyOn(requestInProgressService, 'setRequestInProgress');
component.removeDistributionTargets();
expect(requestInProgressServiceSpy).toHaveBeenCalledWith(true);
workbasketService.removeDistributionTarget().subscribe(() => {
@ -187,5 +202,4 @@ describe('WorkbasketInformationComponent', () => {
});
})
});

View File

@ -47,7 +47,8 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
toogleValidationMap = new Map<string, boolean>();
private workbasketSubscription: Subscription;
private routeSubscription: Subscription;
private routeSubscription: Subscription;
private savingValidationSubscription: Subscription;
@ViewChild('WorkbasketForm') workbasketForm: NgForm;
constructor(private workbasketService: WorkbasketService,
@ -83,9 +84,11 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
onSubmit() {
this.formsValidatorService.formSubmitAttempt = true;
if (this.workbasketForm && this.formsValidatorService.validate(this.workbasketForm, this.toogleValidationMap)) {
this.onSave();
}
this.formsValidatorService.validateFormInformation(this.workbasketForm, this.toogleValidationMap).then(value => {
if (value) {
this.onSave();
}
});
}
isFieldValid(field: string): boolean {
@ -196,7 +199,8 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
ngOnDestroy() {
if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); }
if (this.routeSubscription) { this.routeSubscription.unsubscribe(); }
if (this.routeSubscription) { this.routeSubscription.unsubscribe(); }
if (this.savingValidationSubscription) { this.savingValidationSubscription.unsubscribe(); }
}
}

View File

@ -1,7 +1,7 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { TestBed, async, inject, fakeAsync } from '@angular/core/testing';
import { Component } from '@angular/core';
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router, Routes, ActivatedRoute, NavigationStart, RouterEvent } from '@angular/router';
import { Router, Routes } from '@angular/router';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { HttpClientModule } from '@angular/common/http';
import { MasterAndDetailService } from '../../services/masterAndDetail/master-and-detail.service'

View File

@ -1,7 +1,8 @@
import { NgForm } from '@angular/forms';
import { NgForm, FormArray } from '@angular/forms';
import { Injectable } from '@angular/core';
import { AlertService } from 'app/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/models/alert';
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
@Injectable()
export class FormsValidatorService {
@ -9,32 +10,82 @@ export class FormsValidatorService {
public formSubmitAttempt = false;
constructor(
private alertService: AlertService) {
private alertService: AlertService,
private accessIdsService: AccessIdsService) {
}
public validate(form: NgForm, toogleValidationMap: Map<any, boolean>): boolean {
let valid = true;
public validateFormInformation(form: NgForm, toogleValidationMap: Map<any, boolean>): Promise<any> {
let validSync = true;
const forFieldsPromise = new Promise((resolve, reject) => {
for (const control in form.form.controls) {
if (form.form.controls[control].invalid) {
const validationState = toogleValidationMap.get(control);
validationState ? toogleValidationMap.set(control, !validationState) : toogleValidationMap.set(control, true);
valid = false;
}
if (control.indexOf('owner') === -1 && form.form.controls[control].invalid) {
const validationState = toogleValidationMap.get(control);
validationState ? toogleValidationMap.set(control, !validationState) : toogleValidationMap.set(control, true);
validSync = false;
}
}
if (!valid) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, `There are some empty fields which are required.`))
resolve(validSync);
});
const ownerPromise = new Promise((resolve, reject) => {
if (form.form.controls['workbasket.owner']) {
this.accessIdsService.getAccessItemsInformation(form.form.controls['workbasket.owner'].value).subscribe(items => {
const validationState = toogleValidationMap.get('workbasket.owner');
validationState ? toogleValidationMap.set('workbasket.owner', !validationState) :
toogleValidationMap.set('workbasket.owner', true);
items.find(item => item.accessId === form.form.controls['workbasket.owner'].value) ? resolve(true) : resolve(false);
});
} else {
const validationState = toogleValidationMap.get(form.form.controls['workbasket.owner']);
validationState ? toogleValidationMap.set('workbasket.owner', !validationState) :
toogleValidationMap.set('workbasket.owner', true);
resolve(true);
}
});
return Promise.all([forFieldsPromise, ownerPromise]).then(values => {
if (!(values[0] && values[1])) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'There are some empty fields which are required.'))
}
return valid;
return values[0] && values[1];
});
}
public validateFormAccess(form: FormArray, toogleValidationAccessIdMap: Map<any, boolean>): Promise<boolean> {
const ownerPromise: Array<Promise<boolean>> = new Array<Promise<boolean>>();
for (let i = 0; i < form.length; i++) {
ownerPromise.push(new Promise((resolve, reject) => {
const validationState = toogleValidationAccessIdMap.get(i);
validationState ? toogleValidationAccessIdMap.set(i, !validationState) :
toogleValidationAccessIdMap.set(i, true);
this.accessIdsService.getAccessItemsInformation(form.controls[i].value['accessId']).subscribe(items => {
items.length > 0 ? resolve(true) : resolve(false);
})
}));
}
public isFieldValid(ngForm: NgForm, field: string) {
if (!ngForm || !ngForm.form.controls || !ngForm.form.controls[field]) {
return false;
}
if (!this.formSubmitAttempt) {
return true;
}
return (this.formSubmitAttempt && ngForm.form.controls[field].valid) ||
(ngForm.form.controls[field].touched && ngForm.form.controls[field].valid);
}
let result = true;
return Promise.all(ownerPromise).then(values => {
for (let i = 0; i < values.length; i++) {
result = result && values[i];
}
if (!result) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'There are some empty fields which are required.'))
}
return result;
});
}
public isFieldValid(ngForm: NgForm, field: string) {
if (!ngForm || !ngForm.form.controls || !ngForm.form.controls[field]) {
return false;
}
if (!this.formSubmitAttempt) {
return true;
}
return (this.formSubmitAttempt && ngForm.form.controls[field].valid) ||
(ngForm.form.controls[field].touched && ngForm.form.controls[field].valid);
}
}

View File

@ -34,4 +34,4 @@
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)"
placeholder="{{displayError? placeHolderMessage: ''}}" [@validation]="validationValue">
</div>
</div>
</div>

View File

@ -99,7 +99,6 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
});
}
getUsersAsObservable(token: string): Observable<any> {
return this.accessIdsService.getAccessItemsInformation(token);
}