Merge branch 'DEVELOP' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.gridFailureInformation.frontend into SI-541-Rolle-Gast-Lesezugriff

Signed-off-by: Ina Curdt <Ina.Curdt@pta.de>
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html
index aaee65b..ac0378a 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html
@@ -21,7 +21,7 @@
           </button>
           <ng-container *ngIf="gridFailureDetailsSandbox.showStornoButton && gridFailureDetailsSandbox.saveEnabled">
             <button
-              *visibleByRight="RolesEnum.QUALIFIER"
+              *visibleByRight="[RolesEnum.QUALIFIER]"
               type="button"
               class="btn btn-primary right-button"
               (click)="gridFailureDetailsSandbox.setState(StateEnum.CANCELED)"
@@ -33,7 +33,7 @@
         <div>
           <ng-container *ngIf="gridFailureDetailsSandbox.showQualifyButton && gridFailureDetailsSandbox.saveEnabled">
             <button
-              *visibleByRight="RolesEnum.QUALIFIER"
+              *visibleByRight="[RolesEnum.QUALIFIER]"
               type="button"
               class="btn btn-primary button"
               (click)="gridFailureDetailsSandbox.setState(StateEnum.QUALIFIED)"
@@ -44,21 +44,23 @@
           <ng-container *ngIf="gridFailureDetailsSandbox.showCreatedButton">
             <button
               type="button"
-              *visibleByRight="RolesEnum.CREATOR"
+              *visibleByRight="[RolesEnum.CREATOR]"
               class="btn btn-primary right-button"
               (click)="gridFailureDetailsSandbox.setState(StateEnum.CREATED)"
             >
               {{ 'CreatedBtn' | translate }}
             </button>
           </ng-container>
-          <button
-            *ngIf="gridFailureDetailsSandbox.saveEnabled"
-            type="button"
-            class="btn btn-success button"
-            (click)="gridFailureDetailsSandbox.saveGridFailure()"
-          >
-            {{ 'SaveBtn' | translate }}
-          </button>
+          <div *visibleByRight="[RolesEnum.CREATOR, RolesEnum.QUALIFIER, RolesEnum.PUBLISHER]">
+            <button
+              *ngIf="gridFailureDetailsSandbox.saveEnabled"
+              type="button"
+              class="btn btn-success button"
+              (click)="gridFailureDetailsSandbox.saveGridFailure()"
+            >
+              {{ 'SaveBtn' | translate }}
+            </button>
+          </div>
         </div>
       </div>
     </div>
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.html b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.html
index 4a4707c..07cbe5e 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.html
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.html
@@ -14,7 +14,7 @@
   <div header>
     <div class="d-flex flex-row-reverse header">
       <div class="col-xs-4 center" view="'list'">
-        <button class="btn btn-primary" (click)="sandbox.createGridFailure()">
+        <button class="btn btn-primary" (click)="sandbox.createGridFailure()" *visibleByRight="[RolesEnum.CREATOR]">
           {{ 'GridFailures.New' | translate }}
         </button>
       </div>
@@ -42,12 +42,14 @@
           <button class="btn btn-primary diverse-btn" (click)="clearGridFailureCondensation()">
             {{ 'CancelBtn' | translate }}
           </button>
-          <button class="btn btn-primary diverse-btn" *ngIf="!enableSelectionMode" (click)="changeToSelectionMode()">
-            {{ 'GridFailures.EditCondensation' | translate }}
-          </button>
-          <button class="btn btn-primary diverse-btn" *ngIf="enableSelectionMode" (click)="condenseChoosedGridFailureInformations()">
-            {{ 'GridFailures.CondenseChoosedGridFailureInformations' | translate }}
-          </button>
+          <div class="diverse-condensation-btns" *visibleByRight="[RolesEnum.CREATOR, RolesEnum.QUALIFIER, RolesEnum.PUBLISHER]">
+            <button class="btn btn-primary diverse-btn" *ngIf="!enableSelectionMode" (click)="changeToSelectionMode()" >
+              {{ 'GridFailures.EditCondensation' | translate }}
+            </button>
+            <button class="btn btn-primary diverse-btn" *ngIf="enableSelectionMode" (click)="condenseChoosedGridFailureInformations()" >
+              {{ 'GridFailures.CondenseChoosedGridFailureInformations' | translate }}
+            </button>
+          </div>
         </div>
       </div>
       <ag-grid-angular
@@ -67,11 +69,11 @@
 
     <div class="grid-failure-information-overview" *ngIf="view === 'list'; else map">
       <div class="diverse-options" *ngIf="!showCondensationTable">
