From a9c5f1b110a0f10cfe72cbc8106efdc012927755 Mon Sep 17 00:00:00 2001
From: mechtelm <nicht@mehr.fragen>
Date: Fri, 28 May 2021 14:10:25 +0200
Subject: [PATCH] Introduce new appConfig fields

Logo flexible; move some main.dataservice infos into appConfig; new appConfig data: html, warning etc.
---
 src/app/app-root/login/login.component.html   |  4 +-
 .../status-card/status-card.component.html    | 10 +-
 .../status-card/status-card.component.ts      |  1 -
 src/app/app.component.html                    |  2 +-
 src/app/app.component.ts                      | 64 +++----------
 src/app/app.interceptor.ts                    |  2 +-
 src/app/config/app.config.ts                  | 96 +++++++++++++++++--
 src/app/maindata.service.ts                   | 23 +----
 8 files changed, 115 insertions(+), 87 deletions(-)

diff --git a/src/app/app-root/login/login.component.html b/src/app/app-root/login/login.component.html
index 6b5c3d2f..aeddb266 100644
--- a/src/app/app-root/login/login.component.html
+++ b/src/app/app-root/login/login.component.html
@@ -1,7 +1,7 @@
 <div fxLayout="row wrap" fxLayoutAlign="center stretch">
   <mat-card fxFlex="0 0 400px">
     <mat-card-title>Anmelden</mat-card-title>
-    <form [formGroup]="loginForm" (ngSubmit)="login()" *ngIf="mds.isApiValid">
+    <form [formGroup]="loginForm" (ngSubmit)="login()" *ngIf="mds.appConfig?.isValidApiVersion">
       <mat-card-content fxLayout="column">
         <mat-form-field>
           <input matInput formControlName="name" placeholder="Anmeldename" (keyup.enter)="pw.focus()">
@@ -22,7 +22,7 @@
       </mat-card-actions>
     </form>
     <p style="color: chocolate"><b>{{ problemText }}</b></p>
-    <p style="color: chocolate" *ngIf="!mds.isApiValid"><b>Die Verbindung mit dem Server ist nicht möglich.</b></p>
+    <p style="color: chocolate" *ngIf="!mds.appConfig?.isValidApiVersion"><b>Die Verbindung mit dem Server ist nicht möglich.</b></p>
     <alert *ngIf="systemAnnouncement !== '-'" level="warning" [text]="systemAnnouncement"></alert>
   </mat-card>
 
diff --git a/src/app/app-root/status-card/status-card.component.html b/src/app/app-root/status-card/status-card.component.html
index 14dd57b6..f638168c 100644
--- a/src/app/app-root/status-card/status-card.component.html
+++ b/src/app/app-root/status-card/status-card.component.html
@@ -14,11 +14,11 @@
   <ul style="margin: 0;">
     <li *ngIf="!isProductionMode">Build-Modus: Dev</li>
     <li>Version {{appVersion}}</li>
-    <li>API: Version {{mds.apiVersion}}, {{apiVersionExpected}} erforderlich</li>
-    <li>Broadcasting-Service: {{mds.broadcastingServiceInfo.status}}
-      <span *ngIf="mds.broadcastingServiceInfo.version">
-        - Version {{mds.broadcastingServiceInfo.version}},
-        {{mds.broadcastingServiceInfo.versionExpected}} erforderlich
+    <li>API: Version {{mds.appConfig?.detectedApiVersion}}, {{mds.expectedApiVersion}} erforderlich</li>
+    <li>Broadcasting-Service: {{mds.appConfig?.broadcastingService.status}}
+      <span *ngIf="mds.appConfig?.broadcastingService.version">
+        - Version {{mds.appConfig?.broadcastingService.version}},
+        {{mds.appConfig?.broadcastingService.versionExpected}} erforderlich
       </span>
     </li>
     <li>Verona Player Interface: Version {{veronaApiVersionSupported}}</li>
