Ver código fonte

Improved user handling in app shell

Lukas Angerer 3 anos atrás
pai
commit
85cd030429

+ 11 - 1
src/RunnersMeet.Client/src/app/app.component.html

@@ -5,4 +5,14 @@
 	<li><a [routerLink]="['/tracks/edit/new']">Create Track</a></li>
 	<li><a href="#" (click)="logout()">Logout</a></li>
 </ul>
-<router-outlet></router-outlet>
+<div *ngIf="showLoadingBlock()">
+	Loading...
+</div>
+<router-outlet *ngIf="showRouterOutlet()"></router-outlet>
+<div *ngIf="showLoginBlock()">
+	Not authenticated
+	<button type="button" (click)="login()">Login</button>
+</div>
+<div *ngIf="showPermissionBlock()">
+	Your account has not yet been granted the necessary permissions to use this application, please contact your administrator.
+</div>

+ 23 - 0
src/RunnersMeet.Client/src/app/app.component.ts

@@ -1,6 +1,7 @@
 import { Component } from '@angular/core';
 import { AuthService } from '@auth0/auth0-angular';
 import { PermissionService } from './users/permission.service';
+import { UserState } from './users/user-state';
 
 @Component({
 	selector: 'app-root',
@@ -9,6 +10,7 @@ import { PermissionService } from './users/permission.service';
 })
 export class AppComponent {
 	public title = 'RunnersMeet';
+	public state: UserState = UserState.Loading;
 
 	public constructor(
 		private readonly authService: AuthService,
@@ -16,9 +18,30 @@ export class AppComponent {
 	) {
 		this.permissions.isRegistered().then(result => {
 			console.log('AppComponent | isRegistered:', result);
+			this.state = result;
 		});
 	}
 
+	public showLoadingBlock(): boolean {
+		return this.state === UserState.Loading;
+	}
+
+	public showRouterOutlet(): boolean {
+		return this.state === UserState.Registered;
+	}
+
+	public showLoginBlock(): boolean {
+		return this.state === UserState.Unauthenticated;
+	}
+
+	public showPermissionBlock(): boolean {
+		return this.state === UserState.Authenticated;
+	}
+
+	public login(): void {
+		this.authService.loginWithRedirect();
+	}
+
 	public logout(): void {
 		this.authService.logout({
 			federated: true,

+ 1 - 6
src/RunnersMeet.Client/src/app/pages/home-page/home-page.component.html

@@ -1,4 +1,4 @@
-<div *ngIf="authService.isAuthenticated$ | async">
+<div>
 	<dl>
 		<dt>isLoading</dt>
 		<dd>{{ authService.isLoading$ | async | json }}</dd>
@@ -11,9 +11,4 @@
 		<dt>User ID</dt>
 		<dd>{{ (authService.user$ | async)?.sub }}</dd>
 	</dl>
-	<button type="button" (click)="logout()">Logout</button>
-</div>
-<div *ngIf="!(authService.isAuthenticated$ | async)">
-	Not authenticated
-	<button type="button" (click)="login()">Login</button>
 </div>

+ 0 - 8
src/RunnersMeet.Client/src/app/pages/home-page/home-page.component.ts

@@ -11,12 +11,4 @@ export class HomePageComponent {
 		public readonly authService: AuthService
 	) {
 	}
-
-	public login(): void {
-		this.authService.loginWithRedirect();
-	}
-
-	public logout(): void {
-		this.authService.logout();
-	}
 }

+ 30 - 11
src/RunnersMeet.Client/src/app/users/permission.service.ts

@@ -1,31 +1,50 @@
 import { Injectable } from "@angular/core";
 import { AuthService, User } from "@auth0/auth0-angular";
+import { BehaviorSubject, firstValueFrom, Subject } from "rxjs";
+import { UserProfile } from "./user-profile";
+import { UserState } from "./user-state";
 import { UsersApiService } from "./users-api.service";
 import { UserValidationResult } from "./validate-user-result";
 
 @Injectable()
 export class PermissionService {
 
-	private _user?: User;
+	private readonly _validationResult: Promise<UserValidationResult | null>;
 
-	public get user(): User | undefined {
-		return this._user;
+	public get user(): Promise<User | null> {
+		return this._validationResult.then(r => r?.user ?? null);
+	}
+
+	public get userProfile(): Promise<UserProfile | null> {
+		return this._validationResult.then(r => r?.userProfile ?? null);
 	}
 
 	public constructor(
 		public readonly authService: AuthService,
 		private readonly usersApi: UsersApiService
 	) {
-		this.authService.user$.subscribe(user => {
-			if (user) {
-				this._user = user;
-			} else {
-				this._user = undefined;
-			}
+		this._validationResult = new Promise<UserValidationResult | null>(resolve => {
+			firstValueFrom(this.authService.user$)
+				.then(user => {
+					if (user) {
+						return this.usersApi.validatePermissions(user);
+					} else {
+						return null;
+					}
+				})
+				.then(result => {
+					resolve(result);
+				});
 		});
 	}
 
-	public isRegistered(): Promise<UserValidationResult> {
-		return this.usersApi.validatePermissions();
+	public isRegistered(): Promise<UserState> {
+		return this._validationResult.then(r => {
+			return r == null
+				? UserState.Unauthenticated
+				: (r.claims.length > 0
+					? UserState.Registered
+					: UserState.Authenticated);
+		});
 	}
 }

+ 6 - 0
src/RunnersMeet.Client/src/app/users/user-state.ts

@@ -0,0 +1,6 @@
+export enum UserState {
+	Loading,
+	Unauthenticated,
+	Authenticated,
+	Registered
+}

+ 7 - 2
src/RunnersMeet.Client/src/app/users/users-api.service.ts

@@ -1,5 +1,6 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
+import { User } from '@auth0/auth0-angular';
 import { lastValueFrom } from 'rxjs';
 import { ConfigService } from '../config.service';
 import { UserValidationResult } from './validate-user-result';
@@ -14,7 +15,11 @@ export class UsersApiService {
 		private readonly http: HttpClient
 	) { }
 
-	public validatePermissions(): Promise<UserValidationResult> {
-		return lastValueFrom(this.http.get<UserValidationResult>(this.config.apiUri(`/api/users/validate`)));
+	public validatePermissions(user: User): Promise<UserValidationResult> {
+		return lastValueFrom(this.http.get<UserValidationResult>(this.config.apiUri(`/api/users/validate`)))
+			.then(result => {
+				result.user = user;
+				return result;
+			});
 	}
 }

+ 2 - 0
src/RunnersMeet.Client/src/app/users/validate-user-result.ts

@@ -1,6 +1,8 @@
+import { User } from "@auth0/auth0-angular";
 import { UserProfile } from "./user-profile";
 
 export class UserValidationResult {
 	public userProfile: UserProfile = new UserProfile();
 	public claims: string[] = [];
+	public user: User | null = null;
 }