From 2b7ebe6036dbe93663da181c41ac02870492e043 Mon Sep 17 00:00:00 2001
From: paf <paf@titelfrei.de>
Date: Wed, 2 Dec 2020 14:39:07 +0100
Subject: [PATCH] make all tests from group available for group-monitor as demo

---
 docs/test-mode.md                             |  19 +--
 .../monitor-starter.component.css             |  26 ++++
 .../monitor-starter.component.html            |  13 +-
 .../monitor-starter.component.ts              | 135 ++++++++++--------
 src/app/app-route-guards.ts                   |   4 +-
 src/app/config/test-mode.ts                   |   2 +-
 src/app/config/test-modes.json                |  12 ++
 7 files changed, 139 insertions(+), 72 deletions(-)
 create mode 100644 src/app/app-root/monitor-starter/monitor-starter.component.css

diff --git a/docs/test-mode.md b/docs/test-mode.md
index 2895d07e..861f47e9 100644
--- a/docs/test-mode.md
+++ b/docs/test-mode.md
@@ -14,17 +14,18 @@ then switch on some restrictions and store responses, and finally evaluate the
 test like a testtaker.   
 
 * `DEMO` (default): Nur Ansicht (Demo)
+* `MONITOR-GROUP`: Testgruppen-Monitor (Demo)
 * `HOT`: Durchführung Test/Befragung
 * `REVIEW`: Prüfdurchgang ohne Speichern
 * `TRIAL`: Prüfdurchgang mit Speichern
 
 
-|  | `DEMO` | `HOT` | `REVIEW` | `TRIAL` | 
-| :------------- | :-------------: | :-------------: | :-------------: | :-------------: |
-|Es können Reviews abgegeben werden (Kommentare/Einschätzungen zur Unit bzw. zum Test)|  |  |X |  |
-|Es werden Antworten und Logs gespeichert.|  |X |  |X |
-|Alle Zeitbeschränkungen für Testabschnitte werden angewendet.|  |X |  |X |
-|Alle Navigationsbeschränkungen des Booklets werden angewendet (z. B. erst weiter, wenn vollständig angezeigt).|  |X |  |X |
-|Sollte ein Testabschnitt mit einem Freigabewort geschützt sein, wird dieses bei der Eingabebox schon eingetragen.|X |  |X |X |
-|Sollte eine Maximalzeit für einen Testabschnitt festgelegt sein, wird die verbleibende Zeit angezeigt, auch wenn die Booklet-Konfiguration dies unterbindet.|X |  |X |  |
-|Die Seite mit der Aufgaben-Ãœbersicht wird erlaubt, auch wenn das Booklet dies unterbindet.|  |  |X |  |
+|  | `DEMO` | `MONITOR-GROUP` | `HOT` | `REVIEW` | `TRIAL` | 
+| :------------- | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+|Es können Reviews abgegeben werden (Kommentare/Einschätzungen zur Unit bzw. zum Test)|  |  |  |X |  |
+|Es werden Antworten und Logs gespeichert.|  |  |X |  |X |
+|Alle Zeitbeschränkungen für Testabschnitte werden angewendet.|  |  |X |  |X |
+|Alle Navigationsbeschränkungen des Booklets werden angewendet (z. B. erst weiter, wenn vollständig angezeigt).|  |  |X |  |X |
+|Sollte ein Testabschnitt mit einem Freigabewort geschützt sein, wird dieses bei der Eingabebox schon eingetragen.|X |X |  |X |X |
+|Sollte eine Maximalzeit für einen Testabschnitt festgelegt sein, wird die verbleibende Zeit angezeigt, auch wenn die Booklet-Konfiguration dies unterbindet.|X |X |  |X |  |
+|Die Seite mit der Aufgaben-Ãœbersicht wird erlaubt, auch wenn das Booklet dies unterbindet.|  |  |  |X |  |
diff --git a/src/app/app-root/monitor-starter/monitor-starter.component.css b/src/app/app-root/monitor-starter/monitor-starter.component.css
new file mode 100644
index 00000000..43a8e83f
--- /dev/null
+++ b/src/app/app-root/monitor-starter/monitor-starter.component.css
@@ -0,0 +1,26 @@
+mat-card {
+    margin: 10px;
+}
+
+.mat-card-gray {
+    background-color: lightgray
+}
+
+.booklet_title {
+    display: block;
+    font-size: 16pt;
+    margin-top: 4px;
+    margin-bottom: 0;
+    white-space: pre-wrap;
+    word-break: break-word;
+    line-height: 130%;
+}
+
+.booklet_status {
+    display: block;
+    font-size: 8pt;
+    margin-top: 0;
+    color: mediumturquoise;
+    height: 24px;
+    margin-bottom: 18px;
+}
diff --git a/src/app/app-root/monitor-starter/monitor-starter.component.html b/src/app/app-root/monitor-starter/monitor-starter.component.html
index 08a0bc54..05b65e16 100644
--- a/src/app/app-root/monitor-starter/monitor-starter.component.html
+++ b/src/app/app-root/monitor-starter/monitor-starter.component.html
@@ -6,9 +6,18 @@
         <p *ngIf="accessObjects.length === 0">
           Sie sind angemeldet. Aktuell sind keine Testgruppen zur Überwachung für Sie freigegeben.
         </p>