diff --git a/src/app/app-root/status-card/status-card.component.ts b/src/app/app-root/status-card/status-card.component.ts
index 81d56d6a..8f1a459c 100644
--- a/src/app/app-root/status-card/status-card.component.ts
+++ b/src/app/app-root/status-card/status-card.component.ts
@@ -14,7 +14,6 @@ export class StatusCardComponent implements OnInit {
     @Inject('APP_NAME') public appName: string,
     @Inject('APP_PUBLISHER') public appPublisher: string,
     @Inject('APP_VERSION') public appVersion: string,
-    @Inject('API_VERSION_EXPECTED') public apiVersionExpected: string,
     @Inject('VERONA_API_VERSION_SUPPORTED') public veronaApiVersionSupported: string,
     @Inject('IS_PRODUCTION_MODE') public isProductionMode: boolean,
     public mds: MainDataService
diff --git a/src/app/app.component.html b/src/app/app.component.html
index bbcf9e37..e3190250 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,6 +1,6 @@
 <div class="logo">
   <a [routerLink]="['/']">
-    <img src="assets/IQB-LogoA.png" matTooltip="Zur Startseite" alt="IQB-logo"/>
+    <img [src]="mds.appConfig?.mainLogo" matTooltip="Zur Startseite" alt="IQB-logo"/>
   </a>
 </div>
 
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 9d87de3a..79bfba9a 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,11 +1,13 @@
 import {
-  Component, Inject, OnDestroy, OnInit
+  Component, OnDestroy, OnInit
 } from '@angular/core';
 import { Subscription } from 'rxjs';
 import { CustomtextService } from 'iqb-components';
+import { DomSanitizer } from '@angular/platform-browser';
 import { MainDataService } from './maindata.service';
 import { BackendService } from './backend.service';
 import { AppError } from './app.interfaces';
+import { AppConfig } from './config/app.config';
 
 @Component({
   selector: 'tc-root',
@@ -14,7 +16,6 @@ import { AppError } from './app.interfaces';
 
 export class AppComponent implements OnInit, OnDestroy {
   private appErrorSubscription: Subscription = null;
-
   showError = false;
 
   errorData: AppError;
@@ -23,49 +24,15 @@ export class AppComponent implements OnInit, OnDestroy {
     public mds: MainDataService,
     private bs: BackendService,
     private cts: CustomtextService,
-    @Inject('API_VERSION_EXPECTED') private readonly expectedApiVersion: string
+    private sanitizer: DomSanitizer
   ) { }
 
-  private static isValidVersion(expectedVersion: string, reportedVersion: string): boolean {
-    if (expectedVersion) {
-      const searchPattern = /\d+/g;
-      const expectedVersionNumbers = expectedVersion.match(searchPattern);
-      if (expectedVersionNumbers) {
-        if (reportedVersion) {
-          const reportedVersionNumbers = reportedVersion.match(searchPattern);
-          if (reportedVersionNumbers) {
-            if (reportedVersionNumbers[0] !== expectedVersionNumbers[0]) {
-              return false;
-            }
-            if (expectedVersionNumbers.length > 1) {
-              if ((reportedVersionNumbers.length < 2) || +reportedVersionNumbers[1] < +expectedVersionNumbers[1]) {
-                return false;
-              }
-              if ((expectedVersionNumbers.length > 2) && reportedVersionNumbers[1] === expectedVersionNumbers[1]) {
-                if ((reportedVersionNumbers.length < 3) || +reportedVersionNumbers[2] < +expectedVersionNumbers[2]) {
-                  return false;
-                }
-              }
-            }
-          } else {
-            return false;
-          }
-        } else {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
   closeErrorBox(): void {
     this.showError = false;
   }
 
   ngOnInit(): void {
     setTimeout(() => {
-      this.mds.appConfig.setDefaultCustomTexts();
-
       this.appErrorSubscription = this.mds.appError$.subscribe(err => {
         if (err && !this.mds.errorReportingSilent) {
           this.errorData = err;
@@ -86,33 +53,28 @@ export class AppComponent implements OnInit, OnDestroy {
       this.setupFocusListeners();
 
       this.bs.getSysConfig().subscribe(sysConfig => {
+        this.mds.appConfig = new AppConfig(sysConfig, this.cts, this.mds.expectedApiVersion, this.sanitizer);
         if (!sysConfig) {
-          this.mds.isApiValid = false; // push on this.mds.appError$ ?
+          this.mds.appError$.next({
+            label: 'Server-Problem: Konnte Konfiguration nicht laden',
+            description: 'getSysConfig ist fehlgeschlagen',
+            category: 'FATAL'
+          });
           return;
         }
-        this.cts.addCustomTexts(sysConfig.customTexts);
         const authData = MainDataService.getAuthData();
         if (authData) {
           this.cts.addCustomTexts(authData.customTexts);
         }
 
-        if (sysConfig.broadcastingService && sysConfig.broadcastingService.status) {
-          this.mds.broadcastingServiceInfo = sysConfig.broadcastingService;
-        }
-        this.mds.isApiValid = AppComponent.isValidVersion(this.expectedApiVersion, sysConfig.version);
-        this.mds.apiVersion = sysConfig.version;
-
-        if (!this.mds.isApiValid) {
+        if (!this.mds.appConfig.isValidApiVersion) {
           this.mds.appError$.next({
             label: 'Server-Problem: API-Version ungültig',
-            description: `erwartet: ${this.expectedApiVersion}, gefunden: ${sysConfig.version}`,
+            description:
+              `erwartet: ${this.mds.expectedApiVersion}, gefunden: ${this.mds.appConfig.detectedApiVersion}`,
             category: 'FATAL'
           });
         }
-
-        // TODO implement SysConfig.mainLogo
-
-        this.mds.setTestConfig(sysConfig.testConfig);
       });
 
       this.bs.getSysCheckInfo().subscribe(sysCheckConfigs => {
diff --git a/src/app/app.interceptor.ts b/src/app/app.interceptor.ts
index 74713da0..79e1e1bb 100644
--- a/src/app/app.interceptor.ts
+++ b/src/app/app.interceptor.ts
@@ -19,7 +19,7 @@ export class AuthInterceptor implements HttpInterceptor {
   // TODO separation of concerns: split into two interceptors,
   // one for error handling, one for auth token addition
   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
-    if (this.mds.isApiValid) {
+    if (!this.mds.appConfig || this.mds.appConfig.isValidApiVersion) {
       let tokenStr = '';
       const authData = MainDataService.getAuthData();
       if (authData) {
diff --git a/src/app/config/app.config.ts b/src/app/config/app.config.ts
index c33ec354..85e821de 100644
--- a/src/app/config/app.config.ts
+++ b/src/app/config/app.config.ts
@@ -1,4 +1,5 @@
 import { CustomtextService } from 'iqb-components';
+import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
 import customTextsDefault from './custom-texts.json';
 import { KeyValuePairs } from '../app.interfaces';
 
@@ -9,6 +10,13 @@ export interface SysConfig {
   testConfig: KeyValuePairs;
   serverTimestamp: number;
   broadcastingService: BroadCastingServiceInfo;
+  app_title: string;
+  background_color: string;
+  intro_html: string;
+  impressum_html: string;
+  global_warning: string;
+  global_warning_expired_day: Date;
+  global_warning_expired_hour: number;
 }
 
 export interface BroadCastingServiceInfo {
@@ -17,17 +25,91 @@ export interface BroadCastingServiceInfo {
   versionExpected?: string;
 }
 
+export const localStorageTestConfigKey = 'iqb-tc-c';
+
 export class AppConfig {
+  customTexts: KeyValuePairs = {};
+  detectedApiVersion = '';
+  mainLogo = 'assets/IQB-LogoA.png';
+  testConfig: KeyValuePairs = {};
+  serverTimestamp = 0;
+  broadcastingService: BroadCastingServiceInfo = { status: 'none' };
+  app_title = 'IQB-Testcenter';
+  background_color: string;
+  intro_html = 'Einführungstext nicht definiert';
+  trusted_intro_html: SafeUrl = null;
+  impressum_html = 'Impressum/Datenschutz nicht definiert';
+  trusted_impressum_html: SafeUrl = null;
+  global_warning = '';
+  global_warning_expired_day: Date;
+  global_warning_expired_hour: number;
+  isValidApiVersion = false;
+
   constructor(
-    private cts: CustomtextService
+    sysConfig: SysConfig,
+    cts: CustomtextService,
+    expectedApiVersion: string,
+    sanitizer: DomSanitizer
   ) {
+    const ctSettings = {};
+    Object.keys(customTextsDefault).forEach(k => {
+      ctSettings[k] = customTextsDefault[k].defaultvalue;
+      if (k === 'app_title') this.app_title = customTextsDefault[k].defaultvalue;
+    });
+    if (sysConfig) {
+      Object.keys(sysConfig.customTexts).forEach(k => {
+        ctSettings[k] = sysConfig.customTexts[k];
+        if (k === 'app_title') this.app_title = sysConfig.customTexts[k];
+      });
+      if (sysConfig.app_title) this.app_title = sysConfig.app_title;
+      if (sysConfig.mainLogo) this.mainLogo = sysConfig.mainLogo;
+      this.background_color = sysConfig.background_color;
+      this.isValidApiVersion = AppConfig.checkApiVersion(sysConfig.version, expectedApiVersion);
+      this.detectedApiVersion = sysConfig.version;
+      if (sysConfig.intro_html) this.intro_html = sysConfig.intro_html;
+      if (sysConfig.impressum_html) this.impressum_html = sysConfig.impressum_html;
+      this.global_warning = sysConfig.global_warning;
+      this.global_warning_expired_day = sysConfig.global_warning_expired_day;
+      this.global_warning_expired_hour = sysConfig.global_warning_expired_hour;
+      this.testConfig = sysConfig.testConfig;
+      this.serverTimestamp = sysConfig.serverTimestamp;
+      if (sysConfig.broadcastingService && sysConfig.broadcastingService.status) {
+        this.broadcastingService = sysConfig.broadcastingService;
+      }
+    }
+    cts.addCustomTexts(ctSettings);
+    this.trusted_intro_html = sanitizer.bypassSecurityTrustHtml(this.intro_html);
+    this.trusted_impressum_html = sanitizer.bypassSecurityTrustHtml(this.impressum_html);
+    if (this.testConfig) {
+      localStorage.setItem(localStorageTestConfigKey, JSON.stringify(this.testConfig));
+    } else {
+      localStorage.removeItem(localStorageTestConfigKey);
+    }
   }
 
-  setDefaultCustomTexts(): void {
-    const ctDefaults = {};
-    Object.keys(customTextsDefault).forEach(key => {
-      ctDefaults[key] = customTextsDefault[key].defaultvalue;
-    });
-    this.cts.addCustomTexts(ctDefaults);
+  private static checkApiVersion(versionToCheck: string, expectedVersion: string): boolean {
+    if (!expectedVersion || !versionToCheck) {
+      return false;
+    }
+    const searchPattern = /\d+/g;
+    const expectedVersionNumbers = expectedVersion.match(searchPattern);
+    const reportedVersionNumbers = versionToCheck.match(searchPattern);
+    if (expectedVersionNumbers && reportedVersionNumbers) {
+      if (reportedVersionNumbers[0] !== expectedVersionNumbers[0]) {
+        return false;
+      }
+      if (expectedVersionNumbers.length > 1) {
+        if ((reportedVersionNumbers.length < 2) || +reportedVersionNumbers[1] < +expectedVersionNumbers[1]) {
+          return false;
+        }
+        if ((expectedVersionNumbers.length > 2) && reportedVersionNumbers[1] === expectedVersionNumbers[1]) {
+          if ((reportedVersionNumbers.length < 3) || +reportedVersionNumbers[2] < +expectedVersionNumbers[2]) {
+            return false;
+          }
+        }
+      }
+      return true;
+    }
+    return false;
   }
 }
diff --git a/src/app/maindata.service.ts b/src/app/maindata.service.ts
index 6d5c7f31..86199785 100644
--- a/src/app/maindata.service.ts
+++ b/src/app/maindata.service.ts
@@ -1,15 +1,13 @@
-import { Injectable } from '@angular/core';
+import { Inject, Injectable } from '@angular/core';
 import { BehaviorSubject, Subject } from 'rxjs';
 import { CustomtextService } from 'iqb-components';
 import {
   AppError,
   AuthData, KeyValuePairs
 } from './app.interfaces';
-import { BackendService } from './backend.service';
-import { AppConfig, BroadCastingServiceInfo } from './config/app.config';
+import { AppConfig, localStorageTestConfigKey } from './config/app.config';
 
 const localStorageAuthDataKey = 'iqb-tc-a';
-const localStorageTestConfigKey = 'iqb-tc-c';
 
 @Injectable({
   providedIn: 'root'
@@ -20,9 +18,6 @@ export class MainDataService {
   errorReportingSilent = false;
   isSpinnerOn$ = new BehaviorSubject<boolean>(false);
   progressVisualEnabled = true;
-  isApiValid = true;
-  apiVersion: string;
-  broadcastingServiceInfo: BroadCastingServiceInfo = { status: 'none' };
   appConfig: AppConfig = null;
   sysCheckAvailable = false;
 
@@ -74,11 +69,9 @@ export class MainDataService {
   }
 
   constructor(
-    private bs: BackendService,
+    @Inject('API_VERSION_EXPECTED') readonly expectedApiVersion: string,
     private cts: CustomtextService
-  ) {
-    this.appConfig = new AppConfig(cts);
-  }
+  ) { }
 
   setSpinnerOn(): void {
     this.isSpinnerOn$.next(true);
@@ -98,12 +91,4 @@ export class MainDataService {
       localStorage.removeItem(localStorageAuthDataKey);
     }
   }
-
-  setTestConfig(testConfig: KeyValuePairs = null): void {
-    if (testConfig) {
-      localStorage.setItem(localStorageTestConfigKey, JSON.stringify(testConfig));
-    } else {
-      localStorage.removeItem(localStorageTestConfigKey);
-    }
-  }
 }
-- 
GitLab