From f4f107f01d423e1f3d8d2f2e0a65dbcd8ef63de1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20K=C3=A4sler?= <tom.kaesler@mni.thm.de>
Date: Fri, 2 Aug 2019 01:09:16 +0200
Subject: [PATCH] Refactor auth system and auth guard

---
 .../_dialogs/room-edit/room-edit.component.ts |  2 +-
 .../creator/creator-routing.module.ts         |  8 +++++
 .../room-create/room-create.component.ts      | 20 ++++++++----
 .../shared/room-join/room-join.component.ts   | 14 +++++---
 src/app/guards/authentication.guard.ts        |  7 ++--
 src/app/models/events/room-created.ts         | 13 ++++++++
 .../{messages => events}/room-deleted.ts      |  0
 src/app/models/events/room-joined.ts          | 13 ++++++++
 .../services/http/authentication.service.ts   | 29 +++++++++++++++--
 src/app/services/http/room.service.ts         | 32 +++++++++++++++----
 10 files changed, 114 insertions(+), 24 deletions(-)
 create mode 100644 src/app/models/events/room-created.ts
 rename src/app/models/{messages => events}/room-deleted.ts (100%)
 create mode 100644 src/app/models/events/room-joined.ts

diff --git a/src/app/components/creator/_dialogs/room-edit/room-edit.component.ts b/src/app/components/creator/_dialogs/room-edit/room-edit.component.ts
index 17e932faf..1f5cf486d 100644
--- a/src/app/components/creator/_dialogs/room-edit/room-edit.component.ts
+++ b/src/app/components/creator/_dialogs/room-edit/room-edit.component.ts
@@ -8,7 +8,7 @@ import { RoomService } from '../../../../services/http/room.service';
 import { Router } from '@angular/router';
 import { RoomCreatorPageComponent } from '../../room-creator-page/room-creator-page.component';
 import { EventService } from '../../../../services/util/event.service';
