Skip to content

Commit

Permalink
fix angular app
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanbas21 committed Nov 29, 2023
1 parent 43616b3 commit a69283f
Show file tree
Hide file tree
Showing 89 changed files with 5,759 additions and 56 deletions.
2 changes: 1 addition & 1 deletion angular-todo/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# APP_URL=$APP_URL # not using this for preview-environment instead, we can use window.location.origin
APP_URL=$APP_URL
AM_URL=$AM_URL
API_URL=$API_URL
DEBUGGER_OFF=true
Expand Down
1 change: 1 addition & 0 deletions angular-todo/set-env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ let targetPath =
: 'src/environments/environment.ts';

const envConfigFile = `export const environment = {
APP_URL: '${process.env.APP_URL || window.location.href}',
AM_URL: '${process.env.AM_URL}',
REALM_PATH: '${process.env.REALM_PATH}',
WEB_OAUTH_CLIENT: '${process.env.WEB_OAUTH_CLIENT}',
Expand Down
36 changes: 36 additions & 0 deletions angular-todo/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* angular-todo-prototype
*
* app-routing.module.ts
*
* Copyright (c) 2021 ForgeRock. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './views/home/home.component';
import { LoginComponent } from './views/login/login.component';
import { TodosComponent } from './views/todos/todos.component';
import { AuthGuard } from './auth/auth.guard';
import { RegisterComponent } from './views/register/register.component';
import { LogoutComponent } from './features/logout/logout.component';

const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'todos', canActivate: [AuthGuard], component: TodosComponent },
{ path: 'logout', component: LogoutComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' },
];

/**
* Defines the routes and auth guards for the application
*/
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
18 changes: 18 additions & 0 deletions angular-todo/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!--
angular-todo-prototype
app.component.html
Copyright (c) 2021 ForgeRock. All rights reserved.
This software may be modified and distributed under the terms
of the MIT license. See the LICENSE file for details.
-->

<div id="root" class="cstm_root">
<router-outlet></router-outlet>
<div *ngIf="loading" class="cstm_container_v-centered container-fluid d-flex align-items-center">
<div class="w-100">
<app-loading message="Verifying access ..."></app-loading>
</div>
</div>
</div>
64 changes: 23 additions & 41 deletions angular-todo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
* of the MIT license. See the LICENSE file for details.
*/

import { OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { Config, UserManager } from '@forgerock/javascript-sdk';
import { Component, OnInit } from '@angular/core';
import { environment } from '../environments/environment';
import { UserService } from './services/user.service';
import { Router } from '@angular/router';
import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart } from '@angular/router';
import { Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import { Config, Tokens, TokenStorage, UserManager } from '@forgerock/javascript-sdk';
import {
NavigationCancel,
NavigationEnd,
NavigationError,
NavigationStart,
Router,
} from '@angular/router';
import { filter, Observable } from 'rxjs';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
Expand All @@ -30,17 +34,17 @@ export class AppComponent implements OnInit {
private router: Router,
) {
const navStart = router.events.pipe(
filter((evt: any) => evt instanceof NavigationStart),
filter((evt) => evt instanceof NavigationStart),
) as Observable<NavigationStart>;

const navEnd: Observable<NavigationStart> = router.events.pipe(
filter(
(evt: any) =>
(evt) =>
evt instanceof NavigationEnd ||
evt instanceof NavigationCancel ||
evt instanceof NavigationError,
),
);
) as Observable<NavigationStart>;

navStart.subscribe(() => (this.loading = true));
navEnd.subscribe(() => (this.loading = false));
Expand All @@ -50,48 +54,26 @@ export class AppComponent implements OnInit {
* Initialise the SDK and try to load the user when the app loads
*/
async ngOnInit(): Promise<void> {
/** ***************************************************************************
* SDK INTEGRATION POINT
* Summary: Configure the SDK
* ----------------------------------------------------------------------------
* Details: Below, you will see the following settings:
* - clientId: (OAuth 2.0 only) this is the OAuth 2.0 client you created in ForgeRock, such as `ForgeRockSDKClient`
* - redirectUri: (OAuth 2.0 only) this is the URI/URL of this app to which the
* OAuth 2.0 flow redirects
* - scope: (OAuth 2.0 only) these are the OAuth scopes that you will request from
* ForgeRock
* - serverConfig: this includes the baseUrl of your ForgeRock AM, and should
* include the deployment path at the end, such as `/am/` or `/openam/`
* - realmPath: this is the realm to use within ForgeRock. such as `alpha` or `root`
* - tree: The authentication journey/tree to use, such as `sdkAuthenticationTree`
*************************************************************************** */

Config.set({
clientId: environment.WEB_OAUTH_CLIENT,
redirectUri: `${window.location.origin}/callback.html`,
redirectUri: environment.APP_URL,
scope: 'openid profile email',
serverConfig: {
baseUrl: environment.AM_URL,
timeout: 3000, // 9000 or less
timeout: 30000, // 90000 or less
},
realmPath: environment.REALM_PATH,
tree: environment.JOURNEY_LOGIN,
});

/** *****************************************************************
* SDK INTEGRATION POINT
* Summary: Optional client-side route access validation
* ------------------------------------------------------------------
* Details: Here, you could just make sure tokens exist –
* TokenStorage.get() – or, validate tokens, renew expiry timers,
* session checks ... Below, we are calling the userinfo endpoint to
* ensure valid tokens before continuing, but it's optional.
***************************************************************** */
try {
// Assume user is likely authenticated if there are tokens
const info = await UserManager.getCurrentUser();
this.userService.isAuthenticated = true;
this.userService.info = info;
const tokens = await TokenStorage.get();
if (tokens !== undefined) {
// Assume user is likely authenticated if there are tokens
const info = await UserManager.getCurrentUser();
this.userService.isAuthenticated = true;
this.userService.info = info;
}
} catch (err) {
// User likely not authenticated
console.log(err);
Expand Down
95 changes: 95 additions & 0 deletions angular-todo/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* angular-todo-prototype
*
* app.module.ts
*
* Copyright (c) 2021 ForgeRock. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { LoginComponent } from './views/login/login.component';
import { TextComponent } from './features/journey/text/text.component';
import { PasswordComponent } from './features/journey/password/password.component';
import { HomeComponent } from './views/home/home.component';
import { TodosComponent } from './views/todos/todos.component';
import { LogoutComponent } from './features/logout/logout.component';
import { TodoComponent } from './features/todo/todo.component';
import { BackHomeComponent } from './utilities/back-home/back-home.component';
import { LoadingComponent } from './utilities/loading/loading.component';
import { HomeIconComponent } from './icons/home-icon/home-icon.component';
import { LeftArrowIconComponent } from './icons/left-arrow-icon/left-arrow-icon.component';
import { KeyIconComponent } from './icons/key-icon/key-icon.component';
import { FormComponent } from './features/journey/form/form.component';
import { ButtonComponent } from './features/journey/button/button.component';
import { EyeIconComponent } from './icons/eye-icon/eye-icon.component';
import { AlertComponent } from './features/journey/alert/alert.component';
import { AlertIconComponent } from './icons/alert-icon/alert-icon.component';
import { VerifiedIconComponent } from './icons/verified-icon/verified-icon.component';
import { RegisterComponent } from './views/register/register.component';
import { UnknownComponent } from './features/journey/unknown/unknown.component';
import { BooleanComponent } from './features/journey/boolean/boolean.component';
import { TermsConditionsComponent } from './features/journey/terms-conditions/terms-conditions.component';
import { KbaComponent } from './features/journey/kba/kba.component';
import { LockIconComponent } from './icons/lock-icon/lock-icon.component';
import { NewUserIconComponent } from './icons/new-user-icon/new-user-icon.component';
import { HeaderComponent } from './layout/header/header.component';
import { FooterComponent } from './layout/footer/footer.component';
import { AngularIconComponent } from './icons/angular-icon/angular-icon.component';
import { ForgerockIconComponent } from './icons/forgerock-icon/forgerock-icon.component';
import { TodosIconComponent } from './icons/todos-icon/todos-icon.component';
import { AccountIconComponent } from './icons/account-icon/account-icon.component';
import { TodoIconComponent } from './icons/todo-icon/todo-icon.component';
import { ActionIconComponent } from './icons/action-icon/action-icon.component';
import { ChoiceComponent } from './features/journey/choice/choice.component';

@NgModule({
declarations: [
AppComponent,
LoginComponent,
TextComponent,
PasswordComponent,
HomeComponent,
TodosComponent,
LogoutComponent,
TodoComponent,
BackHomeComponent,
LoadingComponent,
HomeIconComponent,
LeftArrowIconComponent,
KeyIconComponent,
FormComponent,
ButtonComponent,
EyeIconComponent,
AlertComponent,
AlertIconComponent,
VerifiedIconComponent,
RegisterComponent,
UnknownComponent,
BooleanComponent,
TermsConditionsComponent,
KbaComponent,
LockIconComponent,
NewUserIconComponent,
HeaderComponent,
FooterComponent,
AngularIconComponent,
ForgerockIconComponent,
TodosIconComponent,
AccountIconComponent,
TodoIconComponent,
ActionIconComponent,
ChoiceComponent,
],
imports: [BrowserModule, AppRoutingModule, FormsModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
57 changes: 57 additions & 0 deletions angular-todo/src/app/auth/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* angular-todo-prototype
*
* auth.guard.ts
*
* Copyright (c) 2021 ForgeRock. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
RouterStateSnapshot,
UrlTree,
Router,
} from '@angular/router';
import { UserService } from '../services/user.service';
import { Tokens, TokenStorage, UserManager } from '@forgerock/javascript-sdk';

@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(
public userService: UserService,
private router: Router,
) {}

/**
* Extends CanActivate to protect selected routes from unauthenticated access
*
* @param next - Route that the user is trying to access
* @param state - Router state
* @returns Promise - Boolean or route to redirect the user to
*/
async canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Promise<true | UrlTree> {
const loginUrl = this.router.parseUrl('/login');
try {
// Assume user is likely authenticated if there are tokens
const tokens = await TokenStorage.get();
const info = await UserManager.getCurrentUser();
if (tokens === undefined || info === undefined) {
return loginUrl;
}
return true;
} catch (err) {
// User likely not authenticated
console.log(err);
return loginUrl;
}
}
}
30 changes: 30 additions & 0 deletions angular-todo/src/app/features/journey/alert/alert.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!--
angular-todo-prototype
alert.component.html
Copyright (c) 2021 ForgeRock. All rights reserved.
This software may be modified and distributed under the terms
of the MIT license. See the LICENSE file for details.
-->

<!--
Display the message in a danger or success style alert depending on the type
-->
<container-element [ngSwitch]="type">
<p *ngSwitchCase="'error'" class="alert alert-danger d-flex align-items-center mt-1" role="alert">
<app-alert-icon></app-alert-icon>
<span class="ps-2">{{ message }}</span>
</p>
<p
*ngSwitchCase="'success'"
class="alert alert-success d-flex align-items-center mt-5"
role="alert"
>
<app-verified-icon size="36px"></app-verified-icon>
<span class="ps-2">{{ message }}</span>
</p>
<p *ngSwitchDefault class="alert d-flex align-items-center mt-5" role="alert">
<span class="ps-2">{{ message }}</span>
</p>
</container-element>
30 changes: 30 additions & 0 deletions angular-todo/src/app/features/journey/alert/alert.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* angular-todo-prototype
*
* alert.component.ts
*
* Copyright (c) 2021 ForgeRock. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import { Component, Input } from '@angular/core';

/**
* Used for displaying for errors
*/
@Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
})
export class AlertComponent {
/**
* Determines whether this is an error or success alert
*/
@Input() type?: string;

/**
* The message to display
*/
@Input() message?: string;
}
Loading

0 comments on commit a69283f

Please sign in to comment.