+        <p style="color: chocolate"><b>{{ problemText }}</b></p>
         <button mat-raised-button color="primary" (click)="buttonGotoMonitor(accessObject)"
-                *ngFor="let accessObject of accessObjects">
-          {{accessObject.name}}
+                *ngFor="let accessObject of accessObjects[AuthAccessKeyType.TEST_GROUP_MONITOR]">
+          <span class="booklet_title">{{accessObject.name}}</span>
+          <span class="booklet_status">Ãœberwachung starten</span>
+        </button>
+        <br>
+        <h4>Folgende Testhefte stehen für Sie zur Ansicht bereit:</h4>
+        <button mat-raised-button color="primary" (click)="startTest(b)" [disabled]="b.locked"
+                *ngFor="let b of accessObjects[AuthAccessKeyType.TEST]">
+          <span class="booklet_title">{{b.label}}</span>
+          <span class="booklet_status">{{b.locked ? 'gesperrt' : (b.running ? 'Fortsetzen' : 'Ansehen')}}</span>
         </button>
       </div>
     </mat-card-content>
diff --git a/src/app/app-root/monitor-starter/monitor-starter.component.ts b/src/app/app-root/monitor-starter/monitor-starter.component.ts
index 3a9fbc9f..06f80035 100644
--- a/src/app/app-root/monitor-starter/monitor-starter.component.ts
+++ b/src/app/app-root/monitor-starter/monitor-starter.component.ts
@@ -1,25 +1,21 @@
-import { Component, OnDestroy, OnInit } from '@angular/core';
-import { from, Subscription } from 'rxjs';
-import { Router } from '@angular/router';
-import { concatMap } from 'rxjs/operators';
-import { CustomtextService } from 'iqb-components';
-import { BackendService } from '../../backend.service';
-import { MainDataService } from '../../maindata.service';
-import {
-  AccessObject, AuthAccessKeyType, AuthData, WorkspaceData
-} from '../../app.interfaces';
+import {Component, OnDestroy, OnInit} from '@angular/core';
+import {from, Subscription} from 'rxjs';
+import {Router} from '@angular/router';
+import {concatMap, map} from 'rxjs/operators';
+import {CustomtextService} from 'iqb-components';
+import {BackendService} from '../../backend.service';
+import {MainDataService} from '../../maindata.service';
+import {AccessObject, AuthAccessKeyType, AuthData, BookletData} from '../../app.interfaces';
 
 @Component({
   templateUrl: './monitor-starter.component.html',
-  styles: [
-    'mat-card {margin: 10px;}',
-    '.mat-card-gray {background-color: lightgray}'
-  ]
+  styleUrls: ['./monitor-starter.component.css']
 })
 export class MonitorStarterComponent implements OnInit, OnDestroy {
-  accessObjects: (WorkspaceData|AccessObject)[] = [];
-
-  private getWorkspaceDataSubscription: Subscription = null;
+  accessObjects: {[accessType: string]: (AccessObject|BookletData)[]} = {};
+  private getMonitorDataSubscription: Subscription = null;
+  public AuthAccessKeyType = AuthAccessKeyType;
+  public problemText: string;
 
   constructor(
     private router: Router,
@@ -32,51 +28,74 @@ export class MonitorStarterComponent implements OnInit, OnDestroy {
     setTimeout(() => {
       this.mds.setSpinnerOn();
       this.bs.getSessionData().subscribe((authDataUntyped) => {
-        if (typeof authDataUntyped !== 'number') {
-          const authData = authDataUntyped as AuthData;
-          if (authData) {
-            if (authData.token) {
-              this.accessObjects = [];
-              let scopeIdList = [];
-              if (authData.access[AuthAccessKeyType.TEST_GROUP_MONITOR]) {
-                scopeIdList = authData.access[AuthAccessKeyType.TEST_GROUP_MONITOR];
-              }
-              if (this.getWorkspaceDataSubscription !== null) {
-                this.getWorkspaceDataSubscription.unsubscribe();
-              }
-              this.getWorkspaceDataSubscription = from(scopeIdList).pipe(
-                concatMap((monitorScopeId) => {
-                  let functionReturn = null;
-                  if (authData.access[AuthAccessKeyType.TEST_GROUP_MONITOR]) {
-                    functionReturn = this.bs.getGroupData(monitorScopeId);
-                  }
-                  return functionReturn;
-                })
-              ).subscribe(
-                (wsData: AccessObject) => {
-                  if (wsData) {
-                    this.accessObjects.push(wsData);
-                  }
-                },
-                () => this.mds.setSpinnerOff(),
-                () => this.mds.setSpinnerOff()
-              );
-              this.mds.setAuthData(authData);
-            } else {
-              this.mds.setAuthData();
-              this.mds.setSpinnerOff();
-            }
-          } else {
-            this.mds.setAuthData();
-            this.mds.setSpinnerOff();
-          }
-        } else {
+        if (typeof authDataUntyped === 'number') {
           this.mds.setSpinnerOff();
+          return;
+        }
+        const authData = authDataUntyped as AuthData;
+        if (!authData || !authData.token) {
+          this.mds.setAuthData();
+          this.mds.setSpinnerOff();
+          return;
+        }
+        this.accessObjects = {};
+
+        let scopeIdList: {[id: string]: {id: string, type: AuthAccessKeyType}} = {};
+        [AuthAccessKeyType.TEST_GROUP_MONITOR, AuthAccessKeyType.TEST]
+            .forEach(accessType => {
+              this.accessObjects[accessType] = [];
+              (authData.access[accessType] || [])
+                .forEach(accessObjectId => {
+                  scopeIdList[accessObjectId] = {id: accessObjectId, type: accessType};
+                });
+            });
+
+        if (this.getMonitorDataSubscription !== null) {
+          this.getMonitorDataSubscription.unsubscribe();
         }
+
+        this.getMonitorDataSubscription =
+          from(Object.keys(scopeIdList))
+            .pipe(
+              map((accessType: AuthAccessKeyType) => scopeIdList[accessType]),
+              concatMap((accessIdAndType) => {
+                if (accessIdAndType.type === AuthAccessKeyType.TEST_GROUP_MONITOR) {
+                  return this.bs.getGroupData(accessIdAndType.id);
+                } else if (authData.access[AuthAccessKeyType.TEST]) {
+                  return this.bs.getBookletData(accessIdAndType.id);
+                }
+              })
+            )
+            .subscribe(
+          (wsData: AccessObject) => {
+              if (wsData) {
+                this.accessObjects[scopeIdList[wsData.id].type].push(wsData);
+              }
+            },
+          () => this.mds.setSpinnerOff(),
+          () => this.mds.setSpinnerOff()
+          );
+
+        this.mds.setAuthData(authData);
       });
     });
   }
 
+  startTest(b: BookletData) {
+    this.bs.startTest(b.id).subscribe(testId => {
+      if (typeof testId === 'number') {
+        const errCode = testId as number;
+        if (errCode === 423) {
+          this.problemText = 'Dieser Test ist gesperrt';
+        } else {
+          this.problemText = `Problem beim Start (${errCode})`;
+        }
+      } else {
+        this.router.navigate(['/t', testId]);
+      }
+    });
+  }
+
   buttonGotoMonitor(accessObject: AccessObject): void {
     this.router.navigateByUrl(`/gm/${accessObject.id.toString()}`);
   }
@@ -87,8 +106,8 @@ export class MonitorStarterComponent implements OnInit, OnDestroy {
   }
 
   ngOnDestroy(): void {
-    if (this.getWorkspaceDataSubscription !== null) {
-      this.getWorkspaceDataSubscription.unsubscribe();
+    if (this.getMonitorDataSubscription !== null) {
+      this.getMonitorDataSubscription.unsubscribe();
     }
   }
 }
diff --git a/src/app/app-route-guards.ts b/src/app/app-route-guards.ts
index 00f10309..630b10d0 100644
--- a/src/app/app-route-guards.ts
+++ b/src/app/app-route-guards.ts
@@ -25,10 +25,10 @@ export class RouteDispatcherActivateGuard implements CanActivate {
           this.router.navigate(['/r/admin-starter']);
         } else if (authData.flags.indexOf(AuthFlagType.CODE_REQUIRED) >= 0) {
           this.router.navigate(['/r/code-input']);
-        } else if (authData.access[AuthAccessKeyType.TEST]) {
-          this.router.navigate(['/r/test-starter']);
         } else if (authData.access[AuthAccessKeyType.TEST_GROUP_MONITOR]) {
           this.router.navigate(['/r/monitor-starter']);
+        } else if (authData.access[AuthAccessKeyType.TEST]) {
+          this.router.navigate(['/r/test-starter']);
         } else {
           this.router.navigate(['/r/login', '']);
         }
diff --git a/src/app/config/test-mode.ts b/src/app/config/test-mode.ts
index b61f3f08..a821d65c 100644
--- a/src/app/config/test-mode.ts
+++ b/src/app/config/test-mode.ts
@@ -17,7 +17,7 @@ export class TestMode {
 
 	public constructor (loginMode: string = 'DEMO') {
 		if (loginMode) {
-			const regExPattern = /(DEMO|HOT|REVIEW|TRIAL)/;
+			const regExPattern = /(DEMO|MONITOR-GROUP|HOT|REVIEW|TRIAL)/;
 			if (regExPattern.test(loginMode.toUpperCase())) {
 				const mode = loginMode.toUpperCase().match(regExPattern)[0];
 				const modeConfig = testModes[mode];
diff --git a/src/app/config/test-modes.json b/src/app/config/test-modes.json
index b5d80d9e..fc64f7fe 100644
--- a/src/app/config/test-modes.json
+++ b/src/app/config/test-modes.json
@@ -11,6 +11,18 @@
       "showUnitMenu": false
     }
   },
+  "MONITOR-GROUP": {
+    "label": "Testgruppen-Monitor (Demo)",
+    "config": {
+      "canReview": false,
+      "saveResponses": false,
+      "forceTimeRestrictions": false,
+      "forceNaviRestrictions": false,
+      "presetCode": true,
+      "showTimeLeft": true,
+      "showUnitMenu": false
+    }
+  },
   "HOT": {
     "label": "Durchführung Test/Befragung",
     "config": {
-- 
GitLab