// Params required for calling the login() method.
interface EgAuthLoginArgs {
- username: String,
- password: String,
- workstation: String,
- type: String // staff, persist, etc.
+ username: String,
+ password: String,
+ type: String,
+ workstation?: String
}
+export enum EgAuthWsState {
+ PENDING,
+ NOT_USED,
+ NOT_FOUND_SERVER,
+ NOT_FOUND_LOCAL,
+ VALID
+};
+
@Injectable()
export class EgAuthService {
// again, when the op-change cycle has completed.
private opChangeUser: EgAuthUser;
+ workstationState: EgAuthWsState = EgAuthWsState.PENDING;
+
redirectUrl: string;
constructor(
return new Promise<any>( (resolve, reject) => {
this.egNet.request(
'open-ils.auth',
- 'open-ils.auth.session.retrieve', this.token())
- .subscribe(user => {
- // EgNetService interceps NO_SESSION events.
- // We can only get here if the session is valid.
- this.activeUser.user = user;
- this.sessionPoll();
- resolve();
- });
+ 'open-ils.auth.session.retrieve', this.token()
+ ).subscribe(
+ user => {
+ // EgNetService interceps NO_SESSION events.
+ // We can only get here if the session is valid.
+ this.activeUser.user = user;
+ this.sessionPoll();
+ resolve();
+ },
+ err => { reject(); }
+ );
});
}
// Emits event on invalid workstation.
}
- login(args: EgAuthLoginArgs, isOpChange?: boolean): Promise<any> {
+ login(args: EgAuthLoginArgs, isOpChange?: boolean): Promise<void> {
- return new Promise<any>((resolve, reject) => {
+ return new Promise<void>((resolve, reject) => {
this.egNet.request('open-ils.auth', 'open-ils.auth.login', args)
.subscribe(res => {
- this.handleLoginResponse(args, this.egEvt.parse(res), isOpChange);
- resolve(); // TODO: depends on above...
+ this.handleLoginResponse(args, this.egEvt.parse(res), isOpChange)
+ .then(
+ ok => resolve(ok),
+ notOk => reject(notOk)
+ );
});
});
}
handleLoginResponse(
- args: EgAuthLoginArgs, evt: EgEvent, isOpChange: boolean): void {
+ args: EgAuthLoginArgs, evt: EgEvent, isOpChange: boolean): Promise<void> {
switch (evt.textcode) {
case 'SUCCESS':
this.handleLoginOk(args, evt, isOpChange);
- break;
+ return Promise.resolve();
+
case 'WORKSTATION_NOT_FOUND':
- // TODO relogin without workstation and go to ws admin page
- break;
+ console.error(`No such workstation "${args.workstation}"`);
+ this.workstationState = EgAuthWsState.NOT_FOUND_SERVER;
+ delete args.workstation;
+ return this.login(args, isOpChange);
+
default:
- // TODO: reject...
console.error(`Login returned unexpected event: ${evt}`);
+ return Promise.reject('login failed');
}
}
// TODO
}
+ // Resolves if login workstation matches a workstation known to this
+ // browser instance.
+ verifyWorkstation(): Promise<void> {
+ return new Promise((resolve, reject) => {
+
+ if (!this.user()) {
+ this.workstationState = EgAuthWsState.PENDING;
+ reject();
+ return;
+ }
+
+ if (!this.user().wsid()) {
+ this.workstationState = EgAuthWsState.NOT_USED;
+ reject();
+ return;
+ }
+
+ console.debug(`Verifying workstation ${this.user().wsid()}`);
+
+ this.egStore.getItem('eg.workstation.all')
+ .then(workstations => {
+ if (!workstations) workstations = [];
+
+ var ws = workstations.filter(
+ w => {return w.id == this.user().wsid()})[0];
+
+ if (ws) {
+ this.activeUser.workstation = ws.name;
+ this.workstationState = EgAuthWsState.VALID;
+ resolve();
+ } else {
+ this.workstationState = EgAuthWsState.NOT_FOUND_LOCAL;
+ reject();
+ }
+ });
+ });
+ }
deleteSession(): void {
if (this.token()) {
a: any[];
classname: String;
_isfieldmapper: Boolean;
+ // Dynamically appended functions from the IDL.
+ [fields: string]: any;
}
@Injectable()
export class EgStoreService {
// Base path for cookie-based storage.
+ // Useful for limiting cookies to subsections of the application.
loginSessionBasePath: string;
+ // Set of keys whose values should disappear at logout.
loginSessionKeys: string[] = [
'eg.auth.token',
'eg.auth.time',
constructor(private cookieService: CookieService) {}
private parseJson(valJson: string): any {
- let val: any = null;
-
- if (valJson != null) {
- try {
- val = JSON.parse(valJson);
- } catch(E) {
- console.error(`Failure to parse JSON: ${E} => ${valJson}`);
- }
+ if (valJson == null || valJson == '') return null;
+ try {
+ return JSON.parse(valJson);
+ } catch(E) {
+ console.error(`Failure to parse JSON: ${E} => ${valJson}`);
+ return null;
}
+ }
- return val;
+ /**
+ * Add a an app-local login session key
+ */
+ addLoginSessionKey(key: string): void {
+ this.loginSessionKeys.push(key);
}
setItem(key: string, val: any, isJson?: Boolean): Promise<any> {
-
// TODO: route keys appropriately
-
this.setLocalItem(key, val, false);
return Promise.resolve();
}
}
setServerItem(key: string, val: any): Promise<any> {
- // JSON-ify on the server?
return Promise.resolve();
}
setSessionItem(key: string, val: any, isJson?: Boolean): void {
if (!isJson) val = JSON.stringify(val);
+ window.sessionStorage.setItem(key, val);
}
setLoginSessionItem(key: string, val: any, isJson?:Boolean): void {
getItem(key: string): Promise<any> {
// TODO: route keys appropriately
-
return Promise.resolve(this.getLocalItem(key));
}
}
getSessionItem(key: string): any {
+ return this.parseJson(window.sessionStorage.getItem(key));
}
getLoginSessionItem(key: string): any {
}
removeItem(key: string): Promise<any> {
- return Promise.resolve();
+ // TODO: route keys appropriately
+ return Promise.resolve(this.removeLocalItem(key));
}
removeLocalItem(key: string): void {
}
removeSessionItem(key: string): void {
+ window.sessionStorage.removeItem(key);
}
removeLoginSessionItem(key: string): void {
-import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
+import { Injectable } from '@angular/core';
import { Router, Resolve, RouterStateSnapshot,
ActivatedRouteSnapshot } from '@angular/router';
-
import { EgIdlService } from '@eg/core/idl.service';
@Injectable()
-export class EgBaseResolver implements Resolve<any> {
+export class EgBaseResolver implements Resolve<Promise<void>> {
constructor(private router: Router, private egIdl: EgIdlService) {}
resolve(
route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot): Observable<any> {
+ state: RouterStateSnapshot): Promise<void> {
console.debug('EgBaseResolver:resolve()');
this.egIdl.parseIdl();
- return Observable.empty(); // Nothing to report.
+ return Promise.resolve();
}
}
--- /dev/null
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { EgAdminRoutingModule } from './routing.module';
+
+@NgModule({
+ declarations: [],
+ imports: [ EgAdminRoutingModule ]
+})
+
+export class EgAdminModule {}
--- /dev/null
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [{
+ path: '',
+ children : [{
+ path: 'workstation',
+ loadChildren: '@eg/staff/admin/workstation/admin-ws.module#EgAdminWsModule'
+ }]
+}];
+
+@NgModule({
+ imports: [ RouterModule.forChild(routes) ],
+ exports: [ RouterModule ]
+})
+
+export class EgAdminRoutingModule {}
--- /dev/null
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { EgAdminWsRoutingModule } from './routing.module';
+import { EgWorkstationsComponent } from './workstations.component';
+
+@NgModule({
+ declarations: [
+ EgWorkstationsComponent
+ ],
+ imports: [
+ EgAdminWsRoutingModule,
+ CommonModule,
+ FormsModule
+ ]
+})
+
+export class EgAdminWsModule {}
+
--- /dev/null
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { EgWorkstationsComponent } from './workstations.component';
+
+const routes: Routes = [
+ { path: 'workstations',
+ component: EgWorkstationsComponent
+ }
+];
+
+@NgModule({
+ imports: [ RouterModule.forChild(routes) ],
+ exports: [ RouterModule ]
+})
+
+export class EgAdminWsRoutingModule {}
--- /dev/null
+
+<br/>
+<br/>
+<br/>
+<br/>
+<b> WORKSTATIONS ADMIN </b>
--- /dev/null
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { EgNetService } from '@eg/core/net.service';
+import { EgAuthService } from '@eg/core/auth.service';
+
+@Component({
+ templateUrl: 'workstations.component.html'
+})
+
+export class EgWorkstationsComponent implements OnInit {
+
+ constructor(
+ private route: ActivatedRoute,
+ private egNet: EgNetService,
+ private egAuth: EgAuthService
+ ) {}
+
+ ngOnInit() {
+
+ console.log('EgWorkstationsComponent:ngOnInit()');
+
+ }
+}
+
+
-import { Injectable } from '@angular/core';
+import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot,
- CanActivateChild } from '@angular/router';
-import { EgAuthService } from '@eg/core/auth.service';
+ CanActivateChild } from '@angular/router';
+import { EgStoreService } from '@eg/core/store.service';
+import { EgAuthService } from '@eg/core/auth.service';
/**
* Confirm we have a valid auth token before allowing access
@Injectable()
export class EgStaffAuthGuard implements CanActivate, CanActivateChild {
- constructor(private egAuth: EgAuthService, private router: Router) {}
+ readonly WS_ADMIN_PATH = '/staff/admin/workstation/workstations';
+
+ constructor(
+ private router: Router,
+ private egStore: EgStoreService,
+ private egAuth: EgAuthService
+ ) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Promise<boolean> {
- console.debug('EgStaffAuthGuard:canActivate()');
+ console.debug(`EgStaffAuthGuard:canActivate() path ${state.url}`);
+
+ // Staff cookies stay in /$base/staff/
+ // TODO dynamic
+ this.egStore.loginSessionBasePath = '/webby/staff';
+
+ // Any and all are allowed access to the login page.
+ if (state.url == '/staff/login') return Promise.resolve(true);
- // Note: avoid verifying the workstation here, since the
- // workstation admin page requires access to this route.
+ // canActivate() always resolves to true, but may redirect
+ // the caller to the appropriate auth pages along the way.
return new Promise((resolve, error) => {
this.egAuth.testAuthToken().then(
- ok => { resolve(true); },
- err => {
+ ok => {
+ if (ok.invalidWorkstation
+ && state.url != this.WS_ADMIN_PATH
+ ) {
+ // Login is valid, but workstation is unknown
+ // to this browser. Send the caller to the
+ // workstation admin page.
+ this.router.navigate([this.WS_ADMIN_PATH]);
+ }
+ resolve(true);
+ },
+ notOk => {
+ console.debug('No valid auth token, sending to login.');
this.egAuth.redirectUrl = state.url;
this.router.navigate(['/staff/login']);
- resolve(false); // cannot activate
+ resolve(true);
}
);
});
canActivateChild(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Promise<boolean> {
+ console.log('canActivateChild()');
return this.canActivate(route, state);
}
}
+++ /dev/null
-import { NgModule } from '@angular/core';
-import { RouterModule, Routes } from '@angular/router';
-import { EgCircComponent } from './circ.component';
-
-const routes: Routes = [
- { path: '',
- component: EgCircComponent,
- children : [
- { path: 'patron/bcsearch',
- loadChildren: '@eg/staff/circ/patron/bcsearch/bcsearch.module#EgBcSearchModule'
- }
- ]
- },
-];
-
-@NgModule({
- imports: [ RouterModule.forChild(routes) ],
- exports: [ RouterModule ]
-})
-
-export class EgCircRoutingModule {}
+++ /dev/null
-import { Component } from '@angular/core';
-import { Router } from '@angular/router';
-
-@Component({
- template: '<router-outlet></router-outlet>'
-})
-
-export class EgCircComponent { }
-
-
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
-
-import { EgCircComponent } from './circ.component';
-import { EgCircRoutingModule } from './circ-routing.module';
+import { EgCircRoutingModule } from './routing.module';
@NgModule({
declarations: [
- EgCircComponent
],
imports: [
EgCircRoutingModule
'opensrf.system.echo',
'hello', 'goodbye', 'in the middle'
).subscribe(res => this.strList.push(res));
-
- this.egNet.request(
- 'open-ils.actor',
- 'opensrf.system.echo',
- {textcode : 'NO_SESSION', code: 123, desc: 'test desc'}
- ).subscribe(
- x => console.log(x),
- e => console.log('echo event: ' + e),
- () => console.log('done')
- );
}
findUser(): void {
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
-import { EgNetService } from '@eg/core/net.service';
import { EgBcSearchComponent } from './bcsearch.component';
import { EgBcSearchRoutingModule } from './bcsearch-routing.module';
CommonModule,
FormsModule
],
- providers: [EgNetService]
})
-export class EgBcSearchModule {
+export class EgBcSearchModule {}
-}
--- /dev/null
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [{
+ path: '',
+ children : [{
+ path: 'patron',
+ children: [{
+ path: 'bcsearch',
+ loadChildren: '@eg/staff/circ/patron/bcsearch/bcsearch.module#EgBcSearchModule'
+ }]
+ }]
+}];
+
+@NgModule({
+ imports: [ RouterModule.forChild(routes) ],
+ exports: [ RouterModule ]
+})
+
+export class EgCircRoutingModule {}
-import { Injectable } from '@angular/core';
+import { Injectable } from '@angular/core';
import { Router, Resolve, RouterStateSnapshot,
ActivatedRouteSnapshot } from '@angular/router';
-import { EgAuthService } from '@eg/core/auth.service';
+import { Observable, Observer } from 'rxjs/Rx';
+import { EgAuthService } from '@eg/core/auth.service';
+import { EgNetService } from '@eg/core/net.service';
/**
- * Load post-authentication data required by all staff UI's
+ * Verify authentication info and load common startup data.
*/
@Injectable()
-export class EgStaffDataResolver implements Resolve<Promise<boolean>> {
+export class EgStaffDataResolver implements Resolve<Observable<any>> {
+
+ private WS_ADMIN_URL = '/staff/admin/workstation/workstations';
constructor(
private router: Router,
+ private egNet: EgNetService,
private egAuth: EgAuthService
) {}
resolve(
route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot): Promise<boolean> {
+ state: RouterStateSnapshot): Observable<any> {
console.debug('EgStaffDataResolver:resolve()');
- // TODO verify workstation
+ // Listen for auth timeout failures
+ this.egNet.authExpired$.subscribe(
+ uhOh => {
+ console.log('Auth session has expired. Send to login');
+ this.egAuth.redirectUrl = this.router.url;
+ this.router.navigate(['/staff/login']);
+ }
+ );
- let wsPath = '/staff/admin/workstation';
+ return Observable.create(observer => {
+
+ console.debug('auth token => ' + this.egAuth.token());
- if (false) { // WS is invalid
- if (this.router.url != wsPath) {
- console.debug('re-routing to workstation admin page');
- this.router.navigate([wsPath]);
- }
- }
+ this.checkAuth().then(
+ ok => {
+ this.loadStartupData(observer);
+ // route resolvers require at least one observable event.
+ // until we emit other data, just return true.
+ observer.next(true);
+ observer.complete();
+ },
+ notOk => {
+ // Auth-related re-routing occurs within checkAuth.
+ observer.next(true);
+ observer.complete();
+ }
+ );
+ });
+ }
+
+ // Resolves if the caller should continue, rejects otherwise.
+ checkAuth(): Promise<void> {
+ console.log('checkAuth()');
+ return new Promise((resolve, reject) => {
+ console.log('checkAuth(2');
+ this.egAuth.testAuthToken().then(
+ ok => {return this.egAuth.verifyWorkstation()},
+ notOk => {
+ // No valid authtoken, redirect to login page
+ this.egAuth.redirectUrl = this.router.url;
+ this.router.navigate(['/staff/login']);
+ reject();
+ }
+ ).then(
+ ok => {
+ // workstation verified.
+ resolve();
+ },
+ notOk => {
+ console.log('checkAuth(3)');
+ // Login was valid, but we don't know about the
+ // workstation used.
+ if (this.router.url != this.WS_ADMIN_URL) {
+ console.log('checkAuth(4) ' + this.router.url);
+ this.router.navigate([this.WS_ADMIN_URL]);
+ }
+ reject();
+ }
+ );
+ });
+ }
- return Promise.resolve(true);
+ loadStartupData(observer: Observer<any>): Promise<void> {
+ return Promise.resolve();
}
}
<div class="col-md-6 offset-md-3">
<fieldset>
<legend i18n>Sign In</legend>
+ <hr/>
<form (ngSubmit)="handleSubmit()" #loginForm="ngForm">
<div class="form-group">
import { Component, OnInit, Renderer } from '@angular/core';
import { Router } from '@angular/router';
-import { EgAuthService } from '@eg/core/auth.service';
+import { EgAuthService, EgAuthWsState } from '@eg/core/auth.service';
@Component({
templateUrl : './login.component.html'
username : '',
password : '',
type : 'staff',
- workstation : 'BR1-skiddoo'
+ workstation : ''
+ //workstation : 'BR1-skiddoo' // testing
};
workstations = [];
constructor(
private router: Router,
- private egAuth: EgAuthService,
- private renderer: Renderer
+ private renderer: Renderer,
+ private egAuth: EgAuthService
) {}
ngOnInit() {
// Focus username
this.renderer.selectRootElement('#username').focus();
- // load local workstation data
+ // load browser-local workstation data
}
handleSubmit() {
- // where are we go after succesful login
+
+ // post-login URL
let url: string = this.egAuth.redirectUrl || '/staff/splash';
- this.egAuth.login(this.args).then(res => {
- console.debug('Login succeeded');
- this.egAuth.redirectUrl = null;
- console.log(`Routing to URL: ${url}`);
- this.router.navigate([url]);
- });
+ this.egAuth.login(this.args).then(
+ ok => {
+ this.egAuth.redirectUrl = null;
+ if (this.egAuth.workstationState == EgAuthWsState.NOT_FOUND_SERVER) {
+ // User is logged in without a workstation.
+ // Redirect them to the WS admin page.
+ url = '/staff/admin/workstation/workstations';
+ }
+ this.router.navigate([url]);
+ },
+ notOk => {
+ // indicate failure in the UI.
+ }
+ );
}
}
+++ /dev/null
-import { Component, OnInit } from '@angular/core';
-import { Router } from '@angular/router';
-import { EgAuthService } from '@eg/core/auth.service';
-
-@Component({
- template : '<div></div>'
-})
-
-export class EgStaffLogoutComponent implements OnInit {
-
- constructor(
- private router: Router,
- private egAuth: EgAuthService,
- ) {}
-
- ngOnInit() {
- this.egAuth.logout();
- this.router.navigate(['/staff/login']);
- }
-}
<li ngbDropdown class="nav-item dropdown">
<a ngbDropdownToggle i18n class="nav-link dropdown-toggle">Hamburger</a>
<div class="dropdown-menu" ngbDropdownMenu>
- <a i18n class="dropdown-item" routerLink="/staff/logout">Logout</a>
+ <a i18n class="dropdown-item" routerLink="/staff/login">Logout</a>
</div>
</li>
</ul>
-import { Injectable } from '@angular/core';
+import { Injectable } from '@angular/core';
+import { Observable, Observer } from 'rxjs/Rx';
import { Router, Resolve, RouterStateSnapshot,
ActivatedRouteSnapshot } from '@angular/router';
-import { EgStoreService } from '@eg/core/store.service';
-import { EgAuthService } from '@eg/core/auth.service';
+import { EgStoreService } from '@eg/core/store.service';
+import { EgNetService } from '@eg/core/net.service';
+import { EgAuthService } from '@eg/core/auth.service';
/**
* Apply configuration, etc. required by all staff components.
* See EgStaffCommonDataResolver for staff-wide, post-auth activities.
*/
@Injectable()
-export class EgStaffResolver implements Resolve<Promise<boolean>> {
+export class EgStaffResolver implements Resolve<Observable<any>> {
+
+ readonly loginPath = '/staff/login';
+ readonly wsAdminPath = '/staff/admin/workstation/workstations';
constructor(
private router: Router,
private egStore: EgStoreService,
+ private egNet: EgNetService,
private egAuth: EgAuthService
) {}
resolve(
route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot): Promise<boolean> {
- // Staff-global configuration, etc.
+ state: RouterStateSnapshot): Observable<any> {
console.debug('EgStaffResolver:resolve()');
// Staff cookies stay in /$base/staff/
this.egStore.loginSessionBasePath = '/webby/staff'; // TODO dynamic
- return Promise.resolve(true);
+ // Login resets everything. No need to load any data.
+ if (state.url == '/staff/login') return Observable.of(true);
+
+console.log('1');
+
+ return Observable.create(observer => {
+console.log('2');
+ this.egAuth.testAuthToken().then(
+ ok => {
+console.log('3');
+ // Authtoken is OK.
+ this.egAuth.verifyWorkstation().then(
+ ok => {
+console.log('4');
+ // Workstation is OK.
+ this.loadStartupData(observer).then(
+ ok => observer.complete()
+ );
+ },
+ notOk => {
+console.log('5');
+ // Workstation is not OK.
+ if (state.url != this.wsAdminPath] {
+ this.router.navigate([this.wsAdminPath]);
+ }
+ observer.complete();
+ }
+ );
+ },
+ notOk => {
+console.log('6');
+ // Authtoken is not OK.
+ this.egAuth.redirectUrl = this.router.url;
+ this.router.navigate([this.loginPath]);
+ observer.complete();
+ }
+ );
+ });
+ }
+
+ loadStartupData(observer: Observer<any>): Promise<void> {
+ return Promise.resolve();
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EgStaffResolver } from './resolver.service';
-import { EgStaffDataResolver } from './data-resolver.service';
-import { EgStaffAuthGuard } from './auth-guard.service';
+//import { EgStaffDataResolver } from './data-resolver.service';
import { EgStaffComponent } from './staff.component';
import { EgStaffLoginComponent } from './login.component';
-import { EgStaffLogoutComponent } from './logout.component';
import { EgStaffSplashComponent } from './splash.component';
+// Not using 'canActivate' because it's called before all resolvers,
+// but the resolvers parse the IDL, etc.
+
const routes: Routes = [{
path: '',
+ component: EgStaffComponent,
resolve: {staffResolver : EgStaffResolver},
children: [{
+ path: '',
+ redirectTo: 'splash', // must be to sibling path
+ pathMatch: 'full',
+ }, {
path: 'login',
component: EgStaffLoginComponent
}, {
- path: 'logout',
- component: EgStaffLogoutComponent
+ path: 'splash',
+ component: EgStaffSplashComponent
}, {
- path: '',
- // Require a valid authtoken to access child paths
- canActivate : [EgStaffAuthGuard],
- // Load data common to all staff UI's before loading child paths.
- resolve: {dataResolver: EgStaffDataResolver},
- // EgStaffComponent houses the navbar and the page content shell.
- component: EgStaffComponent,
- children: [{
- path: '',
- redirectTo: 'splash', // must be to sibling path
- pathMatch: 'full',
- }, {
- path: 'splash',
- component: EgStaffSplashComponent
- }, {
- // Lazy-load collections of sub-modules (circ, cat, etc.)
- // with loadChildren
- path: 'circ',
- loadChildren : '@eg/staff/circ/circ.module#EgCircModule'
- }]
+ path: 'circ',
+ loadChildren : '@eg/staff/circ/circ.module#EgCircModule'
+ }, {
+ path: 'admin',
+ loadChildren : '@eg/staff/admin/admin.module#EgAdminModule'
}]
}];
exports: [ RouterModule ],
providers: [
EgStaffResolver,
- EgStaffDataResolver,
- EgStaffAuthGuard
+// EgStaffDataResolver
]
})
<br/>
<br/>
<br/>
-<br/>
<b>Staff Splash Page</b>
+<br/>
+Some links to test...
+
+<a routerLink="/staff/admin/workstation/workstations">Workstation Admin</a>
+
import { Component, OnInit } from '@angular/core';
-import { Router, ActivatedRoute } from '@angular/router';
+import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
+import { EgAuthService, EgAuthWsState } from '@eg/core/auth.service';
+import { EgNetService } from '@eg/core/net.service';
@Component({
templateUrl: 'staff.component.html'
export class EgStaffComponent implements OnInit {
+ readonly loginPath = '/staff/login';
+ readonly wsAdminPath = '/staff/admin/workstation/workstations';
+
constructor(
private router: Router,
- private route: ActivatedRoute) {}
+ private route: ActivatedRoute,
+ private egNet: EgNetService,
+ private egAuth: EgAuthService
+ ) {}
ngOnInit() {
- console.debug(`EgStaffComponent loading route ${this.router.url}`);
+ // Fires on all in-app router navigation, but not initial page load.
+ this.router.events.subscribe(routeEvent => {
+ if (routeEvent instanceof NavigationEnd) {
+ console.debug(`EgStaffComponent routing to ${routeEvent.url}`);
+ this.basicAuthChecks(routeEvent);
+ }
+ });
- /*
- if (this.router.url == '/staff') {
- this.router.navigate(['/staff/splash']);
- }
- */
+ // Redirect to the login page on any auth timeout events.
+ this.egNet.authExpired$.subscribe(uhOh => {
+ console.log('Auth session has expired. Send to login');
+ this.egAuth.redirectUrl = this.router.url;
+ this.router.navigate(['/staff/login']);
+ });
this.route.data.subscribe((data: {staffResolver : any}) => {
console.debug('EgStaff ngOnInit complete');
});
}
+
+ /**
+ * Verifying auth token on every route is overkill, since an expired
+ * token will make itself known with the first API call, but we do
+ * want to prevent navigation from the login or workstation admin
+ * page, since these can be accessed without a valid authtoken or
+ * workstation, respectively, once the initial route resolvers
+ * have done their jobs.
+ */
+ basicAuthChecks(routeEvent: NavigationEnd): void {
+ if (!this.egAuth.token()) {
+ if (routeEvent.url != this.loginPath) {
+ this.router.navigate([this.loginPath]);
+ }
+ } else if (this.egAuth.workstationState != EgAuthWsState.VALID) {
+ if (routeEvent.url != this.wsAdminPath) {
+ this.router.navigate([this.wsAdminPath]);
+ }
+ }
+ }
}
import { EgStaffRoutingModule } from './routing.module';
import { EgStaffNavComponent } from './nav.component';
import { EgStaffLoginComponent } from './login.component';
-import { EgStaffLogoutComponent } from './logout.component';
import { EgStaffSplashComponent } from './splash.component';
@NgModule({
EgStaffComponent,
EgStaffNavComponent,
EgStaffSplashComponent,
- EgStaffLoginComponent,
- EgStaffLogoutComponent
+ EgStaffLoginComponent
],
imports: [
EgStaffRoutingModule,