From cebe31583ba0d7ec1c90e94a66db00c8ab65e987 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 14 Jun 2022 16:33:08 -0400 Subject: [PATCH] LP1840773 SCKO Angular Signed-off-by: Bill Erickson --- Open-ILS/src/eg2/src/app/core/auth.service.ts | 28 +++---- .../src/eg2/src/app/scko/banner.component.html | 6 +- Open-ILS/src/eg2/src/app/scko/banner.component.ts | 22 +++--- Open-ILS/src/eg2/src/app/scko/scko.component.ts | 2 + Open-ILS/src/eg2/src/app/scko/scko.service.ts | 89 +++++++++++++++++++++- 5 files changed, 118 insertions(+), 29 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/core/auth.service.ts b/Open-ILS/src/eg2/src/app/core/auth.service.ts index 682b730855..f549cba4a6 100644 --- a/Open-ILS/src/eg2/src/app/core/auth.service.ts +++ b/Open-ILS/src/eg2/src/app/core/auth.service.ts @@ -41,7 +41,7 @@ export enum AuthWsState { export class AuthService { // Override this to store authtokens, etc. in a different location - storePrefix = 'eg.auth'; + authDomain = 'eg.auth'; private authChannel: any; @@ -65,7 +65,7 @@ export class AuthService { // Returns true if we are currently in op-change mode. opChangeIsActive(): boolean { - return Boolean(this.store.getLoginSessionItem(`${this.storePrefix}.time.oc`)); + return Boolean(this.store.getLoginSessionItem(`${this.authDomain}.time.oc`)); } // - Accessor functions always refer to the active user. @@ -95,8 +95,8 @@ export class AuthService { // Only necessary on new page loads. During op-change, // for example, we already have an activeUser. this.activeUser = new AuthUser( - this.store.getLoginSessionItem(`${this.storePrefix}.token`), - this.store.getLoginSessionItem(`${this.storePrefix}.time`) + this.store.getLoginSessionItem(`${this.authDomain}.token`), + this.store.getLoginSessionItem(`${this.authDomain}.time`) ); } @@ -178,8 +178,8 @@ export class AuthService { handleLoginOk(args: AuthLoginArgs, evt: EgEvent, isOpChange: boolean): Promise { if (isOpChange) { - this.store.setLoginSessionItem(`${this.storePrefix}.token.oc`, this.token()); - this.store.setLoginSessionItem(`${this.storePrefix}.time.oc`, this.authtime()); + this.store.setLoginSessionItem(`${this.authDomain}.token.oc`, this.token()); + this.store.setLoginSessionItem(`${this.authDomain}.time.oc`, this.authtime()); } this.activeUser = new AuthUser( @@ -188,8 +188,8 @@ export class AuthService { args.workstation ); - this.store.setLoginSessionItem(`${this.storePrefix}.token`, this.token()); - this.store.setLoginSessionItem(`${this.storePrefix}.time`, this.authtime()); + this.store.setLoginSessionItem(`${this.authDomain}.token`, this.token()); + this.store.setLoginSessionItem(`${this.authDomain}.time`, this.authtime()); return Promise.resolve(); } @@ -198,14 +198,14 @@ export class AuthService { if (this.opChangeIsActive()) { this.deleteSession(); this.activeUser = new AuthUser( - this.store.getLoginSessionItem(`${this.storePrefix}.token.oc`), - this.store.getLoginSessionItem(`${this.storePrefix}.time.oc`), + this.store.getLoginSessionItem(`${this.authDomain}.token.oc`), + this.store.getLoginSessionItem(`${this.authDomain}.time.oc`), this.activeUser.workstation ); - this.store.removeLoginSessionItem(`${this.storePrefix}.token.oc`); - this.store.removeLoginSessionItem(`${this.storePrefix}.time.oc`); - this.store.setLoginSessionItem(`${this.storePrefix}.token`, this.token()); - this.store.setLoginSessionItem(`${this.storePrefix}.time`, this.authtime()); + this.store.removeLoginSessionItem(`${this.authDomain}.token.oc`); + this.store.removeLoginSessionItem(`${this.authDomain}.time.oc`); + this.store.setLoginSessionItem(`${this.authDomain}.token`, this.token()); + this.store.setLoginSessionItem(`${this.authDomain}.time`, this.authtime()); } // Re-fetch the user. return this.testAuthToken(); diff --git a/Open-ILS/src/eg2/src/app/scko/banner.component.html b/Open-ILS/src/eg2/src/app/scko/banner.component.html index 61e6aa9c16..16450459f9 100644 --- a/Open-ILS/src/eg2/src/app/scko/banner.component.html +++ b/Open-ILS/src/eg2/src/app/scko/banner.component.html @@ -16,13 +16,15 @@ + [(ngModel)]="patronUsername" name="patron-username" + placeholder="Username or Barcode" i18n-placeholder> + [(ngModel)]="patronUsername" name="patron-password" + placeholder="Password" i18n-placeholder> diff --git a/Open-ILS/src/eg2/src/app/scko/banner.component.ts b/Open-ILS/src/eg2/src/app/scko/banner.component.ts index 8bd9a56b8e..833d46f794 100644 --- a/Open-ILS/src/eg2/src/app/scko/banner.component.ts +++ b/Open-ILS/src/eg2/src/app/scko/banner.component.ts @@ -14,15 +14,16 @@ import {OrgService} from '@eg/core/org.service'; export class SckoBannerComponent implements OnInit { workstations: any[]; - loginFailed = false; workstationNotFound = false; patronUsername: string; patronPassword: string; + patronLoginFailed = false; staffUsername: string; staffPassword: string; staffWorkstation: string; + staffLoginFailed = false; constructor( private route: ActivatedRoute, @@ -37,10 +38,6 @@ export class SckoBannerComponent implements OnInit { const node = document.getElementById('staff-username'); - console.log('PFX', this.scko.auth.storePrefix); - console.log(this.scko.auth.token()); - console.log(this.scko.auth.user()); - // NOTE: Displaying a list of workstations will not work for users // of Hatch until the extension is updated to support /eg2/*/scko this.store.getWorkstations() @@ -67,7 +64,7 @@ export class SckoBannerComponent implements OnInit { submitStaffLogin() { - this.loginFailed = false; + this.staffLoginFailed = false; const args = { type: 'persistent', @@ -76,14 +73,14 @@ export class SckoBannerComponent implements OnInit { workstation: this.staffWorkstation }; - this.loginFailed = false; + this.staffLoginFailed = false; this.workstationNotFound = false; this.auth.login(args).then( ok => { if (this.auth.workstationState === AuthWsState.NOT_FOUND_SERVER) { - this.loginFailed = true; + this.staffLoginFailed = true; this.workstationNotFound = true; } else { @@ -93,8 +90,6 @@ export class SckoBannerComponent implements OnInit { this.org.clearCachedSettings().then(_ => { // Force reload of the app after a successful login. - // This allows the route resolver to re-run with a - // valid auth token and workstation. window.location.href = this.ngLocation.prepareExternalUrl('/scko'); @@ -102,12 +97,17 @@ export class SckoBannerComponent implements OnInit { } }, notOk => { - this.loginFailed = true; + this.staffLoginFailed = true; } ); } submitPatronLogin() { + this.patronLoginFailed = false; + this.scko.loadPatron(this.patronUsername, this.patronPassword) + .finally(() => { + this.patronLoginFailed = this.scko.patron === null; + }); } } diff --git a/Open-ILS/src/eg2/src/app/scko/scko.component.ts b/Open-ILS/src/eg2/src/app/scko/scko.component.ts index e3f90a50bc..31a5bf8f47 100644 --- a/Open-ILS/src/eg2/src/app/scko/scko.component.ts +++ b/Open-ILS/src/eg2/src/app/scko/scko.component.ts @@ -2,6 +2,7 @@ import {Component, OnInit, ViewEncapsulation} from '@angular/core'; import {Router, ActivatedRoute, NavigationEnd} from '@angular/router'; import {AuthService} from '@eg/core/auth.service'; import {SckoService} from './scko.service'; +import {ServerStoreService} from '@eg/core/server-store.service'; @Component({ templateUrl: 'scko.component.html', @@ -18,6 +19,7 @@ export class SckoComponent implements OnInit { ) {} ngOnInit() { + this.scko.load(); } } diff --git a/Open-ILS/src/eg2/src/app/scko/scko.service.ts b/Open-ILS/src/eg2/src/app/scko/scko.service.ts index cdfc91df81..c0854610b0 100644 --- a/Open-ILS/src/eg2/src/app/scko/scko.service.ts +++ b/Open-ILS/src/eg2/src/app/scko/scko.service.ts @@ -11,12 +11,97 @@ export class SckoService { // Currently active patron account object. patron: IdlObject; + barcodeRegex: RegExp; + patronPasswordRequired = false; constructor( private net: NetService, + private evt: EventService, + private serverStore: ServerStoreService, public auth: AuthService - ) { - this.auth.storePrefix = 'eg.scko'; + ) {} + + load(): Promise { + this.auth.authDomain = 'eg.scko'; + + return this.auth.testAuthToken() + + .then(_ => { + + return this.serverStore.getItemBatch([ + 'opac.barcode_regex', + 'circ.selfcheck.patron_login_timeout', + 'circ.selfcheck.auto_override_checkout_events', + 'circ.selfcheck.patron_password_required', + 'circ.checkout_auto_renew_age', + 'circ.selfcheck.workstation_required', + 'circ.selfcheck.alert.popup', + 'circ.selfcheck.alert.sound', + 'credit.payments.allow', + 'circ.selfcheck.block_checkout_on_copy_status' + ]); + + }).then(sets => { + const regPattern = sets['opac.barcode_regex'] || /^\d/; + this.barcodeRegex = new RegExp(regPattern); + this.patronPasswordRequired = + sets['circ.selfcheck.patron_password_required']; + }); + } + + loadPatron(username: string, password: string): Promise { + this.patron = null; + + if (!username) { return; } + + let barcode; + + if (username.match(this.barcodeRegex)) { + barcode = username; + username = null; + } + + if (this.patronPasswordRequired) { + // TODO verify password + + } else { + + return this.fetchPatron(username, barcode); + } + } + + fetchPatron(username: string, barcode: string): Promise { + + return this.net.request( + 'open-ils.actor', + 'open-ils.actor.user.retrieve_id_by_barcode_or_username', + this.auth.token(), barcode, username).toPromise() + + .then(patronId => { + + const evt = this.evt.parse(patronId); + + if (evt || !patronId) { + console.error("Cannot find user: ", evt); + return Promise.reject('User not found'); + } + + return this.net.request( + 'open-ils.actor', + 'open-ils.actor.user.fleshed.retrieve.authoritative', + this.auth.token(), patronId).toPromise() + + }).then(patron => { + + const evt = this.evt.parse(patron); + + if (evt) { + console.error('fetchPatron()', evt); + return Promise.reject('User not found'); + } + + this.patron = patron; + }); } } -- 2.11.0