Merge branch 'KON-13-Uebersicht-kontakte-dsgvo' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.contactBaseData.frontend into DEVELOP

Signed-off-by: Dimitrios Chalepakis <dimitrios.chalepakis@pta.de>
diff --git a/i18n/contacts.de.json b/i18n/contacts.de.json
index dbe91b2..e1aa16e 100644
--- a/i18n/contacts.de.json
+++ b/i18n/contacts.de.json
@@ -20,6 +20,11 @@
     "CommunicationsDataList": "Kommunikationskanäle",
     "ContactPersonList": "Ansprechpartner",
     "CommunicationsDataList": "Kommunikationskanäle",
-    "ModuleAssignment": "Modulzuordnung"
+    "ModuleAssignment": "Modulzuordnung",
+    "AllModuleAssignments": "Alle Modulzuordnungen",
+    "WithoutModuleAssignment": "Keine Modulzuordnung",
+    "DSGVO-advanced-filter": "DSGVO - Filtererweiterung",
+    "DSGVO-advanced-filter-deletion-lock-exceeded": "Filterung nach Kontakten mit abgelaufener Löschsperre",
+    "DSGVO-advanced-filter-expiring-data-in-past": "Filterung nach Kontakten mit überschrittenem Ablaufdatum"
   }
 }
diff --git a/package.json b/package.json
index 602c2b6..67da642 100644
--- a/package.json
+++ b/package.json
@@ -17,9 +17,8 @@
     "sy-post-build": "node hooks/post-build.js",
     "sy-build": "npm run sy-pre-build && ng build --base-href /contactdatabase/ --prod --aot && npm run sy-post-build",
     "sy-build-noprod": "npm run sy-pre-build && ng build --base-href /contactdatabase/ && npm run sy-post-build",
-    "start-in-docker": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker.conf.json",    
-	"start-in-docker-unsecure": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker-unsecure.conf.json"
-
+    "start-in-docker": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker.conf.json",
+    "start-in-docker-unsecure": "npm run sy-pre-start && ng serve --optimization=false --vendor-chunk --common-chunk --host=0.0.0.0 --disableHostCheck=true --proxy-config proxy-docker-unsecure.conf.json"
   },
   "private": true,
   "dependencies": {
diff --git a/src/app/pages/contacts/contacts-api-client.ts b/src/app/pages/contacts/contacts-api-client.ts
index 745f47e..f1eb052 100644
--- a/src/app/pages/contacts/contacts-api-client.ts
+++ b/src/app/pages/contacts/contacts-api-client.ts
@@ -34,11 +34,25 @@
         modifiedContacts.searchText,
         modifiedContacts.contactTypeId,
         modifiedContacts.sort,
+        modifiedContacts.moduleName,
+        modifiedContacts.withoutAssignedModule,
+        modifiedContacts.expiringDataInPast,
+        modifiedContacts.deletionLockExceeded,
         request.pageNumber ? request.pageNumber - 1 : 0,
         request.pageSize
       );
     } else {
-      return this._getContactsPage(modifiedContacts.searchText, modifiedContacts.contactTypeId, modifiedContacts.sort, 1, 3);
+      return this._getContactsPage(
+        modifiedContacts.searchText,
+        modifiedContacts.contactTypeId,
+        modifiedContacts.sort,
+        modifiedContacts.moduleName,
+        modifiedContacts.withoutAssignedModule,
+        modifiedContacts.expiringDataInPast,
+        modifiedContacts.deletionLockExceeded,
+        1,
+        3
+      );
     }
   }
 
@@ -51,6 +65,10 @@
     @Query('searchText') searchtext: string,
     @Query('contactType') contactTypeId: string,
     @Query('sort') sort: string,