-        <div class="custom-control custom-switch filter-switch" *visibleByRight="RolesEnum.PUBLISHER">
+        <div class="custom-control custom-switch filter-switch" *visibleByRight="[RolesEnum.PUBLISHER]">
           <input type="checkbox" class="custom-control-input" id="filterSwitch" (change)="changeFilter($event.target.checked)" />
           <label class="custom-control-label" for="filterSwitch">{{ 'GridFailures.FilterLabel' | translate }}</label>
         </div>
-        <button class="btn btn-primary diverse-btn" (click)="changeToSelectionMode()">
+        <button class="btn btn-primary diverse-btn" (click)="changeToSelectionMode()" *visibleByRight="[RolesEnum.CREATOR, RolesEnum.QUALIFIER, RolesEnum.PUBLISHER]" >
           {{ 'GridFailures.Condensation' | translate }}
         </button>
       </div>
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts
index b3e7b65..45acef8 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts
@@ -1,3 +1,4 @@
+import { PermissionsModel } from '@grid-failure-information-app/shared/models/permissions.model';
 /********************************************************************************
  * Copyright (c) 2020 Contributors to the Eclipse Foundation
  *
@@ -36,6 +37,7 @@
       loadCondensedGridFailures() {},
       setGlobalGridFailureFilter() {},
       resetOverviewList() {},
+      permissions:{reader: true}
     } as any;
     utilService = {
       displayNotification() {},
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
index 40d2ae8..b4a7b77 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
@@ -130,6 +130,7 @@
   }
 
   private _setInitialGridOptions(): void {
+    this.gridOptions.context = {...this.gridOptions.context,icons:{ readonly:this.sandbox.permissions.reader}};
     this.gridOptions.context.eventSubject.pipe(takeUntil(this._endSubscriptions$)).subscribe(event => {
       switch (event.type) {
         case this._eventTypeEnum.Edit:
@@ -160,6 +161,7 @@
       }
     });
 
+    this.gridOptionsCondensation.context = {...this.gridOptionsCondensation.context,icons:{ readonly:this.sandbox.permissions.reader}};
     this.gridOptionsCondensation.context.eventSubject.pipe(takeUntil(this._endSubscriptions$)).subscribe(event => {
       switch (event.type) {
         case this._eventTypeEnum.Remove:
diff --git a/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.spec.ts b/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.spec.ts
index 97b9d0e..93187ab 100644
--- a/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.spec.ts
@@ -40,7 +40,6 @@
       data: { editable: true },
     };
     component.agInit(params);
-    expect(component.editFlag).toBe(true);
     expect(component.addIcon).toBe(true);
     expect(component.readonlyIcon).toBe(true);
     expect(component.deleteIcon).toBe(true);
@@ -60,7 +59,6 @@
       data: { editable: false },
     };
     component.agInit(params);
-    expect(component.editFlag).toBe(false);
     expect(component.addIcon).toBe(null);
     expect(component.readonlyIcon).toBe(null);
     expect(component.deleteIcon).toBe(null);
diff --git a/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.ts b/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.ts
index 4c5cf45..ed16d91 100644
--- a/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.ts
+++ b/projects/grid-failure-information-app/src/app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component.ts
@@ -24,7 +24,6 @@
   public editIcon = null;
   public deleteIcon = null;
   public readonlyIcon = null;
-  public editFlag = null;
   public addIcon = null;
   public removeIcon = null;
   public condensedIcon = null;
@@ -34,7 +33,6 @@
 
   public agInit(params: ICellRendererParams): void {
     this.params = params;
-    this.editFlag = params.data['editable'];
     this._updateIcon();
     if (params.context && params.context.icons) {
       const contextIcons = params.context.icons;
@@ -63,14 +61,14 @@
     this.params.context.eventSubject.subscribe((event: any) => {
       switch (event.eventType) {
         case this._modeEnum.InitialMode:
-          this.editIcon = true;
+          this.editIcon = true && !this.readonlyIcon;
           this.condensedIcon = this.params.data.condensed;
           this.addIcon = false;
           this.removeIcon = false;
           break;
         case this._modeEnum.OverviewTableSelectionMode:
           this.editIcon = false;
-          this.addIcon = !this.params.data.condensed;
+          this.addIcon = !this.params.data.condensed &&!this.readonlyIcon;
           this.condensedIcon = false;
           break;
         case this._modeEnum.CondensationTableSelectionMode:
diff --git a/projects/grid-failure-information-app/src/app/shared/constants/enums.ts b/projects/grid-failure-information-app/src/app/shared/constants/enums.ts
index 5c00023..06eec2e 100644
--- a/projects/grid-failure-information-app/src/app/shared/constants/enums.ts
+++ b/projects/grid-failure-information-app/src/app/shared/constants/enums.ts
@@ -50,7 +50,7 @@
   CREATOR = 'grid-failure-creator',
   PUBLISHER = 'grid-failure-publisher',
   QUALIFIER = 'grid-failure-qualifier',
-  READER = 'grid-failure-reader'
+  READER = 'grid-failure-reader',
 }
 
 export enum StateEnum {
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/directives.module.ts b/projects/grid-failure-information-app/src/app/shared/directives/directives.module.ts
index d47a8a9..3a695a9 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/directives.module.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/directives.module.ts
@@ -1,3 +1,4 @@
+
 /********************************************************************************
  * Copyright (c) 2020 Contributors to the Eclipse Foundation
  *
@@ -17,11 +18,12 @@
 import { TranslateColumnDefinitionsDirective } from '@grid-failure-information-app/shared/directives/agGrid/translate-column-definitions.directive';
 import { VisibleByRightDirective } from '@grid-failure-information-app/shared/directives/visible-by-right';
 import { AgGridAngular } from 'ag-grid-angular';
+import { FormDisableDirective } from '@grid-failure-information-app/shared/directives/form-disable.directive';
 
 @NgModule({
   imports: [CommonModule],
-  declarations: [AutoResizeColumnsDirective, TranslateColumnDefinitionsDirective, ServerSideDirective, VisibleByRightDirective],
-  exports: [AutoResizeColumnsDirective, TranslateColumnDefinitionsDirective, ServerSideDirective, VisibleByRightDirective],
+  declarations: [AutoResizeColumnsDirective, TranslateColumnDefinitionsDirective, ServerSideDirective, VisibleByRightDirective, FormDisableDirective],
+  exports: [AutoResizeColumnsDirective, TranslateColumnDefinitionsDirective, ServerSideDirective, VisibleByRightDirective, FormDisableDirective],
 
   entryComponents: [AgGridAngular],
 })
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts b/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts
new file mode 100644
index 0000000..bb0771b
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+// import { FormDisableDirective } from '@shared/directives/form-disable.directive';
+import { FormDisableDirective } from '@grid-failure-information-app/shared/directives/form-disable.directive';
+import { async } from '@angular/core/testing';
+import { of } from 'rxjs/observable/of';
+import { PermissionsModel } from '../models/permissions.model';
+
+describe('FormDisableDirective', () => {
+  let viewContainerRef: any;
+  let appState: any;
+  beforeEach(async(() => {
+    viewContainerRef = {
+      createEmbeddedView: () => {},
+      clear: () => {},
+      element: { nativeElement: { elements: [{ classList: {}, disabled: undefined, childNodes: [] }] } },
+    };
+
+    appState = {
+      pipe: () => of(),
+      dispatch: () => {},
+      select: () => of({ roles: ['grid-failure-reader'] }),
+      map: () => of({ reader: true }),
+    };
+  }));
+
+  it('should create an instance', () => {
+    const directive = new FormDisableDirective(viewContainerRef as any, appState as any);
+    expect(directive).toBeTruthy();
+  });
+
+  it('should traverse a DOM', () => {
+    const directive = new FormDisableDirective(viewContainerRef as any, appState as any);
+    const spy = spyOn(directive, '_traverseDOM' as any);
+    directive.ngAfterViewInit();
+    expect(spy).toHaveBeenCalled();
+  });
+
+});
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.ts b/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.ts
new file mode 100644
index 0000000..9bfb851
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.ts
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { Directive, ViewContainerRef, AfterViewInit, OnDestroy } from '@angular/core';
+import { Store } from '@ngrx/store';
+// import * as store from '@shared/store';
+import * as store from '@grid-failure-information-app/shared/store';
+import { Observable, Subject } from 'rxjs';
+// import { User } from '@shared/models/user';
+import { User } from '@grid-failure-information-app/shared/models/user';
+// import { PermissionsModel } from '@shared/models/permissions.model';
+import { PermissionsModel } from '@grid-failure-information-app/shared/models/permissions.model';
+import { takeUntil } from 'rxjs/operators';
+
+@Directive({
+  selector: 'form',
+})
+export class FormDisableDirective implements AfterViewInit, OnDestroy {
+  private _endSubscriptions$: Subject<boolean> = new Subject();
+  private _permissions$: Observable<PermissionsModel> = this._appState$
+    .select(store.getUser)
+    .pipe(takeUntil(this._endSubscriptions$))
+    .map((user: User) => {
+      return new PermissionsModel(user.roles);
+    });
+
+  constructor(private _viewContainer: ViewContainerRef, private _appState$: Store<store.State>) {}
+
+  ngAfterViewInit() {
+    this._permissions$.subscribe(permissions => {
+      this._traverseDOM(this._viewContainer.element.nativeElement.elements, permissions);
+    });
+  }
+  ngOnDestroy() {
+    this._endSubscriptions$.next(true);
+  }
+  private _traverseDOM(elements: any[], permissions: PermissionsModel): void {
+    for (const element of elements) {
+      const isCancelButton = !!Object.keys(element.classList || {}).find(
+        item => element.classList[item] === 'cancel-button' || element.classList[item] === 'btn-sm'
+      );
+      element.disabled = element.disabled || (!isCancelButton && permissions.reader);
+
+      this._traverseDOM(element.childNodes, permissions);
+    }
+  }
+}
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.spec.ts b/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.spec.ts
index b3035b0..dc83e66 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.spec.ts
@@ -76,20 +76,68 @@
 
   it('should clear view for invalidRole', () => {
     const directive = new VisibleByRightDirective(templateRef as any, viewContainerRef as any, appState as any);
-    directive.visibleByRight = ["_InvalidRole_"];
+
+    directive.visibleByRight = ['_InvalidRole_'];
+    const spy = spyOn(directive['_viewContainer'], 'clear' as any);
+    directive.ngOnInit();
+    expect(spy).toHaveBeenCalled();
+  });
+  it('should create embedded view for role creator', () => {
+    const directive = new VisibleByRightDirective(templateRef as any, viewContainerRef as any, appState as any);
+    directive.visibleByRight = [RolesEnum.CREATOR];
+    const spy = spyOn(directive['_viewContainer'], 'createEmbeddedView' as any);
+    directive.ngOnInit();
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('should clear view for another role than admin or qualifier', () => {
+    appState = {
+      pipe: () => of(),
+      dispatch: () => {},
+      select: () => of({ roles: [RolesEnum.PUBLISHER] }),
+      map: () => of({}),
+    };
+    const directive = new VisibleByRightDirective(templateRef as any, viewContainerRef as any, appState as any);
+
+    directive.visibleByRight = [RolesEnum.QUALIFIER];
     const spy = spyOn(directive['_viewContainer'], 'clear' as any);
     directive.ngOnInit();
     expect(spy).toHaveBeenCalled();
   });
 
   it('should create embedded view for role creator', () => {
-    // Arrange
     const directive = new VisibleByRightDirective(templateRef as any, viewContainerRef as any, appState as any);
     directive.visibleByRight = [RolesEnum.CREATOR];
     const spy = spyOn(directive['_viewContainer'], 'createEmbeddedView' as any);
-    // Act
     directive.ngOnInit();
-    // Assert
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('should clear view for reader', () => {
+    appState = {
+      pipe: () => of(),
+      dispatch: () => {},
+      select: () => of({ roles: [RolesEnum.READER] }),
+      map: () => of({}),
+    };
+    const directive = new VisibleByRightDirective(templateRef as any, viewContainerRef as any, appState as any);
+    directive.visibleByRight = [RolesEnum.QUALIFIER];
+    const spy = spyOn(directive['_viewContainer'], 'clear' as any);
+    directive.ngOnInit();
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('should create embedded view for reader', () => {
+    appState = {
+      pipe: () => of(),
+      dispatch: () => {},
+      select: () => of({ roles: [RolesEnum.READER] }),
+      map: () => of({}),
+    };
+    const directive = new VisibleByRightDirective(templateRef as any, viewContainerRef as any, appState as any);
+    directive.visibleByRight = [RolesEnum.READER];
+    const spy = spyOn(directive['_viewContainer'], 'createEmbeddedView' as any);
+    directive.ngOnInit();
     expect(spy).toHaveBeenCalled();
   });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.ts b/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.ts
index 4b21a32..f6e8849 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/visible-by-right.ts
@@ -23,9 +23,7 @@
   selector: '[visibleByRight]',
 })
 export class VisibleByRightDirective implements OnInit, OnDestroy {
-
   @Input() visibleByRight?: string[];
-
   private _endSubscriptions$: Subject<boolean> = new Subject();
   private _permissions$: Observable<PermissionsModel> = this._appState$
     .select(store.getUser)
diff --git a/projects/grid-failure-information-app/src/app/shared/guards/admin.guard.ts b/projects/grid-failure-information-app/src/app/shared/guards/admin.guard.ts
index 1b15c77..2b6312b 100644
--- a/projects/grid-failure-information-app/src/app/shared/guards/admin.guard.ts
+++ b/projects/grid-failure-information-app/src/app/shared/guards/admin.guard.ts
@@ -18,6 +18,7 @@
 import { User } from '@grid-failure-information-app/shared/models/user';
 import { PermissionsModel } from '@grid-failure-information-app/shared/models/permissions.model';
 import { takeUntil, take } from 'rxjs/operators';
+import { RolesEnum } from '../constants/enums';
 
 @Injectable()
 export class AdminGuard implements CanActivate {