export class AuthService {
// Override this to store authtokens, etc. in a different location
- storePrefix = 'eg.auth';
+ authDomain = 'eg.auth';
private authChannel: any;
// 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.
// 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`)
);
}
handleLoginOk(args: AuthLoginArgs, evt: EgEvent, isOpChange: boolean): Promise<void> {
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(
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();
}
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();
<input type="text" class="form-control border border-dark shadow-rounded"
autocomplete="off" id="patron-username" required
- [(ngModel)]="patronUsername" placeholder="Username or Barcode" i18n-placeholder>
+ [(ngModel)]="patronUsername" name="patron-username"
+ placeholder="Username or Barcode" i18n-placeholder>
<label class="sr-only" for="patron-password" i18n>Password</label>
<input type="password" class="form-control shadow border border-dark rounded ml-2"
autocomplete="off" id="patron-password" required
- [(ngModel)]="patronUsername" placeholder="Password" i18n-placeholder>
+ [(ngModel)]="patronUsername" name="patron-password"
+ placeholder="Password" i18n-placeholder>
<button type="submit" class="btn btn-dark ml-2">Submit</button>
</form>
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,
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()
submitStaffLogin() {
- this.loginFailed = false;
+ this.staffLoginFailed = false;
const args = {
type: 'persistent',
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 {
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');
}
},
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;
+ });
}
}
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',
) {}
ngOnInit() {
+ this.scko.load();
}
}
// 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<any> {
+ 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<any> {
+ 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<any> {
+
+ 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;
+ });
}
}