+    @Query('moduleName') moduleName: string,
+    @Query('withoutAssignedModule') withoutAssignedModule: boolean,
+    @Query('expiringDataInPast') expiringDataInPast: boolean,
+    @Query('deletionLockExceeded') deletionLockExceeded: boolean,
     @Query('page') pageNumber: number,
     @Query('size') pageSize: number
   ): Observable<any> {
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.html b/src/app/pages/contacts/contacts-list/contacts-list.component.html
index ba03537..027e603 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.html
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.html
@@ -16,34 +16,71 @@
   </div>
   <div class="contacts-grid-wrapper" body>
     <div class="diverse-options">
-      <div class="searching diverse-options-item">
-        <div class="search-options">
-          <input
-            type="text"
-            class="item"
-            id="searchText"
-            placeholder="Suche"
-            (keyup)="setModifiedContactsSearchText($event.target.value); searchContacts($event)"
-          />
+      <div class="search-options diverse-options-item">
+        <input
+          type="text"
+          class="item"
+          id="search-text"
+          placeholder="Suche"
+          (keyup)="setModifiedContactsSearchText($event.target.value); searchContacts($event)"
+        />
 
-          <select
-            [required]="false"
-            type="text"
-            class="form-control item"
-            (change)="setModifiedContactsContactTypeId($event.target.value); searchContacts($event)"
+        <select
+          [required]="false"
+          type="text"
+          class="form-control item"
+          (change)="setModifiedContactsContactTypeId($event.target.value); searchContacts($event)"
+        >
+          <option value="{{ INTERNAL_PERSON }}">{{ 'Contacts.InternalContact' | translate }}</option>
+          <option value="{{ EXTERNAL_PERSON }}">{{ 'Contacts.ExternalContact' | translate }}</option>
+          <option value="{{ COMPANY }}">{{ 'Contacts.Company' | translate }}</option>
+          <option value="" selected>{{ 'Contacts.AllContactTypes' | translate }}</option>
+        </select>
+
+        <div class="dsgvo-filter-container search-btn">
+          <button
+            type="button"
+            class="btn btn-default btn-sm"
+            (click)="isDSGVOFilterAdvancedVisible = !isDSGVOFilterAdvancedVisible"
+            title="{{ 'Contacts.DSGVO-advanced-filter' | translate }}"
           >
-            <option value="{{ INTERNAL_PERSON }}">{{ 'Contacts.InternalContact' | translate }}</option>
-            <option value="{{ EXTERNAL_PERSON }}">{{ 'Contacts.ExternalContact' | translate }}</option>
-            <option value="{{ COMPANY }}">{{ 'Contacts.Company' | translate }}</option>
-            <option value="" selected>{{ 'Contacts.AllContactTypes' | translate }}</option>
-          </select>
+            DSGVO
+          </button>
+          <div class="dsgvo-filter-options" *ngIf="isDSGVOFilterAdvancedVisible">
+            <select
+              [required]="false"
+              type="text"
+              class="form-control"
+              style="margin-right: 12px;"
+              (change)="setModifiedContactsModuleAssignmentFilter($event.target.value); searchContacts($event)"
+            >
+              <option *ngFor="let moduleType of userModuleAssignmentSandbox.userModuleTypes$ | async" [value]="moduleType.id">{{ moduleType.id }}</option>
+              <option [value]="'-1'">{{ 'Contacts.WithoutModuleAssignment' | translate }}</option>
+              <option [value]="''" selected>{{ 'Contacts.AllModuleAssignments' | translate }}</option>
+            </select>
 
-          <div class="search-btn">
-            <button type="button" class="btn btn-default btn-sm" (click)="searchContacts($event)" title="suchen">
-              <em class="fa fa-search fa-lg " aria-hidden="true "></em>
-            </button>
+            <div class="dsgvo-filter-item custom-control custom-switch" title="{{ 'Contacts.DSGVO-advanced-filter-expiring-data-in-past' | translate }}">
+              <input type="checkbox" class="custom-control-input" id="expiry-date" (change)="setModifiedContactsExpiryDateFilter(); searchContacts($event)" />
+              <label class="custom-control-label" style="position: 0px;" for="expiry-date"></label>
+            </div>
+
+            <div class="dsgvo-filter-item custom-control custom-switch" title="{{ 'Contacts.DSGVO-advanced-filter-deletion-lock-exceeded' | translate }}">
+              <input
+                type="checkbox"
+                class="custom-control-input"
+                id="deletion-lock-until"
+                (change)="setModifiedContactsDeletionLockExceedFilter(); searchContacts($event)"
+              />
+              <label class="custom-control-label" for="deletion-lock-until"></label>
+            </div>
           </div>
         </div>
+
+        <div class="search-btn">
+          <button type="button" class="btn btn-default btn-sm" (click)="searchContacts($event)" title="suchen">
+            <em class="fa fa-search fa-lg " aria-hidden="true "></em>
+          </button>
+        </div>
       </div>
 
       <div class="sorting-options diverse-options-item">
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.scss b/src/app/pages/contacts/contacts-list/contacts-list.component.scss
index 83462b7..7b3ad89 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.scss
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.scss
@@ -46,24 +46,23 @@
   margin-right: 2px;
 }
 
