diff --git a/src/app/app-root/admin-starter/admin-starter.component.html b/src/app/app-root/admin-starter/admin-starter.component.html index fce919ea22ba017d1904748ca6cffd48a95467e8..30ec80d4d98cc0177a8a6e772312330f66b6c117 100644 --- a/src/app/app-root/admin-starter/admin-starter.component.html +++ b/src/app/app-root/admin-starter/admin-starter.component.html @@ -2,7 +2,7 @@ <mat-card-title>Verwaltung: Bitte Studie wählen</mat-card-title> <mat-card-content> <div fxLayoutGap="10px" fxLayout="column"> - <p *ngIf="(mds.loginData$ | async)?.workspaces.length === 0"> + <p *ngIf="workspaces.length === 0"> Sie sind mit Administrator-Funktionen angemeldet. Aktuell sind keine Studien für Sie freigegeben. </p> <button mat-raised-button color="primary" (click)="buttonGotoWorkspaceAdmin(ws)" @@ -12,7 +12,7 @@ </div> </mat-card-content> <mat-card-actions> - <button mat-raised-button color="foreground" *ngIf="mds.isSuperAdmin" [routerLink]="['/superadmin']">System-Admin</button> + <button mat-raised-button color="foreground" *ngIf="isSuperAdmin" [routerLink]="['/superadmin']">System-Admin</button> <button mat-raised-button color="foreground" (click)="resetLogin()">Neu anmelden</button> </mat-card-actions> </mat-card> diff --git a/src/app/app-root/admin-starter/admin-starter.component.ts b/src/app/app-root/admin-starter/admin-starter.component.ts index 956f5d60dae1be4de4e54cce6a9799fba6e79ffd..6e085e84b0341db773a34523b4065c4ed35dd6c3 100644 --- a/src/app/app-root/admin-starter/admin-starter.component.ts +++ b/src/app/app-root/admin-starter/admin-starter.component.ts @@ -1,33 +1,54 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnDestroy, OnInit} from '@angular/core'; import {MainDataService} from "../../maindata.service"; import {Router} from "@angular/router"; +import {AuthAccessKeyType, AuthData, WorkspaceData} from "../../app.interfaces"; +import {from, Subscription} from "rxjs"; +import {concatMap} from "rxjs/operators"; +import {BackendService} from "../../backend.service"; -interface WorkspaceData { - id: string; - name: string; -} @Component({ templateUrl: './admin-starter.component.html', }) -export class AdminStarterComponent implements OnInit { +export class AdminStarterComponent implements OnInit, OnDestroy { workspaces: WorkspaceData[] = []; isSuperAdmin = false; + private getWorkspaceDataSubscription: Subscription = null; constructor( private router: Router, - public mds: MainDataService + private bs: BackendService, + private mds: MainDataService ) { } ngOnInit() { - const workspaces = this.mds.workspaces; - for (let wsId of Object.keys(workspaces)) { - this.workspaces.push({ - id: wsId, - name: workspaces[wsId], + setTimeout(() => { + this.bs.getSessionData().subscribe(authDataUntyped => { + if (typeof authDataUntyped !== 'number') { + const authData = authDataUntyped as AuthData; + if (authData) { + if (authData.token) { + if (authData.access[AuthAccessKeyType.SUPER_ADMIN]) { + this.isSuperAdmin = true; + } + if (authData.access[AuthAccessKeyType.WORKSPACE_ADMIN]) { + this.workspaces = []; + this.getWorkspaceDataSubscription = from(authData.access[AuthAccessKeyType.WORKSPACE_ADMIN]).pipe( + concatMap(workspaceId => { + return this.bs.getWorkspaceData(workspaceId) + })).subscribe(wsData => this.workspaces.push(wsData)); + } + this.mds.setAuthData(authData); + } else { + this.mds.setAuthData(); + } + } else { + this.mds.setAuthData(); + } + } }) - } + }); } buttonGotoWorkspaceAdmin(ws: WorkspaceData) { @@ -38,4 +59,10 @@ export class AdminStarterComponent implements OnInit { this.mds.setAuthData(); this.router.navigate(['/']); } + + ngOnDestroy() { + if (this.getWorkspaceDataSubscription !== null) { + this.getWorkspaceDataSubscription.unsubscribe(); + } + } } diff --git a/src/app/app-root/app-root.component.ts b/src/app/app-root/app-root.component.ts index 85788888416013d2f6d5605207886a58081be30e..c8693a53b55fb751eb5d2bf7309d7fcd3fb642c9 100644 --- a/src/app/app-root/app-root.component.ts +++ b/src/app/app-root/app-root.component.ts @@ -8,23 +8,4 @@ import {Component} from '@angular/core'; styles: ['.root-frame {padding: 80px;}'] }) export class AppRootComponent { -/* - constructor( - public mds: MainDataService, - private router: Router, - private route: ActivatedRoute - ) { } - - ngOnInit(): void { - const loginData = this.mds.loginData$.getValue(); - if (loginData.adminToken.length > 0) { - this.router.navigate(['./admin-starter'], {relativeTo: this.route}); - } else if (loginData.loginToken.length > 0) { - this.router.navigate(['./code-input'], {relativeTo: this.route}); - } else if (loginData.personToken.length > 0) { - this.router.navigate(['./test-starter'], {relativeTo: this.route}); - } else { - this.router.navigate(['./login'], {relativeTo: this.route}); - } - } */ } diff --git a/src/app/app-root/login/login.component.html b/src/app/app-root/login/login.component.html index 2f35c0698a2427fdbe95081469f53c3382fd21cf..a40024f8e825b3861fa21dec8c0bf2d46fd958d3 100644 --- a/src/app/app-root/login/login.component.html +++ b/src/app/app-root/login/login.component.html @@ -8,8 +8,9 @@ <input matInput formControlName="name" placeholder="Anmeldename" (keyup.enter)="pw.focus()"> </mat-form-field> <mat-form-field> - <input matInput #pw type="password" formControlName="pw" placeholder="Kennwort" (keyup.enter)="login()"> + <input matInput #pw type="password" formControlName="pw" placeholder="Kennwort"> </mat-form-field> + <p>{{ problemText }}</p> </mat-card-content> <mat-card-actions> <button mat-raised-button type="submit" [disabled]="loginForm.invalid" color="primary">Weiter</button> diff --git a/src/app/app-root/login/login.component.ts b/src/app/app-root/login/login.component.ts index 4516aa0170d509d1881f4e34d0ad8ea09fd10180..fd82b80adf5677d55145f7baa4fcb4e21cb6cb05 100644 --- a/src/app/app-root/login/login.component.ts +++ b/src/app/app-root/login/login.component.ts @@ -1,11 +1,10 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; import {FormControl, FormGroup, Validators} from "@angular/forms"; import {MainDataService} from "../../maindata.service"; -import {CustomtextService, ServerError} from "iqb-components"; +import {CustomtextService} from "iqb-components"; import {ActivatedRoute, Router} from "@angular/router"; import {Subscription} from "rxjs"; -import {appconfig} from "../../app.config"; -import {LoginData} from "../../app.interfaces"; +import {AuthData} from "../../app.interfaces"; import {BackendService} from "../../backend.service"; @Component({ @@ -19,6 +18,7 @@ export class LoginComponent implements OnInit, OnDestroy { private routingSubscription: Subscription = null; static oldLoginName = ''; returnTo = ''; + problemText = ''; loginForm = new FormGroup({ name: new FormControl(LoginComponent.oldLoginName, [Validators.required, Validators.minLength(3)]), @@ -42,41 +42,30 @@ export class LoginComponent implements OnInit, OnDestroy { login() { const loginData = this.loginForm.value; LoginComponent.oldLoginName = loginData['name']; + console.log('###'); this.bs.login(loginData['name'], loginData['pw']).subscribe( - loginData => { - if (loginData instanceof ServerError) { - const e = loginData as ServerError; - if (e.code === 400) { - this.mds.appError$.next({ - label: 'Diese Anmeldedaten sind für diesen Server nicht gültig.', - description: e.labelSystem + ' (' + e.code.toString + ')', - category: "PROBLEM" - }); + authData => { + this.problemText = ''; + if (typeof authData === 'number') { + const errCode = authData as number; + if (errCode === 400) { + this.problemText = 'Anmeldungsdaten sind nicht gültig.'; + } else { + this.problemText = 'Problem bei der Anmeldung.'; + // app.interceptor will show error message } - this.mds.addCustomtextsFromDefList(appconfig.customtextsLogin); - // no change in other data } else { - if ((loginData as LoginData).customTexts) { - this.cts.addCustomTexts((loginData as LoginData).customTexts); + const authDataTyped = authData as AuthData; + if (authDataTyped.customTexts) { + this.cts.addCustomTexts(authDataTyped.customTexts); } - this.mds.setAuthData(loginData as LoginData); + this.mds.setAuthData(authDataTyped); if (this.returnTo) { this.router.navigateByUrl(this.returnTo); } else { - if (this.mds.adminToken) { - this.router.navigate(['/r/admin-starter']); - } else if (this.mds.loginToken) { - this.router.navigate(['/r/code-input']); - } else if (this.mds.personToken) { - this.router.navigate(['/r/test-starter']); - } else { - this.mds.appError$.next({ - label: 'Keine Berechtigung für diese Anmeldedaten gefunden.', - description: 'Request ohne Fehler, aber kein Token?!', - category: "PROBLEM" - }); - } + // let the app-root routing guard decide where to go to + this.router.navigate(['/r']); } } } diff --git a/src/app/app-routing-guards.ts b/src/app/app-routing-guards.ts index 55172a1d9a21cd26f5bd5c854b3221e905034b39..01e2b475a5d9d7500c3f6b4e06d4806807f5ac36 100644 --- a/src/app/app-routing-guards.ts +++ b/src/app/app-routing-guards.ts @@ -2,6 +2,7 @@ import {Injectable} from "@angular/core"; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router"; import {MainDataService} from "./maindata.service"; import {Observable} from "rxjs"; +import {AuthAccessKeyType, AuthFlagType} from "./app.interfaces"; @Injectable() export class RouteDispatcherActivateGuard implements CanActivate { @@ -15,15 +16,25 @@ export class RouteDispatcherActivateGuard implements CanActivate { next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { - if (this.mds.adminToken.length > 0) { - this.router.navigate(['/r/admin-starter']); - } else if (this.mds.personToken.length > 0) { - this.router.navigate(['/r/test-starter']); - } else if (this.mds.loginToken.length > 0) { - this.router.navigate(['/r/code-input']); + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.access[AuthAccessKeyType.WORKSPACE_ADMIN] || authData.access[AuthAccessKeyType.SUPER_ADMIN]) { + 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 { + this.router.navigate(['/r/login', '']); + } + } else { + this.router.navigate(['/r/login', '']); + } } else { this.router.navigate(['/r/login', '']); } + return false; } } diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index da8cc9f151eedab05449e2159eda247dbb6590d9..f23539104ce5b420d570beaaf62c3aae26ee0f6e 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,5 +1,4 @@ import { AboutComponent } from './app-root/about/about.component'; -import { StartComponent } from './start/start.component'; import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import {AppRootComponent} from "./app-root/app-root.component"; @@ -21,6 +20,7 @@ const routes: Routes = [ {path: 'r', component: AppRootComponent, children: [ {path: '', redirectTo: 'route-dispatcher', pathMatch: 'full'}, + {path: 'login', redirectTo: 'route-dispatcher', pathMatch: 'full'}, {path: 'login/:returnTo', component: LoginComponent}, {path: 'about', component: AboutComponent}, {path: 'check-starter', component: SysCheckStarterComponent}, @@ -30,7 +30,6 @@ const routes: Routes = [ {path: 'code-input', component: CodeInputComponent} ] }, - {path: 'start', component: StartComponent}, {path: 'about', component: AboutComponent}, {path: 'check', loadChildren: () => import('./sys-check/sys-check.module').then(m => m.SysCheckModule)}, {path: 'admin', loadChildren: () => import('./workspace-admin/workspace.module').then(m => m.WorkspaceModule)}, diff --git a/src/app/app.component.ts b/src/app/app.component.ts index cd6136fc5d81b7d0669a6d090eb1115fa6688d04..df2819cfa505ecc02376660baed3ac4be7ac6377 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -92,17 +92,20 @@ export class AppComponent implements OnInit, OnDestroy { if (sc) { this.mds.setDefaultCustomtexts(sc.customTexts); this.mds.isApiVersionValid = AppComponent.isValidVersion(this.expectedApiVersion, sc.version); - if (this.mds.isApiVersionValid) { - console.log("API ok (erwartet: " + this.expectedApiVersion + ", gefunden: " + sc.version + ")"); - } else { + if (!this.mds.isApiVersionValid) { this.mds.appError$.next({ label: "Server-Problem: API-Version ungültig", description: "erwartet: " + this.expectedApiVersion + ", gefunden: " + sc.version, - category: "PROBLEM" + category: "FATAL" }); } } else { this.mds.isApiVersionValid = false; + this.mds.appError$.next({ + label: "Allgemeines Server-Problem", + description: "getSysConfig lieferte null", + category: "FATAL" + }); } }); }); diff --git a/src/app/app.interceptor.ts b/src/app/app.interceptor.ts index 68d556e49bb63d12b6702f242fd9012b91991575..37618aa00d3d37a15059a14c0f0b6b393dfe066c 100644 --- a/src/app/app.interceptor.ts +++ b/src/app/app.interceptor.ts @@ -4,9 +4,10 @@ import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; -import {Observable, of} from 'rxjs'; +import {Observable, throwError} from 'rxjs'; import {catchError, tap} from "rxjs/operators"; import {Router, RouterState, RouterStateSnapshot} from "@angular/router"; +import {AuthAccessKeyType, AuthFlagType} from "./app.interfaces"; @Injectable() export class AuthInterceptor implements HttpInterceptor { @@ -16,21 +17,34 @@ export class AuthInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { if (!this.mds.isApiVersionValid) { - return of(null); + this.mds.appError$.next({ + label: "Server-Problem: API-Version ungültig", + description: "Keine weiteren Server-Aufrufe erlaubt", + category: "FATAL" + }); + return throwError(500); } // if (request.headers.get('AuthToken') !== null) { // return next.handle(request); // } + let tokenStr = ''; + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.access[AuthAccessKeyType.WORKSPACE_ADMIN] || authData.access[AuthAccessKeyType.SUPER_ADMIN]) { + tokenStr = authData.token; + } else if (authData.flags.indexOf(AuthFlagType.CODE_REQUIRED) >= 0) { + tokenStr = 'l:' + authData.token; + } else if (authData.access[AuthAccessKeyType.TEST]) { + tokenStr = 'p:' + authData.token; + } + } + } - const authData = { - l: this.mds.loginToken, - p: this.mds.personToken, - at: this.mds.adminToken - }; const requestA = request.clone({ setHeaders: { - AuthToken: JSON.stringify(authData) + AuthToken: tokenStr } }); @@ -38,15 +52,16 @@ export class AuthInterceptor implements HttpInterceptor { return next.handle(requestA).pipe( tap(requ => { // filter out OPTIONS request - if (requ.type > 0) { // TODO check the way to detect OPTION + if (requ.type > 0) { // TODO is there another way to detect OPTION? this.mds.decrementDelayedProcessesCount(); - console.log('äöüsl'); } }), catchError(e => { this.mds.decrementDelayedProcessesCount(); + let errorCode = 999; if (e instanceof HttpErrorResponse) { const httpError = e as HttpErrorResponse; + errorCode = httpError.status; if (httpError.error instanceof ErrorEvent) { this.mds.appError$.next({ label: 'Fehler in der Netzwerkverbindung', @@ -93,7 +108,7 @@ export class AuthInterceptor implements HttpInterceptor { } } - return of(e); + return throwError(errorCode); }) ) } diff --git a/src/app/app.interfaces.ts b/src/app/app.interfaces.ts index 000c661825b4308340d8299dd2bb94c6583e1d4f..d0a699a171bd94bc3108a18c91d87e26fe93f9f4 100644 --- a/src/app/app.interfaces.ts +++ b/src/app/app.interfaces.ts @@ -1,3 +1,35 @@ +export enum AuthFlagType { + CODE_REQUIRED = "codeRequired", + PENDING = "pending", + EXPIRED = "expired" +} + +export enum AuthAccessKeyType { + WORKSPACE_ADMIN = "workspaceAdmin", + SUPER_ADMIN = "superAdmin", + TEST = "test", + WORKSPACE_MONITOR = "workspaceMonitor", + TEST_GROUP_MONITOR = "testGroupMonitor" +} + +export interface AccessType { + [key: string]: string[]; +} + +export interface AuthData { + token: string; + displayName: string; + customTexts: KeyValuePairs; + flags: AuthFlagType[]; + access: AccessType; +} + +export interface WorkspaceData { + id: string; + name: string; + role: "RW" | "RO" | "n.d."; +} + export interface BookletData { id: string; filename: string; @@ -12,24 +44,6 @@ export interface BookletListByCode { [code: string]: string[]; } -export enum AuthType { - LOGIN = "LOGIN", - ADMIN = "ADMIN", - PERSON = "PERSON", - SUPERADMIN = "SUPERADMIN" -} - -export interface AccessRightList { - [key: string]: string; -} - -export interface AuthData { - token: string; - authTypes: AuthType[]; - displayName: string; - accessRights: AccessRightList; -} - export interface LoginData { loginToken: string; personToken: string; @@ -41,7 +55,7 @@ export interface LoginData { booklets: BookletListByCode; testId: number; bookletLabel: string; - customTexts: KeyValuePair; + customTexts: KeyValuePairs; adminToken: string; workspaces: WorkspaceData[]; isSuperadmin: boolean; @@ -61,11 +75,11 @@ export interface PersonTokenAndTestId { } export interface SysConfig { - customTexts: KeyValuePair; + customTexts: KeyValuePairs; version: string; } -export interface KeyValuePair { +export interface KeyValuePairs { [K: string]: string; } @@ -73,12 +87,6 @@ export interface KeyValuePairNumber { [K: string]: number; } -export interface WorkspaceData { - id: number; - name: string; - role: string; -} - export interface AppError { label: string; description: string; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 91ab28bf2b45fdc02f887cba8ee55c16803901cd..3ff9dff50346b0da2ab76035ca5674a1a712eca5 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,7 +8,6 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BackendService } from './backend.service'; -import { StartComponent } from './start/start.component'; import { LocationStrategy, HashLocationStrategy } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; import {AuthInterceptor} from './app.interceptor'; @@ -42,7 +41,6 @@ import { TestStarterComponent } from './app-root/test-starter/test-starter.compo @NgModule({ declarations: [ AppComponent, - StartComponent, AboutComponent, AppRootComponent, SysCheckStarterComponent, diff --git a/src/app/backend.service.ts b/src/app/backend.service.ts index 24d3624d103f05ae9c3beb26a02dc34e93b7a724..a168af7be96ab33512c9ad2391d0f44e3c3b3c2e 100644 --- a/src/app/backend.service.ts +++ b/src/app/backend.service.ts @@ -1,9 +1,17 @@ import { Injectable, Inject } from '@angular/core'; import {HttpClient, HttpParams} from '@angular/common/http'; -import { Observable, of } from 'rxjs'; +import {Observable, of} from 'rxjs'; import {catchError, switchMap} from 'rxjs/operators'; -import {LoginData, BookletStatus, PersonTokenAndTestId, SysConfig, SysCheckInfo} from './app.interfaces'; +import { + LoginData, + BookletStatus, + PersonTokenAndTestId, + SysConfig, + SysCheckInfo, + AuthData, + WorkspaceData +} from './app.interfaces'; import {ErrorHandler, ServerError} from 'iqb-components'; // ============================================================================ @@ -18,28 +26,48 @@ export class BackendService { ) {} - login(name: string, password: string): Observable<LoginData | ServerError> { - + login(name: string, password: string): Observable<AuthData | number> { return this.http - .put<LoginData>(this.serverUrl + 'session/admin', {name, password}) + .put<AuthData>(this.serverUrl + 'session/admin', {name, password}) .pipe( - catchError(ErrorHandler.handle), - switchMap(myLoginData => { - if (myLoginData instanceof ServerError) { - if ((myLoginData as ServerError).code === 401) { + catchError(errCode => of(errCode)), + switchMap(authData => { + if (typeof authData === 'number') { + const errCode = authData as number; + if (errCode === 400) { return this.http .put<LoginData>(this.serverUrl + 'session/login', {name, password}) - .pipe(catchError(ErrorHandler.handle)); + .pipe(catchError(errCode => of(errCode))); } else { - return of(myLoginData); + return of(errCode); } } else { - return of(myLoginData); + return of(authData); } }) ); } + getWorkspaceData(workspaceId: string): Observable<WorkspaceData> { + return this.http + .get<WorkspaceData>(this.serverUrl + 'workspace/' + workspaceId) + .pipe(catchError(() => { + console.warn('get workspace data failed for ' + workspaceId); + return of(<WorkspaceData>{ + id: workspaceId, + name: workspaceId, + role: "n.d." + }) + })); + } + + getSessionData(): Observable<AuthData | number> { + return this.http + .get<AuthData>(this.serverUrl + 'session') + .pipe( + catchError(errCode => of(errCode)) + ) + } getSession(loginToken: string, personToken: string): Observable<LoginData | ServerError> { diff --git a/src/app/maindata.service.ts b/src/app/maindata.service.ts index 1d059e09fbe76f0ab34134d272e9820e45461304..d17f3d916c79e0c4e31e048cdf705ea91a23333e 100644 --- a/src/app/maindata.service.ts +++ b/src/app/maindata.service.ts @@ -1,7 +1,11 @@ import {BackendService} from './backend.service'; import {BehaviorSubject, Subject} from 'rxjs'; import {Injectable} from '@angular/core'; -import {AccessRightList, AppError, AuthData, AuthType, LoginData} from './app.interfaces'; +import { + AppError, + AuthData, + LoginData +} from './app.interfaces'; import {CustomtextService, ServerError} from 'iqb-components'; import {appconfig, customtextKeySeparator, CustomTextsDefList} from './app.config'; @@ -12,26 +16,7 @@ const localStorageAuthDataKey = 'iqb-tc'; }) export class MainDataService { - private static get defaultLoginData(): LoginData { - return { - loginToken: '', - personToken: '', - mode: '', - groupName: '', - name: '', - workspaceName: '', - booklets: null, - code: '', - testId: 0, - bookletLabel: '', - customTexts: {}, - adminToken: '', - workspaces: [], - isSuperadmin: false - }; - } - - public loginData$ = new BehaviorSubject<LoginData>(MainDataService.defaultLoginData); + public loginData$ = new BehaviorSubject<LoginData>(null); public globalErrorMsg$ = new BehaviorSubject<ServerError>(null); // TODO remove globalErrorMsg$ public appError$ = new BehaviorSubject<AppError>(null); public delayedProcessesCount$ = new BehaviorSubject<number>(0); @@ -40,64 +25,7 @@ export class MainDataService { // set by app.component.ts public postMessage$ = new Subject<MessageEvent>(); - public get adminToken(): string { - const authData = MainDataService.getAuthDataFromLocalStorage(); - if (authData) { - if (authData.token) { - if (authData.authTypes.indexOf(AuthType.ADMIN) >= 0) { - return authData.token; - } - } - } - return ''; - } - public get isSuperAdmin(): boolean { - const authData = MainDataService.getAuthDataFromLocalStorage(); - if (authData) { - if (authData.token) { - if (authData.authTypes.indexOf(AuthType.SUPERADMIN) >= 0) { - return true; - } - } - } - return false; - } - public get loginToken(): string { - const authData = MainDataService.getAuthDataFromLocalStorage(); - if (authData) { - if (authData.token) { - if (authData.authTypes.indexOf(AuthType.LOGIN) >= 0) { - return authData.token; - } - } - } - return ''; - } - public get personToken(): string { - const authData = MainDataService.getAuthDataFromLocalStorage(); - if (authData) { - if (authData.token) { - if (authData.authTypes.indexOf(AuthType.PERSON) >= 0) { - return authData.token; - } - } - } - return ''; - } - - public get workspaces(): AccessRightList { - const authData = MainDataService.getAuthDataFromLocalStorage(); - if (authData) { - if (authData.token) { - if (authData.authTypes.indexOf(AuthType.ADMIN) >= 0) { - return authData.accessRights; - } - } - } - return {}; - } - - private static getAuthDataFromLocalStorage(): AuthData { + static getAuthDataFromLocalStorage(): AuthData { const storageEntry = localStorage.getItem(localStorageAuthDataKey); if (storageEntry !== null) { if (storageEntry.length > 0) { @@ -131,50 +59,9 @@ export class MainDataService { } } - setAuthData(loginData: LoginData = null) { - if (loginData) { - const authData = <AuthData>{ - token: '', - authTypes: [], - displayName: '', - accessRights: {} - }; - if (loginData.adminToken) { - authData.token = loginData.adminToken; - authData.displayName = loginData.name; - authData.authTypes.push(AuthType.ADMIN); - if (loginData.isSuperadmin) { - authData.authTypes.push(AuthType.SUPERADMIN); - } - for (let ws of loginData.workspaces) { - authData.accessRights[ws.id.toString()] = ws.name; - } - MainDataService.setAuthDataToLocalStorage(authData); - } else if (loginData.loginToken) { - authData.token = loginData.loginToken; - authData.displayName = loginData.name; - authData.authTypes.push(AuthType.LOGIN); - MainDataService.setAuthDataToLocalStorage(authData); - } else if (loginData.personToken) { - authData.token = loginData.personToken; - authData.displayName = loginData.name; - authData.authTypes.push(AuthType.PERSON); - if (loginData.code) { - const bookletList = loginData.booklets[loginData.code]; - if (bookletList) { - for (let b of bookletList) { - authData.accessRights[b] = b; - } - } - } else { - for (let b of loginData.booklets[0]) { - authData.accessRights[b] = b; - } - } - MainDataService.setAuthDataToLocalStorage(authData); - } else { - MainDataService.setAuthDataToLocalStorage(); - } + setAuthData(authData: AuthData = null) { + if (authData) { + MainDataService.setAuthDataToLocalStorage(authData); } else { MainDataService.setAuthDataToLocalStorage(); } diff --git a/src/app/start/start-button-data.class.ts b/src/app/start/start-button-data.class.ts deleted file mode 100644 index 67f92dabe32f01a92367280c6c33a83a55d6bad2..0000000000000000000000000000000000000000 --- a/src/app/start/start-button-data.class.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { map } from 'rxjs/operators'; -import { BackendService } from '../backend.service'; -import { BookletStatus } from '../app.interfaces'; -import { ServerError } from 'iqb-components'; -// import { of } from 'rxjs'; -// import { pipe } from '@angular/core/src/render3'; - -export class StartButtonData { - id: string; - label: string; - filename: string; - isEnabled: boolean; - statustxt: string; - lastUnit: number; - - constructor( - id: string - ) { - this.id = id; - this.label = ''; - this.filename = ''; - this.isEnabled = false; - this.statustxt = 'Bitte warten'; - } - - public getBookletStatus(bs: BackendService, code = '') { - return bs.getBookletState(this.id, code) - .pipe( - map(respDataUntyped => { - let myreturn = false; - if (respDataUntyped instanceof ServerError) { - const e = respDataUntyped as ServerError; - this.statustxt = e.code.toString() + ': ' + e.labelNice; - } else { - const respData = respDataUntyped as BookletStatus; - this.statustxt = respData.statusLabel; - this.isEnabled = respData.canStart; - myreturn = respData.canStart; - this.lastUnit = respData.lastUnit; - this.label = respData.label; - } - return myreturn; - }) - ); - } - } diff --git a/src/app/start/start.component.css b/src/app/start/start.component.css deleted file mode 100644 index daaa3954799c28ca82a518ad0bee0ed00e093457..0000000000000000000000000000000000000000 --- a/src/app/start/start.component.css +++ /dev/null @@ -1,27 +0,0 @@ -div.booklet_title { - font-size: 16pt; - margin-top: 4px; - margin-bottom: 0; - white-space: pre-wrap; - word-break: break-word; - line-height: 130%; -} - -div.booklet_status { - font-size: 8pt; - margin-top: 0; - color: mediumturquoise; - height: 24px; - margin-bottom: 18px; -} - -.mat-card { - margin: 10px; -} -.status { - background-color: lightgrey; -} - -.error-msg { - color: brown; -} diff --git a/src/app/start/start.component.html b/src/app/start/start.component.html deleted file mode 100644 index 8c6529f2534bf74428aaef99c51d9aa937fa8940..0000000000000000000000000000000000000000 --- a/src/app/start/start.component.html +++ /dev/null @@ -1,150 +0,0 @@ -<div class="logo"> - <a [routerLink]="['/']"> - <img src="assets/IQB-LogoA.png" matTooltip="Startseite" alt="IQB-Logo"/> - </a> -</div> -<div class="page-body"> - <div class="spinner" *ngIf="dataLoading"> - <mat-spinner></mat-spinner> - </div> - <div fxLayout="row wrap" fxLayoutAlign="center stretch" style="padding: 30px;"> - - - <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX --> - <mat-card fxFlex="0 0 400px" fxLayout="column" *ngIf="showLoginForm"> - <!-- - - - - - - - - - - - - - - - - --> - <form [formGroup]="testtakerloginform" (ngSubmit)="login()"> - <mat-card-title>Anmelden</mat-card-title> - <mat-card-content fxLayout="column"> - <mat-form-field> - <input matInput formControlName="testname" placeholder="Anmeldename" (keyup.enter)="pw.focus()"> - </mat-form-field> - <mat-form-field> - <input matInput #pw type="password" formControlName="testpw" placeholder="Kennwort" (keyup.enter)="login()"> - </mat-form-field> - </mat-card-content> - <mat-card-actions> - <button mat-raised-button type="submit" [disabled]="testtakerloginform.invalid" color="primary">Weiter</button> - </mat-card-actions> - </form> - <p class="error-msg">{{ (mds.globalErrorMsg$ | async)?.labelNice }}</p> - - </mat-card> - - <!-- - - - - - - - - - - - - - - - - --> - <mat-card fxFlex="0 0 400px" *ngIf="showCodeForm"> - <form [formGroup]="codeinputform" (ngSubmit)="codeinput()"> - <mat-card-title>{{ 'login_codeInputTitle' | customtext:'login_codeInputTitle':cts.updateCount }}</mat-card-title> - <mat-card-content> - <mat-form-field> - <input matInput formControlName="code" (keyup.enter)="codeinput()"> <!-- no placeholder! --> - </mat-form-field> - </mat-card-content> - <mat-card-actions> - <button mat-raised-button type="submit" [disabled]="codeinputform.invalid" color="primary">Weiter</button> - <button mat-raised-button color="foreground" (click)="resetLogin()">Neu anmelden</button> - </mat-card-actions> - </form> - </mat-card> - - <!-- - - - - - - - - - - - - - - - - --> - <mat-card fxFlex="0 0 400px" fxLayout="column" *ngIf="showBookletButtons"> - <mat-card-title>{{ bookletSelectTitle }}</mat-card-title> - <mat-card-content> - <div fxLayoutGap="10px" fxLayout="column"> - <p *ngIf="bookletlist.length === 0"> - Für diese Anmeldung wurde kein Test gefunden. - </p> - <button mat-raised-button color="primary" (click)="startBooklet(b)" - [disabled]="!b.isEnabled" *ngFor="let b of bookletlist"> - <div class="booklet_title">{{b.label}}</div> - <div class="booklet_status">{{b.statustxt}}</div> - </button> - </div> - </mat-card-content> - <mat-card-actions> - <button mat-raised-button color="foreground" (click)="resetLogin()">Neu anmelden</button> - </mat-card-actions> - </mat-card> - - <!-- - - - - - - - - - - - - - - - - --> - <mat-card fxFlex="0 0 400px" fxLayout="column" *ngIf="showTestRunningButtons && !dataLoading"> - <mat-card-title>{{ 'login_testRunningText' | customtext:'login_testRunningText':cts.updateCount }}</mat-card-title> - <mat-card-content> - <div fxLayout="column" fxLayoutGap="20px"> - <button mat-raised-button color="primary" [routerLink]="['/t']">{{ 'login_testReturnButtonText' | customtext:'login_testReturnButtonText':cts.updateCount }}</button> - <button mat-raised-button color="primary" (click)="stopBooklet()">{{ 'login_testEndButtonText' | customtext:'login_testEndButtonText':cts.updateCount }}</button> - <button mat-raised-button color="foreground" (click)="resetLogin()">Neu anmelden</button> - </div> - </mat-card-content> - </mat-card> - - <mat-card fxFlex="0 0 400px" fxLayout="column" *ngIf="showAdminSelection"> - <mat-card-title>Studie wählen</mat-card-title> - <mat-card-content> - <div fxLayoutGap="10px" fxLayout="column"> - <p *ngIf="(mds.loginData$ | async)?.workspaces.length === 0"> - Sie sind mit Administrator-Funktionen angemeldet. Aktuell sind keine Studien für Sie freigegeben. - </p> - <button mat-raised-button color="primary" (click)="buttonGotoWorkspaceAdmin(ws)" - *ngFor="let ws of (mds.loginData$ | async)?.workspaces"> - {{ws.name}} - </button> - </div> - </mat-card-content> - <mat-card-actions> - <button mat-raised-button color="foreground" *ngIf="(mds.loginData$ | async)?.isSuperadmin" [routerLink]="['/superadmin']">Nutzer/Arbeitsbereiche</button> - <button mat-raised-button color="foreground" (click)="resetLogin()">Neu anmelden</button> - </mat-card-actions> - </mat-card> - - <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX --> - <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX --> - <mat-card fxFlex="0 2 400px" fxLayout="column" class="status"> - <mat-card-title>{{ 'app_title' | customtext:'app_title':cts.updateCount }}</mat-card-title> - - <!-- - - - - - - - - - - - - - - - - --> - <mat-card-content> - <div *ngIf="showLoginForm"> - <p>Das <a href="http://www.iqb.hu-berlin.de" target="_blank">Institut zur Qualitätsentwicklung im Bildungswesen</a> - {{ 'app_intro1' | customtext:'app_intro1':cts.updateCount }}</p> - - <p>Die mit diesem System erhobenen Daten enthalten grundsätzlich keinen direkten - Personenbezug. Es werden z. B. nie Namen gespeichert. Um Auskünfte zu einer bestimmten Befragung bzw. Studie - zu erhalten, wenden Sie sich bitte an das <a href="mailto:mechtel@iqb.hu-berlin.de"> - IQB</a>. Wir benötigen dazu den ungefähren Zeitraum und das Bundesland, in dem die Befragung bzw. Studie - durchgeführt wurde.</p> - </div> - - <!-- - - - - - - - - - - - - - - - - --> - <div *ngIf="!showLoginForm"> - <p>Anmeldestatus:</p> - <ul> - <li *ngFor="let line of loginStatusText">{{ line }}</li> - </ul> - </div> - - <!-- - - - - - - - - - - - - - - - - --> - <div *ngIf="showCodeForm"> - <p>{{ 'login_codeInputPrompt' | customtext:'login_codeInputPrompt':cts.updateCount }}</p> - </div> - - <!-- - - - - - - - - - - - - - - - - --> - <div *ngIf="showBookletButtons"> - <p>{{ bookletSelectPrompt }}</p> - </div> - - <!-- - - - - - - - - - - - - - - - - --> - <div *ngIf="showTestRunningButtons"> - <p>{{ 'login_testRunningLongText' | customtext:'login_testRunningLongText':cts.updateCount }}</p> - </div> - <div class="error-msg">{{ (mds.globalErrorMsg$ | async)?.labelNice }}</div> - - </mat-card-content> - <mat-card-actions> - <button mat-raised-button color="foreground" [routerLink]="['/about']">Impressum/Datenschutz</button> - <button mat-raised-button color="foreground" [routerLink]="['/check']">System-Check</button> - </mat-card-actions> - </mat-card> - </div> -</div> diff --git a/src/app/start/start.component.spec.ts b/src/app/start/start.component.spec.ts deleted file mode 100644 index c5b2e3cb2c45bc891438be51e319846a3eb7e671..0000000000000000000000000000000000000000 --- a/src/app/start/start.component.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { StartComponent } from './start.component'; -import {HttpClientModule} from "@angular/common/http"; -import {BackendService} from "../backend.service"; -import {ReactiveFormsModule} from "@angular/forms"; -import {MatDialogModule} from "@angular/material/dialog"; -import {AppRoutingModule} from "../app-routing.module"; -import {IqbComponentsModule} from "iqb-components"; - -describe('StartComponent', () => { - let component: StartComponent; - let fixture: ComponentFixture<StartComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ StartComponent ], - imports: [ - HttpClientModule, - ReactiveFormsModule, - MatDialogModule, - AppRoutingModule, - IqbComponentsModule - ], - providers: [ - BackendService - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(StartComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/start/start.component.ts b/src/app/start/start.component.ts deleted file mode 100644 index 816bad977589a004817cf6c1d96605ee391ac452..0000000000000000000000000000000000000000 --- a/src/app/start/start.component.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { MainDataService } from '../maindata.service'; -import { Subscription, forkJoin } from 'rxjs'; -import {CustomtextService, MessageDialogComponent, MessageDialogData, MessageType, ServerError} from 'iqb-components'; -import { BackendService } from '../backend.service'; -import {PersonTokenAndTestId, LoginData, WorkspaceData} from '../app.interfaces'; -import { Router } from '@angular/router'; -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { StartButtonData } from './start-button-data.class'; -import { appconfig } from '../app.config'; -import {MatDialog} from "@angular/material/dialog"; - -@Component({ - templateUrl: './start.component.html', - styleUrls: ['./start.component.css'] -}) -export class StartComponent implements OnInit, OnDestroy { - public dataLoading = false; - public showLoginForm = true; - public showCodeForm = false; - public showBookletButtons = false; - public bookletlist: StartButtonData[] = []; - public showTestRunningButtons = false; - public showAdminSelection = false; - - private loginDataSubscription: Subscription = null; - - // for template - private validCodes = []; - private loginStatusText = ['nicht angemeldet']; - public bookletSelectTitle = 'Bitte wählen'; - - private testtakerloginform: FormGroup; - private codeinputform: FormGroup; - private lastloginname = ''; - public bookletSelectPrompt = 'Bitte wählen'; - - // ?? - // private sessiondata: PersonBooklets; - // private code = ''; - // private isError = false; - // private errorMessage = ''; - - - constructor(private fb: FormBuilder, - public mds: MainDataService, - public messsageDialog: MatDialog, - private router: Router, - private bs: BackendService, - public cts: CustomtextService) { - } - - ngOnInit() { - this.loginDataSubscription = this.mds.loginData$.subscribe(logindata => { - this.bookletlist = []; - if (logindata.adminToken.length > 0) { - this.showLoginForm = false; - this.showAdminSelection = true; - this.showCodeForm = false; - this.showBookletButtons = false; - this.showTestRunningButtons = false; - this.loginStatusText = []; - this.loginStatusText.push('Admin-Bereich '); - console.log(logindata); - this.loginStatusText.push('angemeldet als ' + logindata.name); - if (logindata.isSuperadmin) { - this.loginStatusText.push('Rechte auch für Anlegen/Löschen von Nutzern und Workspaces'); - } - } else if (logindata.loginToken.length > 0) { - // Statustext box - this.showAdminSelection = false; - this.loginStatusText = []; - this.loginStatusText.push('Studie: ' + logindata.workspaceName); - this.loginStatusText.push('angemeldet als "' + - logindata.name + (logindata.code.length > 0 ? ('/' + logindata.code + '"') : '"')); - this.loginStatusText.push('Gruppe: ' + logindata.groupName); - - if (logindata.mode === 'run-trial') { - // @ts-ignore - const tmt = this.cts.getCustomText('login_trialmodeText'); - if (tmt.length > 0) { - this.loginStatusText.push(tmt); - } - } else if (logindata.mode === 'run-review') { - // @ts-ignore - const tmt = this.cts.getCustomText('login_reviewmodeText'); - if (tmt.length > 0) { - this.loginStatusText.push(tmt); - } - } - - this.showLoginForm = false; - let createBookletSelectButtons = false; - if (logindata.personToken.length > 0) { - // test started or just finished - this.showBookletButtons = false; - this.showCodeForm = false; - this.showLoginForm = false; - if (logindata.testId === 0) { - this.showBookletButtons = true; - this.showTestRunningButtons = false; - // booklet finished - // buttons to select booklet - - createBookletSelectButtons = true; - this.loginStatusText.push('Nicht gestartet.'); - } else { - // booklet started - this.showBookletButtons = false; - this.showTestRunningButtons = true; - - this.loginStatusText.push('Gestartet: "' + logindata.bookletLabel + '"'); - } - - } else { - this.showTestRunningButtons = false; - - this.validCodes = Object.keys(logindata.booklets); - if (this.validCodes.length > 1) { - if (logindata.code.length > 0) { - this.showCodeForm = false; - this.showBookletButtons = true; - // code given - // buttons to select booklet - - createBookletSelectButtons = true; - } else { - // code not yet given - // code prompt - this.showCodeForm = true; - this.showBookletButtons = false; - } - } else { - // no code but there is only one code - // buttons to select booklet - - this.showCodeForm = false; - this.showBookletButtons = true; - createBookletSelectButtons = true; - } - } - - if (createBookletSelectButtons) { - if (logindata.booklets[logindata.code].length > 0) { - const myBookletStatusLoadings = []; - for (const booklet of logindata.booklets[logindata.code]) { - const myTest = new StartButtonData(booklet); - myBookletStatusLoadings.push(myTest.getBookletStatus(this.bs, logindata.code)); - this.bookletlist.push(myTest); - } - this.dataLoading = true; - forkJoin(myBookletStatusLoadings).subscribe(allOk => { - this.dataLoading = false; - - let numberOfOpenBooklets = 0; - for (const ok of allOk) { - if (ok) { - numberOfOpenBooklets += 1; - } - } - - if (numberOfOpenBooklets === 0) { - this.bookletSelectTitle = 'Beendet'; - // @ts-ignore - this.bookletSelectPrompt = this.cts.getCustomText('login_bookletSelectPromptNull'); - } else if (numberOfOpenBooklets === 1) { - this.bookletSelectPrompt = 'Bitte links auf den Testheft-Schalter klicken!'; - this.bookletSelectTitle = 'Bitte starten'; - // @ts-ignore - this.bookletSelectPrompt = this.cts.getCustomText('login_bookletSelectPromptOne'); - } else { - this.bookletSelectPrompt = 'Bitte links ein Testheft wählen und klicken!'; - this.bookletSelectTitle = 'Bitte wählen'; - // @ts-ignore - this.bookletSelectPrompt = this.cts.getCustomText('login_bookletSelectPromptMany'); - } - }); - } else { - this.bookletSelectTitle = 'Kein Zugriff'; - this.bookletSelectPrompt = 'Keine Informationen zu dieser Anmeldung verfügbar'; - } - } - } else { - // blank start, only login form - this.validCodes = []; - this.loginStatusText = ['nicht angemeldet']; - this.showBookletButtons = false; - this.showCodeForm = false; - this.showAdminSelection = false; - this.showLoginForm = true; - this.showTestRunningButtons = false; - } - }); // loginDataSubscription - - - this.testtakerloginform = this.fb.group({ - testname: this.fb.control(this.lastloginname, [Validators.required, Validators.minLength(3)]), - testpw: this.fb.control('', []) - }); - - this.codeinputform = this.fb.group({ - code: this.fb.control('', [Validators.required, Validators.minLength(1)]) - }); - } - - // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - login() { - this.dataLoading = true; - this.bs.login(this.testtakerloginform.get('testname').value, this.testtakerloginform.get('testpw').value).subscribe( - loginData => { - if (loginData instanceof ServerError) { - const e = loginData as ServerError; - this.mds.globalErrorMsg$.next(e); - this.mds.addCustomtextsFromDefList(appconfig.customtextsLogin); - // no change in other data - } else { - this.mds.globalErrorMsg$.next(null); - if ((loginData as LoginData).customTexts) { - this.cts.addCustomTexts((loginData as LoginData).customTexts); - } - // this.mds.setNewLoginData(loginData as LoginData); TODO delete component - } - this.dataLoading = false; - } - ); - } - - // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - codeinput() { - const myCode = this.codeinputform.get('code').value as string; - if (myCode.length === 0) { - this.messsageDialog.open(MessageDialogComponent, { - width: '400px', - data: <MessageDialogData>{ - // @ts-ignore - title: this.cts.getCustomText('login_codeInputTitle') + ': Leer', - // @ts-ignore - content: this.cts.getCustomText('login_codeInputPrompt'), - type: MessageType.error - } - }); - } else if (this.validCodes.indexOf(myCode) < 0) { - this.messsageDialog.open(MessageDialogComponent, { - width: '400px', - data: <MessageDialogData>{ - // @ts-ignore - title: this.cts.getCustomText('login_codeInputTitle') + ': Ungültig', - // @ts-ignore - content: this.cts.getCustomText('login_codeInputPrompt'), - type: MessageType.error - } - }); - } else { - this.mds.setCode(myCode); - } - } - - // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - startBooklet(b: StartButtonData) { - this.bs.startBooklet(this.mds.getCode(), b.id, b.label).subscribe( - startReturnUntyped => { - if (startReturnUntyped instanceof ServerError) { - const e = startReturnUntyped as ServerError; - this.mds.globalErrorMsg$.next(e); - } else { - const startReturn = startReturnUntyped as PersonTokenAndTestId; - this.mds.globalErrorMsg$.next(null); - // ************************************************ - - // by setting bookletDbId$ the test-controller will load the booklet - this.dataLoading = true; - this.mds.setBookletDbId(startReturn.personToken, startReturn.testId, b.label); - this.router.navigateByUrl('/t'); - - // ************************************************ - } - } - ); - } - - // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - resetLogin() { - // this.mds.setNewLoginData(); TODO fix - } - - // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - stopBooklet() { - this.mds.endBooklet(); - } - - buttonGotoWorkspaceAdmin(ws: WorkspaceData) { - this.router.navigateByUrl('/admin/' + ws.id.toString() + '/files'); - } - - buttonGotoWorkspaceMonitor(ws: WorkspaceData) { - this.router.navigateByUrl('/wsmonitor/' + ws.id.toString()); - } - - // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % - ngOnDestroy() { - if (this.loginDataSubscription !== null) { - this.loginDataSubscription.unsubscribe(); - } - } -} diff --git a/src/app/superadmin/superadmin.interfaces.ts b/src/app/superadmin/superadmin.interfaces.ts index 91e12796f765db07a9d29739af4dd3612fa21944..2c4d2633af4e433486f793df3421e3e289594a4b 100644 --- a/src/app/superadmin/superadmin.interfaces.ts +++ b/src/app/superadmin/superadmin.interfaces.ts @@ -23,6 +23,6 @@ export interface UserData { id: number; name: string; email: string; - is_superadmin: string; + isSuperadmin: boolean; selected: boolean; } diff --git a/src/app/superadmin/users/users.component.html b/src/app/superadmin/users/users.component.html index 7650653c7e6e95690b7f2546e835205c12114bd3..3e633482a87711e4a98fe9a1f24be858d772cf20 100644 --- a/src/app/superadmin/users/users.component.html +++ b/src/app/superadmin/users/users.component.html @@ -37,7 +37,7 @@ <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> - <mat-cell *matCellDef="let element"> {{element.name}} {{element.is_superadmin === '1' ? '*' : ''}}</mat-cell> + <mat-cell *matCellDef="let element"> {{element.name}} {{element.isSuperadmin ? '*' : ''}}</mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> diff --git a/src/app/superadmin/users/users.component.ts b/src/app/superadmin/users/users.component.ts index 2b1c2f0520ec25aee0e1ae27852a76331ba4be93..53d59e49e138bd70d863c8208c4c81f1bd47d5b4 100644 --- a/src/app/superadmin/users/users.component.ts +++ b/src/app/superadmin/users/users.component.ts @@ -110,7 +110,7 @@ export class UsersComponent implements OnInit { width: '400px', data: <ConfirmDialogData>{ title: 'Ändern des Superadmin-Status', - content: 'Für "' + userObject.name + '" den Status auf "' + (userObject.is_superadmin === '0' ? '' : 'NICHT ') + 'Superadmin" setzen?', + content: 'Für "' + userObject.name + '" den Status auf "' + (userObject.isSuperadmin ? 'NICHT ' : '') + 'Superadmin" setzen?', confirmbuttonlabel: 'Status ändern', showcancel: true } @@ -120,7 +120,7 @@ export class UsersComponent implements OnInit { if ((typeof result !== 'undefined') && (result !== false)) { const passwdDialogRef = this.superadminPasswordDialog.open(SuperadminPasswordRequestComponent, { width: '600px', - data: 'Superadmin-Status ' + (userObject.is_superadmin === '0' ? 'setzen' : 'entziehen') + data: 'Superadmin-Status ' + (userObject.isSuperadmin ? 'entziehen' : 'setzen') }); passwdDialogRef.afterClosed().subscribe(result => { @@ -128,11 +128,12 @@ export class UsersComponent implements OnInit { if (result !== false) { this.bs.setSuperUserStatus( selectedRows[0]['id'], - userObject.is_superadmin === '0', + !userObject.isSuperadmin, (<FormGroup>result).get('pw').value).subscribe( respOk => { if (respOk !== false) { this.snackBar.open('Status geändert', '', {duration: 1000}); + this.updateObjectList(); } else { this.snackBar.open('Konnte Status nicht ändern', 'Fehler', {duration: 1000}); } diff --git a/src/app/workspace-admin/backend.service.ts b/src/app/workspace-admin/backend.service.ts index cafe10923b55d06c2095fb53528b7de62c7eb88e..ee0b1d1f3b2bfe9b92762af6a73b2d8497ed31bb 100644 --- a/src/app/workspace-admin/backend.service.ts +++ b/src/app/workspace-admin/backend.service.ts @@ -2,10 +2,11 @@ import { GetFileResponseData, CheckWorkspaceResponseData, SysCheckStatistics, ReviewData, LogData, UnitResponse, ResultData } from './workspace.interfaces'; import {Injectable, Inject} from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; +import {Observable, of} from 'rxjs'; import { catchError } from 'rxjs/operators'; import { ErrorHandler, ServerError } from 'iqb-components'; import {WorkspaceDataService} from "./workspacedata.service"; +import {WorkspaceData} from "../app.interfaces"; @Injectable({ providedIn: 'root' @@ -20,6 +21,13 @@ export class BackendService { ) { } + getWorkspaceData(workspaceId: string): Observable<WorkspaceData | number> { + return this.http + .get<WorkspaceData>(this.serverUrl + 'workspace/' + workspaceId) + .pipe( + catchError(errCode => of(errCode)) + ); + } getFiles(): Observable<GetFileResponseData[] | ServerError> { diff --git a/src/app/workspace-admin/files/files.component.ts b/src/app/workspace-admin/files/files.component.ts index b278f5c9696d7e2a277120f6d8967abc4bad7f51..ea5b15d9151d6fe34f22f9f27d4826b20a5b511a 100644 --- a/src/app/workspace-admin/files/files.component.ts +++ b/src/app/workspace-admin/files/files.component.ts @@ -37,7 +37,7 @@ export class FilesComponent implements OnInit { private mds: MainDataService, public wds: WorkspaceDataService, public confirmDialog: MatDialog, - public messsageDialog: MatDialog, + public messageDialog: MatDialog, public snackBar: MatSnackBar ) { } @@ -112,7 +112,7 @@ export class FilesComponent implements OnInit { } }); } else { - this.messsageDialog.open(MessageDialogComponent, { + this.messageDialog.open(MessageDialogComponent, { width: '400px', data: <MessageDialogData>{ title: 'Löschen von Dateien', diff --git a/src/app/workspace-admin/workspace.component.ts b/src/app/workspace-admin/workspace.component.ts index 78d2fbb04c760084d163a296195d8759fa144ccc..0a388eb8bff501f87571e89501acb3b220363374 100644 --- a/src/app/workspace-admin/workspace.component.ts +++ b/src/app/workspace-admin/workspace.component.ts @@ -1,8 +1,8 @@ import { WorkspaceDataService } from './workspacedata.service'; -import { MainDataService } from '../maindata.service'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; import { Component, OnInit, OnDestroy } from '@angular/core'; +import {BackendService} from "./backend.service"; @Component({ @@ -14,17 +14,21 @@ export class WorkspaceComponent implements OnInit, OnDestroy { constructor( private route: ActivatedRoute, - public mds: MainDataService, + private bs: BackendService, public wds: WorkspaceDataService ) { } ngOnInit() { this.routingSubscription = this.route.params.subscribe(params => { this.wds.wsId = params['ws']; - const wsList = this.mds.workspaces; - if (wsList && wsList[this.wds.wsId]) { - this.wds.wsName = wsList[this.wds.wsId]; - } + this.bs.getWorkspaceData(this.wds.wsId).subscribe( + wsData => { + if (typeof wsData !== 'number') { + this.wds.wsName = wsData.name; + this.wds.wsRole = wsData.role; + } + } + ) }); } diff --git a/src/app/workspace-admin/workspace.interfaces.ts b/src/app/workspace-admin/workspace.interfaces.ts index b53f17d1622617ce9b17a3e4f533e1666f7ee912..11cc9ecefe067cade92d81137cb5992752a5a78e 100644 --- a/src/app/workspace-admin/workspace.interfaces.ts +++ b/src/app/workspace-admin/workspace.interfaces.ts @@ -1,3 +1,9 @@ +export interface WorkspaceData { + id: string; + name: string; + role: "RW" | "RO" | "n.d."; +} + export interface GetFileResponseData { filename: string; filesize: number; diff --git a/src/app/workspace-admin/workspacedata.service.ts b/src/app/workspace-admin/workspacedata.service.ts index e9b641ddb12fc40edda26414aaa8e62678c3f7b4..c4c7a63f676f91174ca41294a46c77de70e98901 100644 --- a/src/app/workspace-admin/workspacedata.service.ts +++ b/src/app/workspace-admin/workspacedata.service.ts @@ -6,7 +6,7 @@ import { Injectable } from '@angular/core'; @Injectable() export class WorkspaceDataService { - public wsId = ''; + public wsId: string; public wsRole = 'RW'; public wsName = ''; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 2ea5c28809a1a50116ddb0f8460fc858feefee3d..c65de53f15af5011f0aecca5472dbea0e9754fa4 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -10,7 +10,7 @@ export const environment = { appName: 'IQB-Testcenter', appPublisher: 'IQB - Institut zur Qualitätsentwicklung im Bildungswesen', appVersion: '0 (dev)', - apiVersionExpected: '2.0.1' + apiVersionExpected: '2.0.0' }; /*