From 969067642bdcb787237680be02964e48cfe8ac34 Mon Sep 17 00:00:00 2001 From: Nguyen <87511888+nknguyenhc@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:55:33 +0800 Subject: [PATCH] Add login redirect (#1256) Previously, upon login, users are brought to the default landing page of the phase. We redirect to the intended landing page, with appropriate next route checking. --- .../confirm-login/confirm-login.component.ts | 2 +- src/app/core/guards/auth.guard.ts | 2 + src/app/core/services/auth.service.ts | 37 ++++++++++++++++++- src/app/core/services/phase.service.ts | 7 ++++ .../shared/view-issue/view-issue.component.ts | 10 ++++- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/app/auth/confirm-login/confirm-login.component.ts b/src/app/auth/confirm-login/confirm-login.component.ts index e292672a..ad8f5d55 100644 --- a/src/app/auth/confirm-login/confirm-login.component.ts +++ b/src/app/auth/confirm-login/confirm-login.component.ts @@ -44,8 +44,8 @@ export class ConfirmLoginComponent implements OnInit { */ handleAuthSuccess() { this.authService.setTitleWithPhaseDetail(); - this.router.navigateByUrl(this.phaseService.currentPhase); this.authService.changeAuthState(AuthState.Authenticated); + this.authService.navigateToLandingPage(); } /** diff --git a/src/app/core/guards/auth.guard.ts b/src/app/core/guards/auth.guard.ts index def27642..2fadddd4 100644 --- a/src/app/core/guards/auth.guard.ts +++ b/src/app/core/guards/auth.guard.ts @@ -11,8 +11,10 @@ export class AuthGuard implements CanActivate, CanLoad { canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | boolean { if (this.auth.isAuthenticated()) { + this.auth.clearNext(); return true; } else { + this.auth.storeNext(state); this.router.navigate(['']); return false; } diff --git a/src/app/core/services/auth.service.ts b/src/app/core/services/auth.service.ts index cf8a9cb6..7dba5703 100644 --- a/src/app/core/services/auth.service.ts +++ b/src/app/core/services/auth.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { NgZone } from '@angular/core'; import { Title } from '@angular/platform-browser'; -import { Router } from '@angular/router'; +import { Router, RouterStateSnapshot } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; import { AppConfig } from '../../../environments/environment'; import { generateSessionId } from '../../shared/lib/session'; @@ -30,6 +30,8 @@ export enum AuthState { * updating the application state with regards to authentication. */ export class AuthService { + private static readonly SESSION_NEXT_KEY = 'next'; + authStateSource = new BehaviorSubject(AuthState.NotAuthenticated); currentAuthState = this.authStateSource.asObservable(); accessToken = new BehaviorSubject(undefined); @@ -50,6 +52,27 @@ export class AuthService { private logger: LoggingService ) {} + /** + * Stores the data about the next route in the session storage. + */ + storeNext(next: RouterStateSnapshot) { + sessionStorage.setItem(AuthService.SESSION_NEXT_KEY, next.url); + } + + /** + * Returns the next route + */ + private getNext(): string { + return sessionStorage.getItem(AuthService.SESSION_NEXT_KEY); + } + + /** + * Clears the next route from the session storage. + */ + clearNext() { + sessionStorage.removeItem(AuthService.SESSION_NEXT_KEY); + } + /** * Will store the OAuth token. */ @@ -144,4 +167,16 @@ export class AuthService { } window.location.href = url; } + + /** + * Navigates to next if there is, or default landing page. + */ + navigateToLandingPage() { + const nextRoute = this.getNext(); + if (!nextRoute || !this.phaseService.isValidRoute(nextRoute)) { + this.router.navigateByUrl(this.phaseService.currentPhase); + } else { + this.router.navigateByUrl(nextRoute); + } + } } diff --git a/src/app/core/services/phase.service.ts b/src/app/core/services/phase.service.ts index ada3c9bb..3e5d8b22 100644 --- a/src/app/core/services/phase.service.ts +++ b/src/app/core/services/phase.service.ts @@ -161,6 +161,13 @@ export class PhaseService { return this.orgName.concat('/').concat(this.repoName); } + /** + * Checks whether the given route is allowed in this phase. + */ + isValidRoute(route: string): boolean { + return route.startsWith('/' + this.currentPhase); + } + reset() { this.currentPhase = null; } diff --git a/src/app/shared/view-issue/view-issue.component.ts b/src/app/shared/view-issue/view-issue.component.ts index 34b24e93..f36b6726 100644 --- a/src/app/shared/view-issue/view-issue.component.ts +++ b/src/app/shared/view-issue/view-issue.component.ts @@ -1,4 +1,5 @@ import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; +import { Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { Issue } from '../../core/models/issue.model'; import { UserRole } from '../../core/models/user.model'; @@ -53,7 +54,8 @@ export class ViewIssueComponent implements OnInit, OnDestroy, OnChanges { public permissions: PermissionService, public userService: UserService, public issueService: IssueService, - private phaseService: PhaseService + private phaseService: PhaseService, + private router: Router ) {} ngOnInit() { @@ -126,7 +128,11 @@ export class ViewIssueComponent implements OnInit, OnDestroy, OnChanges { this.issue = issue; this.pollIssue(id); }, - (err) => this.errorHandlingService.handleError(err) + (err) => { + this.router.navigateByUrl(this.phaseService.currentPhase).then(() => { + this.errorHandlingService.handleError(new Error('Invalid URL provided!')); + }); + } ); }