-.searching {
-  display: flex;
-  flex-wrap: nowrap;
-  justify-content: flex-start;
-}
-
 .search-options {
   display: flex;
   flex-wrap: nowrap;
   justify-content: flex-start;
   align-items: center;
+  flex-grow: 1;
 }
 
 .item {
-  min-width: 170px;
+  flex-basis: 185px;
   margin: 5px;
 }
 
+#search-text {
+  max-width: 160px;
+}
+
 .search-btn {
   display: flex;
   align-items: center;
@@ -80,6 +79,7 @@
   flex-wrap: nowrap;
   justify-content: flex-start;
   align-items: center;
+  min-width: 380px;
 }
 
 .diverse-btn {
@@ -102,3 +102,21 @@
   margin-right: 2px;
   margin-bottom: 2px;
 }
+.dsgvo-filter-container {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-start;
+  justify-self: center;
+}
+.dsgvo-filter-options {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-start;
+  align-items: center;
+  flex-grow: 1;
+}
+.dsgvo-filter-item {
+  margin: 4px 0px 0px 12px;
+}
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts b/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts
index 295e22f..222b05f 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.spec.ts
@@ -17,11 +17,12 @@
 describe('ContactsListComponent', () => {
   let component: ContactsListComponent;
   let contactsSandbox: any = {};
+  let userModuleAssignmentSandbox: any = {};
   let router: any = {};
 
   beforeEach(() => {
     router = { navigateByUrl() {}, navigate() {} } as any;
-    component = new ContactsListComponent(contactsSandbox, router);
+    component = new ContactsListComponent(contactsSandbox, userModuleAssignmentSandbox, router);
   });
 
   it('should create', () => {
@@ -170,7 +171,7 @@
     expect((component as any)._sortingOrder).toBe('asc');
   });
 
-  it('checks if function _setModifiedContactsSortProperty() works', () => {
+  it('checks if function _setModifiedContactsSort() works', () => {
     component.setSortingContactType('name');
     (component as any)._setModifiedContactsSort();
     expect(component.modifiedContacts.sort).toBe('name,asc');
@@ -183,4 +184,31 @@
     (component as any)._setModifiedContactsSort();
     expect(component.modifiedContacts.sort).toBe(null);
   });
+
+  it('checks if function setModifiedContactsExpiryDateFilter() works', () => {
+    expect(component.modifiedContacts.expiringDataInPast).toBeFalsy();
+    component.setModifiedContactsExpiryDateFilter();
+    expect(component.modifiedContacts.expiringDataInPast).toBeTruthy();
+  });
+
+  it('checks if function setModifiedContactsDeletionLockExceedFilter() works', () => {
+    expect(component.modifiedContacts.deletionLockExceeded).toBeFalsy();
+    component.setModifiedContactsDeletionLockExceedFilter();
+    expect(component.modifiedContacts.deletionLockExceeded).toBeTruthy();
+  });
+
+  it('checks if function setModifiedContactsModuleAssignmentFilter() works', () => {
+    let moduleName = '-1';
+    component.setModifiedContactsModuleAssignmentFilter(moduleName);
+    expect(component.modifiedContacts.moduleName).toBe(null);
+    expect(component.modifiedContacts.withoutAssignedModule).toBeTruthy();
+    moduleName = '';
+    component.setModifiedContactsModuleAssignmentFilter(moduleName);
+    expect(component.modifiedContacts.moduleName).toBe(null);
+    expect(component.modifiedContacts.withoutAssignedModule).toBeFalsy();
+    moduleName = 'Betriebstagebuch';
+    component.setModifiedContactsModuleAssignmentFilter(moduleName);
+    expect(component.modifiedContacts.moduleName).toBe(moduleName);
+    expect(component.modifiedContacts.withoutAssignedModule).toBeFalsy();
+  });
 });
diff --git a/src/app/pages/contacts/contacts-list/contacts-list.component.ts b/src/app/pages/contacts/contacts-list/contacts-list.component.ts
index 99b8d8d..56a3d9e 100644
--- a/src/app/pages/contacts/contacts-list/contacts-list.component.ts
+++ b/src/app/pages/contacts/contacts-list/contacts-list.component.ts
@@ -17,6 +17,8 @@
 import { Router } from '@angular/router';
 import { Globals } from '@shared/constants/globals';
 import { ModifiedContacts } from '@shared/models/modifiedContacts.model';
+import { UserModuleAssignmentSandBox } from '@shared/components/list-details-view/user-module-assignment/user-module-assignment.sandbox';
+import { ofType } from '@ngrx/effects';
 
 @Component({
   selector: 'app-contacts-list',
@@ -34,11 +36,14 @@
 
   public columnDefinition: any = CONTACTS_COLDEF;
   public modifiedContacts: ModifiedContacts = new ModifiedContacts();
+  public isDSGVOFilterAdvancedVisible = false;
 
   private _sortingOrder: string = 'asc';
   private _sortingContactType: string = '';
+  private _expiringDataInPast = false;
+  private _deletionLockExceeded = false;
 
-  constructor(public contactsSandbox: ContactsSandbox, private router: Router) {
+  constructor(public contactsSandbox: ContactsSandbox, public userModuleAssignmentSandbox: UserModuleAssignmentSandBox, private router: Router) {
     super();
   }
 
@@ -104,6 +109,32 @@
     this.modifiedContacts.contactTypeId = contactTypeId;
   }
 
+  public setModifiedContactsModuleAssignmentFilter(moduleName: string) {
+    if (moduleName === '-1') {
+      //show contacts without module assignments
+      this.modifiedContacts.moduleName = null;
+      this.modifiedContacts.withoutAssignedModule = true;
+    } else if (moduleName == '') {
+      //show contacts with all module assignments
+      this.modifiedContacts.moduleName = null;
+      this.modifiedContacts.withoutAssignedModule = false;
+    } else {
+      //show contacts with specific module assignments
+      this.modifiedContacts.moduleName = moduleName;
+      this.modifiedContacts.withoutAssignedModule = false;
+    }
+  }
+
+  public setModifiedContactsExpiryDateFilter() {
+    this._expiringDataInPast = !this._expiringDataInPast;
+    this.modifiedContacts.expiringDataInPast = this._expiringDataInPast;
+  }
+
+  public setModifiedContactsDeletionLockExceedFilter() {
+    this._deletionLockExceeded = !this._deletionLockExceeded;
+    this.modifiedContacts.deletionLockExceeded = this._deletionLockExceeded;
+  }
+
   public setSortingContactType(sortingContactType: string) {
     this._sortingContactType = sortingContactType;
   }
diff --git a/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html b/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html
index 69931c7..d88aa5e 100644
--- a/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html
+++ b/src/app/shared/components/list-details-view/user-module-assignment/details/details.component.html
@@ -31,7 +31,7 @@
       <div class="input-group col-sm-7">
         <div class="input-group-prepend">
           <button class="btn btn-outline-primary calendar" (click)="expiringDateCalendar.toggle()" type="button">
-            <i class="fa fa-calendar"></i>
+            <em class="fa fa-calendar"></em>
           </button>
         </div>
         <input
@@ -49,7 +49,7 @@
         />
         <div class="input-group-append">
           <button class="btn btn-outline-primary calendar" (click)="reset('expiringDate')" type="button">
-            <i class="fa fa-times-circle" aria-hidden="true"></i>
+            <em class="fa fa-times-circle" aria-hidden="true"></em>
           </button>
         </div>
       </div>
diff --git a/src/app/shared/models/modifiedContacts.model.ts b/src/app/shared/models/modifiedContacts.model.ts
index 886e071..e7817a9 100644
--- a/src/app/shared/models/modifiedContacts.model.ts
+++ b/src/app/shared/models/modifiedContacts.model.ts
@@ -1,15 +1,17 @@
 import { Contact } from '@shared/models';
 
 export class ModifiedContacts {
+  public searchText: string = null;
+  public contactTypeId: string = '';
+  public sort: string = null;
+  public moduleName: string = null;
+  public withoutAssignedModule: boolean = null;
+  public expiringDataInPast: boolean = null;
+  public deletionLockExceeded: boolean = null;
 
-    public searchText: string = null;
-    public contactTypeId: string = '';
-    public sort: string = null;
-  
-    public constructor(data: any = null) {
-      Object.keys(data || {})
-        .filter(property => this.hasOwnProperty(property))
-        .forEach(property => (this[property] = data[property]));
-    }
+  public constructor(data: any = null) {
+    Object.keys(data || {})
+      .filter(property => this.hasOwnProperty(property))
+      .forEach(property => (this[property] = data[property]));
   }
-  
\ No newline at end of file
+}