-import { RoomDeleted } from '../../../../models/messages/room-deleted';
+import { RoomDeleted } from '../../../../models/events/room-deleted';
 
 @Component({
   selector: 'app-room-edit',
diff --git a/src/app/components/creator/creator-routing.module.ts b/src/app/components/creator/creator-routing.module.ts
index eef47c99d..61db32fe6 100644
--- a/src/app/components/creator/creator-routing.module.ts
+++ b/src/app/components/creator/creator-routing.module.ts
@@ -15,41 +15,49 @@ const routes: Routes = [
   {
     path: 'room/:roomId',
     component: RoomCreatorPageComponent,
+    canActivate: [AuthenticationGuard],
     data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/create-content',
     component: ContentCreatePageComponent,
     canActivate: [AuthenticationGuard],
+    data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/statistics',
     component: StatisticsPageComponent,
     canActivate: [AuthenticationGuard],
+    data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/statistics/:contentId',
     component: StatisticComponent,
+    canActivate: [AuthenticationGuard],
     data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/comments',
     component: CommentPageComponent,
+    canActivate: [AuthenticationGuard],
     data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/feedback-barometer',
     component: FeedbackBarometerPageComponent,
+    canActivate: [AuthenticationGuard],
     data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/:contentGroup',
     component: ContentListComponent,
+    canActivate: [AuthenticationGuard],
     data: { roles: [UserRole.CREATOR] }
   },
   {
     path: 'room/:roomId/:contentGroup/presentation',
     component: ContentPresentationComponent,
+    canActivate: [AuthenticationGuard],
     data: { roles: [UserRole.CREATOR] }
   }
 ];
diff --git a/src/app/components/shared/_dialogs/room-create/room-create.component.ts b/src/app/components/shared/_dialogs/room-create/room-create.component.ts
index 5d25a5be0..7f99231ac 100644
--- a/src/app/components/shared/_dialogs/room-create/room-create.component.ts
+++ b/src/app/components/shared/_dialogs/room-create/room-create.component.ts
@@ -1,10 +1,12 @@
 import { Component, Inject, OnInit } from '@angular/core';
 import { RoomService } from '../../../../services/http/room.service';
 import { Room } from '../../../../models/room';
+import { UserRole } from '../../../../models/user-roles.enum';
 import { Router } from '@angular/router';
 import { NotificationService } from '../../../../services/util/notification.service';
 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
 import { ContentService } from '../../../../services/http/content.service';
+import { AuthenticationService } from '../../../../services/http/authentication.service';
 import { TranslateService } from '@ngx-translate/core';
 import { TSMap } from 'typescript-map';
 
@@ -19,13 +21,16 @@ export class RoomCreateComponent implements OnInit {
   room: Room;
   roomId: string;
 
-  constructor(private roomService: RoomService,
-              private contentService: ContentService,
-              private router: Router,
-              private notification: NotificationService,
-              public dialogRef: MatDialogRef<RoomCreateComponent>,
-              private translateService: TranslateService,
-              @Inject(MAT_DIALOG_DATA) public data: any) {
+  constructor(
+    private roomService: RoomService,
+    private contentService: ContentService,
+    private router: Router,
+    private notification: NotificationService,
+    public dialogRef: MatDialogRef<RoomCreateComponent>,
+    private translateService: TranslateService,
+    private authService: AuthenticationService,
+    @Inject(MAT_DIALOG_DATA) public data: any
+  ) {
   }
 
   ngOnInit() {
@@ -57,6 +62,7 @@ export class RoomCreateComponent implements OnInit {
       this.translateService.get('home-page.created-1').subscribe(msg => { msg1 = msg; });
       this.translateService.get('home-page.created-2').subscribe(msg => { msg2 = msg; });
       this.notification.show(msg1 + longRoomName + msg2);
+      this.authService.setAccess(room.shortId, UserRole.CREATOR);
       this.router.navigate([`/creator/room/${this.room.shortId}`]);
       this.dialogRef.close();
     });
diff --git a/src/app/components/shared/room-join/room-join.component.ts b/src/app/components/shared/room-join/room-join.component.ts
index 4d9ab6ebe..302f4ed94 100644
--- a/src/app/components/shared/room-join/room-join.component.ts
+++ b/src/app/components/shared/room-join/room-join.component.ts
@@ -25,11 +25,13 @@ export class RoomJoinComponent implements OnInit {
 
   matcher = new RegisterErrorStateMatcher();
 
-  constructor(private roomService: RoomService,
-              private router: Router,
-              public notificationService: NotificationService,
-              private translateService: TranslateService,
-              public authenticationService: AuthenticationService) {
+  constructor(
+    private roomService: RoomService,
+    private router: Router,
+    public notificationService: NotificationService,
+    private translateService: TranslateService,
+    public authenticationService: AuthenticationService
+  ) {
   }
 
   ngOnInit() {
@@ -93,6 +95,8 @@ export class RoomJoinComponent implements OnInit {
       this.router.navigate([`/creator/room/${this.room.shortId}/comments`]);
     } else {
       this.roomService.addToHistory(this.room.id);
+      this.authenticationService.setAccess(this.room.shortId, UserRole.PARTICIPANT);
+
       this.router.navigate([`/participant/room/${this.room.shortId}/comments`]);
     }
   }
diff --git a/src/app/guards/authentication.guard.ts b/src/app/guards/authentication.guard.ts
index 5f4e5e726..aca9dbf90 100644
--- a/src/app/guards/authentication.guard.ts
+++ b/src/app/guards/authentication.guard.ts
@@ -15,17 +15,18 @@ export class AuthenticationGuard implements CanActivate {
               private router: Router) {
   }
 
-  canActivate(next: ActivatedRouteSnapshot,
+  canActivate(route: ActivatedRouteSnapshot,
               state: RouterStateSnapshot): boolean {
     // Get active user
     const user: User = this.authenticationService.getUser();
     // Get roles having access to this route
     // undefined if every logged in user should have access regardless of its role
-    const requiredRoles = next.data['roles'] as Array<UserRole>;
+    const requiredRoles = route.data['roles'] as Array<UserRole>;
     // Allow access when user is logged in AND
     // the route doesn't require a specific role OR
     // the user's role is one of the required roles
-    if (user && (!requiredRoles || requiredRoles.includes(user.role))) {
+    console.log(requiredRoles[0]);
+    if (this.authenticationService.hasAccess(route.params.roomId, requiredRoles[0])) {
       return true;
     }
 
diff --git a/src/app/models/events/room-created.ts b/src/app/models/events/room-created.ts
new file mode 100644
index 000000000..3bc9ea5da
--- /dev/null
+++ b/src/app/models/events/room-created.ts
@@ -0,0 +1,13 @@
+export class RoomCreated {
+  type: string;
+  payload: {
+    id: string;
+  };
+
+  constructor(id: string) {
+    this.type = 'RoomCreated';
+    this.payload = {
+      id: id
+    };
+  }
+}
diff --git a/src/app/models/messages/room-deleted.ts b/src/app/models/events/room-deleted.ts
similarity index 100%
rename from src/app/models/messages/room-deleted.ts
rename to src/app/models/events/room-deleted.ts
diff --git a/src/app/models/events/room-joined.ts b/src/app/models/events/room-joined.ts
new file mode 100644
index 000000000..204688915
--- /dev/null
+++ b/src/app/models/events/room-joined.ts
@@ -0,0 +1,13 @@
+export class RoomJoined {
+  type: string;
+  payload: {
+    id: string;
+  };
+
+  constructor(id: string) {
+    this.type = 'RoomJoined';
+    this.payload = {
+      id: id
+    };
+  }
+}
diff --git a/src/app/services/http/authentication.service.ts b/src/app/services/http/authentication.service.ts
index cb5eccd37..e867a10d2 100644
--- a/src/app/services/http/authentication.service.ts
+++ b/src/app/services/http/authentication.service.ts
@@ -4,6 +4,7 @@ import { User } from '../../models/user';
 import { Observable ,  of ,  BehaviorSubject } from 'rxjs';
 import { UserRole } from '../../models/user-roles.enum';
 import { DataStoreService } from '../util/data-store.service';
+import { EventService } from '../util/event.service';
 import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { ClientAuthentication } from '../../models/client-authentication';
 
@@ -26,12 +27,26 @@ export class AuthenticationService {
     headers: new HttpHeaders({})
   };
 
-  constructor(private dataStoreService: DataStoreService,
-              private http: HttpClient) {
+  private roomAccess = new Map();
+
+  constructor(
+    private dataStoreService: DataStoreService,
+    public eventService: EventService,
+    private http: HttpClient
+  ) {
     if (dataStoreService.has(this.STORAGE_KEY)) {
       // Load user data from local data store if available
       this.user.next(JSON.parse(dataStoreService.get(this.STORAGE_KEY)));
     }
+    this.eventService.on<any>('RoomJoined').subscribe(payload => {
+      this.roomAccess.set(payload.id, UserRole.PARTICIPANT);
+    });
+    this.eventService.on<any>('RoomDeleted').subscribe(payload => {
+      this.roomAccess.delete(payload.id);
+    });
+    this.eventService.on<any>('RoomCreated').subscribe(payload => {
+      this.roomAccess.set(payload.id, UserRole.CREATOR);
+    });
   }
 
   /*
@@ -149,4 +164,14 @@ export class AuthenticationService {
   getUserAsSubject(): BehaviorSubject<User> {
     return this.user;
   }
+
+  hasAccess(roomId: string, role: UserRole): boolean {
+    const usersRole = this.roomAccess.get(roomId);
+    console.log(usersRole);
+    return (usersRole && (usersRole === role));
+  }
+
+  setAccess(roomId: string, role: UserRole): void {
+    this.roomAccess.set(roomId, role);
+  }
 }
diff --git a/src/app/services/http/room.service.ts b/src/app/services/http/room.service.ts
index 36fcdb516..333519ec3 100644
--- a/src/app/services/http/room.service.ts
+++ b/src/app/services/http/room.service.ts
@@ -1,10 +1,14 @@
 import { Injectable } from '@angular/core';
 import { Room } from '../../models/room';
+import { RoomJoined } from '../../models/events/room-joined';
+import { RoomCreated } from '../../models/events/room-created';
+import { UserRole } from '../../models/user-roles.enum';
 import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { Observable } from 'rxjs';
 import { catchError, tap, map } from 'rxjs/operators';
 import { AuthenticationService } from './authentication.service';
 import { BaseHttpService } from './base-http.service';
+import { EventService } from '../util/event.service';
 import { TSMap } from 'typescript-map';
 
 const httpOptions = {
@@ -21,8 +25,11 @@ export class RoomService extends BaseHttpService {
   };
   private joinDate = new Date(Date.now());
 
-  constructor(private http: HttpClient,
-              private authService: AuthenticationService) {
+  constructor(
+    private http: HttpClient,
+    private eventService: EventService,
+    private authService: AuthenticationService
+  ) {
     super();
   }
 
@@ -32,7 +39,11 @@ export class RoomService extends BaseHttpService {
       properties: { ownerId: this.authService.getUser().id },
       externalFilters: {}
     }).pipe(
-      tap(() => ''),
+      tap((rooms) => {
+        for (const r of rooms) {
+          this.authService.setAccess(r.shortId, UserRole.CREATOR);
+        }
+      }),
       catchError(this.handleError('getCreatorRooms', []))
     );
   }
@@ -43,7 +54,11 @@ export class RoomService extends BaseHttpService {
       properties: {},
       externalFilters: { inHistoryOfUserId: this.authService.getUser().id }
     }).pipe(
-      tap(() => ''),
+      tap((rooms) => {
+        for (const r of rooms) {
+          this.authService.setAccess(r.shortId, UserRole.PARTICIPANT);
+        }
+      }),
       catchError(this.handleError('getParticipantRooms', []))
     );
   }
@@ -53,7 +68,12 @@ export class RoomService extends BaseHttpService {
     delete room.revision;
     const connectionUrl = this.apiUrl.base + this.apiUrl.rooms + '/';
     room.ownerId = this.authService.getUser().id;
-    return this.http.post<Room>(connectionUrl, room, httpOptions);
+    return this.http.post<Room>(connectionUrl, room, httpOptions).pipe(
+      tap(returnedRoom => {
+        this.authService.setAccess(returnedRoom.shortId, UserRole.PARTICIPANT);
+      }),
+      catchError(this.handleError<Room>(`add Room ${room}`))
+    );
   }
 
   getRoom(id: string): Observable<Room> {
@@ -78,7 +98,7 @@ export class RoomService extends BaseHttpService {
 
   addToHistory(roomId: string): void {
     const connectionUrl = `${ this.apiUrl.base + this.apiUrl.user }/${ this.authService.getUser().id }/roomHistory`;
-    this.http.post(connectionUrl, { roomId: roomId, lastVisit: this.joinDate.getTime() }, httpOptions).subscribe();
+    this.http.post(connectionUrl, { roomId: roomId, lastVisit: this.joinDate.getTime() }, httpOptions).subscribe(() => {});
   }
 
   updateRoom(updatedRoom: Room): Observable<Room> {
-- 
GitLab