import {FormsModule} from '@angular/forms';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
-import {EgEventService} from '@eg/core/event';
-import {EgStoreService} from '@eg/core/store';
-import {EgIdlService} from '@eg/core/idl';
-import {EgNetService} from '@eg/core/net';
-import {EgAuthService} from '@eg/core/auth';
-import {EgPermService} from '@eg/core/perm';
-import {EgPcrudService} from '@eg/core/pcrud';
-import {EgOrgService} from '@eg/core/org';
+import {EgEventService} from '@eg/core/event.service';
+import {EgStoreService} from '@eg/core/store.service';
+import {EgIdlService} from '@eg/core/idl.service';
+import {EgNetService} from '@eg/core/net.service';
+import {EgAuthService} from '@eg/core/auth.service';
+import {EgPermService} from '@eg/core/perm.service';
+import {EgPcrudService} from '@eg/core/pcrud.service';
+import {EgOrgService} from '@eg/core/org.service';
@NgModule({
declarations: [
--- /dev/null
+import {Injectable, EventEmitter} from '@angular/core';
+import {EgNetService} from './net.service';
+import {EgEventService, EgEvent} from './event.service';
+import {EgIdlService, EgIdlObject} from './idl.service';
+import {EgStoreService} from './store.service';
+
+// Not universally available.
+declare var BroadcastChannel;
+
+// Models a login instance.
+class EgAuthUser {
+ user: EgIdlObject; // actor.usr (au) object
+ workstation: string; // workstation name
+ token: string;
+ authtime: number;
+
+ constructor(token: string, authtime: number, workstation?: string) {
+ this.token = token;
+ this.workstation = workstation;
+ this.authtime = authtime;
+ }
+}
+
+// Params required for calling the login() method.
+interface EgAuthLoginArgs {
+ 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 {
+
+ private authChannel: any;
+
+ private activeUser: EgAuthUser;
+
+ // opChangeUser refers to the user that has been superseded during
+ // an op-change event. opChangeUser resumes its status as the
+ // activeUser once the op-change cycle has completed.
+ private opChangeUser: EgAuthUser;
+
+ workstationState: EgAuthWsState = EgAuthWsState.PENDING;
+
+ // Used by auth-checking resolvers
+ redirectUrl: string;
+
+ // reference to active auth validity setTimeout handler.
+ pollTimeout: any;
+
+ constructor(
+ private egEvt: EgEventService,
+ private net: EgNetService,
+ private store: EgStoreService
+ ) {
+
+ console.log("egAuth constructor()");
+
+ // BroadcastChannel is not yet defined in PhantomJS
+ this.authChannel = BroadcastChannel ?
+ new BroadcastChannel('eg.auth') : {};
+ }
+
+
+ // - Accessor functions always refer to the active user.
+
+ user(): EgIdlObject {
+ return this.activeUser ? this.activeUser.user : null;
+ };
+
+ // Workstation name.
+ workstation(): string {
+ return this.activeUser ? this.activeUser.workstation : null;
+ };
+
+ token(): string {
+ return this.activeUser ? this.activeUser.token : null;
+ };
+
+ authtime(): number {
+ return this.activeUser ? this.activeUser.authtime : 0;
+ };
+
+ // NOTE: EgNetService emits an event if the auth session has expired.
+ testAuthToken(): Promise<any> {
+
+ this.activeUser = new EgAuthUser(
+ this.store.getLoginSessionItem('eg.auth.token'),
+ this.store.getLoginSessionItem('eg.auth.time')
+ );
+
+ if (!this.token()) return Promise.reject('no authtoken');
+
+ return this.net.request(
+ 'open-ils.auth',
+ 'open-ils.auth.session.retrieve', this.token()).toPromise()
+ .then(user => {
+ // EgNetService interceps NO_SESSION events.
+ // We can only get here if the session is valid.
+ this.activeUser.user = user;
+ this.listenForLogout();
+ this.sessionPoll();
+ });
+ }
+
+ login(args: EgAuthLoginArgs, isOpChange?: boolean): Promise<void> {
+ return this.net.request('open-ils.auth', 'open-ils.auth.login', args)
+ .toPromise().then(res => {
+ return this.handleLoginResponse(
+ args, this.egEvt.parse(res), isOpChange)
+ })
+ }
+
+ handleLoginResponse(
+ args: EgAuthLoginArgs, evt: EgEvent, isOpChange: boolean): Promise<void> {
+
+ switch (evt.textcode) {
+ case 'SUCCESS':
+ this.handleLoginOk(args, evt, isOpChange);
+ return Promise.resolve();
+
+ case 'WORKSTATION_NOT_FOUND':
+ console.error(`No such workstation "${args.workstation}"`);
+ this.workstationState = EgAuthWsState.NOT_FOUND_SERVER;
+ delete args.workstation;
+ return this.login(args, isOpChange);
+
+ default:
+ console.error(`Login returned unexpected event: ${evt}`);
+ return Promise.reject('login failed');
+ }
+ }
+
+ // Stash the login data
+ handleLoginOk(args: EgAuthLoginArgs, evt: EgEvent, isOpChange: boolean): void {
+
+ if (isOpChange) {
+ this.store.setLoginSessionItem('eg.auth.token.oc', this.token());
+ this.store.setLoginSessionItem('eg.auth.time.oc', this.authtime());
+ this.opChangeUser = this.activeUser;
+ }
+
+ this.activeUser = new EgAuthUser(
+ evt.payload.authtoken,
+ evt.payload.authtime,
+ args.workstation
+ );
+
+ this.store.setLoginSessionItem('eg.auth.token', this.token());
+ this.store.setLoginSessionItem('eg.auth.time', this.authtime());
+ }
+
+ undoOpChange(): Promise<any> {
+ if (this.opChangeUser) {
+ this.deleteSession();
+ this.activeUser = this.opChangeUser;
+ this.opChangeUser = null;
+ this.store.removeLoginSessionItem('eg.auth.token.oc');
+ this.store.removeLoginSessionItem('eg.auth.time.oc');
+ this.store.setLoginSessionItem('eg.auth.token', this.token());
+ this.store.setLoginSessionItem('eg.auth.time', this.authtime());
+ }
+ return this.testAuthToken();
+ }
+
+ /**
+ * Listen for logout events initiated by other browser tabs.
+ */
+ listenForLogout(): void {
+ if (this.authChannel.onmessage) return;
+
+ this.authChannel.onmessage = (e) => {
+ console.debug(
+ `received eg.auth broadcast ${JSON.stringify(e.data)}`);
+
+ if (e.data.action == 'logout') {
+ // Logout will be handled by the originating tab.
+ // We just need to clear tab-local memory.
+ this.cleanup();
+ this.net.authExpired$.emit({viaExternal: true});
+ }
+ }
+ }
+
+ /**
+ * Force-check the validity of the authtoken on occasion.
+ * This allows us to redirect an idle staff client back to the login
+ * page after the session times out. Otherwise, the UI would stay
+ * open with potentially sensitive data visible.
+ * TODO: What is the practical difference (for a browser) between
+ * checking auth validity and the ui.general.idle_timeout setting?
+ * Does that setting serve a purpose in a browser environment?
+ */
+ sessionPoll(): void {
+
+ // add a 5 second delay to give the token plenty of time
+ // to expire on the server.
+ let pollTime = this.authtime() * 1000 + 5000;
+
+ this.pollTimeout = setTimeout(() => {
+ this.net.request(
+ 'open-ils.auth',
+ 'open-ils.auth.session.retrieve',
+ this.token(),
+ 0, // return extra auth details, unneeded here.
+ 1 // avoid extending the auth timeout
+
+ // EgNetService intercepts NO_SESSION events.
+ // If the promise resolves, the session is valid.
+ ).toPromise().then(user => this.sessionPoll())
+
+ }, pollTime);
+ }
+
+
+ // Resolves if login workstation matches a workstation known to this
+ // browser instance.
+ verifyWorkstation(): Promise<void> {
+
+ if (!this.user()) {
+ this.workstationState = EgAuthWsState.PENDING;
+ return Promise.reject('Cannot verify workstation without user');
+ }
+
+ if (!this.user().wsid()) {
+ this.workstationState = EgAuthWsState.NOT_USED;
+ return Promise.reject('User has no workstation ID to verify');
+ }
+
+ return new Promise((resolve, reject) => {
+ this.store.getItem('eg.workstation.all')
+ .then(workstations => {
+
+ if (workstations) {
+ let ws = workstations.filter(
+ w => {return w.id == this.user().wsid()})[0];
+
+ if (ws) {
+ this.activeUser.workstation = ws.name;
+ this.workstationState = EgAuthWsState.VALID;
+ return resolve();
+ }
+ }
+
+ this.workstationState = EgAuthWsState.NOT_FOUND_LOCAL;
+ reject();
+ });
+ });
+ }
+
+ deleteSession(): void {
+ if (this.token()) {
+ this.net.request(
+ 'open-ils.auth',
+ 'open-ils.auth.session.delete', this.token())
+ .subscribe(x => console.debug('logged out'))
+ }
+ }
+
+ // Tell all listening browser tabs that it's time to logout.
+ // This should only be invoked by one tab.
+ broadcastLogout(): void {
+ console.debug('Notifying tabs of imminent auth token removal');
+ this.authChannel.postMessage({action : 'logout'});
+ }
+
+ // Remove/reset session data
+ cleanup(): void {
+ this.activeUser = null;
+ this.opChangeUser = null;
+ if (this.pollTimeout) {
+ clearTimeout(this.pollTimeout);
+ this.pollTimeout = null;
+ }
+ }
+
+ // Invalidate server auth token and clean up.
+ logout(): void {
+ this.deleteSession();
+ this.store.clearLoginSessionItems();
+ this.cleanup();
+ }
+}
+++ /dev/null
-import {Injectable, EventEmitter} from '@angular/core';
-import {EgNetService} from './net';
-import {EgEventService, EgEvent} from './event';
-import {EgIdlService, EgIdlObject} from './idl';
-import {EgStoreService} from './store';
-
-// Not universally available.
-declare var BroadcastChannel;
-
-// Models a login instance.
-class EgAuthUser {
- user: EgIdlObject; // actor.usr (au) object
- workstation: string; // workstation name
- token: string;
- authtime: number;
-
- constructor(token: string, authtime: number, workstation?: string) {
- this.token = token;
- this.workstation = workstation;
- this.authtime = authtime;
- }
-}
-
-// Params required for calling the login() method.
-interface EgAuthLoginArgs {
- 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 {
-
- private authChannel: any;
-
- private activeUser: EgAuthUser;
-
- // opChangeUser refers to the user that has been superseded during
- // an op-change event. opChangeUser resumes its status as the
- // activeUser once the op-change cycle has completed.
- private opChangeUser: EgAuthUser;
-
- workstationState: EgAuthWsState = EgAuthWsState.PENDING;
-
- // Used by auth-checking resolvers
- redirectUrl: string;
-
- // reference to active auth validity setTimeout handler.
- pollTimeout: any;
-
- constructor(
- private egEvt: EgEventService,
- private net: EgNetService,
- private store: EgStoreService
- ) {
-
- console.log("egAuth constructor()");
-
- // BroadcastChannel is not yet defined in PhantomJS
- this.authChannel = BroadcastChannel ?
- new BroadcastChannel('eg.auth') : {};
- }
-
-
- // - Accessor functions always refer to the active user.
-
- user(): EgIdlObject {
- return this.activeUser ? this.activeUser.user : null;
- };
-
- // Workstation name.
- workstation(): string {
- return this.activeUser ? this.activeUser.workstation : null;
- };
-
- token(): string {
- return this.activeUser ? this.activeUser.token : null;
- };
-
- authtime(): number {
- return this.activeUser ? this.activeUser.authtime : 0;
- };
-
- // NOTE: EgNetService emits an event if the auth session has expired.
- testAuthToken(): Promise<any> {
-
- this.activeUser = new EgAuthUser(
- this.store.getLoginSessionItem('eg.auth.token'),
- this.store.getLoginSessionItem('eg.auth.time')
- );
-
- if (!this.token()) return Promise.reject('no authtoken');
-
- return this.net.request(
- 'open-ils.auth',
- 'open-ils.auth.session.retrieve', this.token()).toPromise()
- .then(user => {
- // EgNetService interceps NO_SESSION events.
- // We can only get here if the session is valid.
- this.activeUser.user = user;
- this.listenForLogout();
- this.sessionPoll();
- });
- }
-
- login(args: EgAuthLoginArgs, isOpChange?: boolean): Promise<void> {
- return this.net.request('open-ils.auth', 'open-ils.auth.login', args)
- .toPromise().then(res => {
- return this.handleLoginResponse(
- args, this.egEvt.parse(res), isOpChange)
- })
- }
-
- handleLoginResponse(
- args: EgAuthLoginArgs, evt: EgEvent, isOpChange: boolean): Promise<void> {
-
- switch (evt.textcode) {
- case 'SUCCESS':
- this.handleLoginOk(args, evt, isOpChange);
- return Promise.resolve();
-
- case 'WORKSTATION_NOT_FOUND':
- console.error(`No such workstation "${args.workstation}"`);
- this.workstationState = EgAuthWsState.NOT_FOUND_SERVER;
- delete args.workstation;
- return this.login(args, isOpChange);
-
- default:
- console.error(`Login returned unexpected event: ${evt}`);
- return Promise.reject('login failed');
- }
- }
-
- // Stash the login data
- handleLoginOk(args: EgAuthLoginArgs, evt: EgEvent, isOpChange: boolean): void {
-
- if (isOpChange) {
- this.store.setLoginSessionItem('eg.auth.token.oc', this.token());
- this.store.setLoginSessionItem('eg.auth.time.oc', this.authtime());
- this.opChangeUser = this.activeUser;
- }
-
- this.activeUser = new EgAuthUser(
- evt.payload.authtoken,
- evt.payload.authtime,
- args.workstation
- );
-
- this.store.setLoginSessionItem('eg.auth.token', this.token());
- this.store.setLoginSessionItem('eg.auth.time', this.authtime());
- }
-
- undoOpChange(): Promise<any> {
- if (this.opChangeUser) {
- this.deleteSession();
- this.activeUser = this.opChangeUser;
- this.opChangeUser = null;
- this.store.removeLoginSessionItem('eg.auth.token.oc');
- this.store.removeLoginSessionItem('eg.auth.time.oc');
- this.store.setLoginSessionItem('eg.auth.token', this.token());
- this.store.setLoginSessionItem('eg.auth.time', this.authtime());
- }
- return this.testAuthToken();
- }
-
- /**
- * Listen for logout events initiated by other browser tabs.
- */
- listenForLogout(): void {
- if (this.authChannel.onmessage) return;
-
- this.authChannel.onmessage = (e) => {
- console.debug(
- `received eg.auth broadcast ${JSON.stringify(e.data)}`);
-
- if (e.data.action == 'logout') {
- // Logout will be handled by the originating tab.
- // We just need to clear tab-local memory.
- this.cleanup();
- this.net.authExpired$.emit({viaExternal: true});
- }
- }
- }
-
- /**
- * Force-check the validity of the authtoken on occasion.
- * This allows us to redirect an idle staff client back to the login
- * page after the session times out. Otherwise, the UI would stay
- * open with potentially sensitive data visible.
- * TODO: What is the practical difference (for a browser) between
- * checking auth validity and the ui.general.idle_timeout setting?
- * Does that setting serve a purpose in a browser environment?
- */
- sessionPoll(): void {
-
- // add a 5 second delay to give the token plenty of time
- // to expire on the server.
- let pollTime = this.authtime() * 1000 + 5000;
-
- this.pollTimeout = setTimeout(() => {
- this.net.request(
- 'open-ils.auth',
- 'open-ils.auth.session.retrieve',
- this.token(),
- 0, // return extra auth details, unneeded here.
- 1 // avoid extending the auth timeout
-
- // EgNetService intercepts NO_SESSION events.
- // If the promise resolves, the session is valid.
- ).toPromise().then(user => this.sessionPoll())
-
- }, pollTime);
- }
-
-
- // Resolves if login workstation matches a workstation known to this
- // browser instance.
- verifyWorkstation(): Promise<void> {
-
- if (!this.user()) {
- this.workstationState = EgAuthWsState.PENDING;
- return Promise.reject('Cannot verify workstation without user');
- }
-
- if (!this.user().wsid()) {
- this.workstationState = EgAuthWsState.NOT_USED;
- return Promise.reject('User has no workstation ID to verify');
- }
-
- return new Promise((resolve, reject) => {
- this.store.getItem('eg.workstation.all')
- .then(workstations => {
-
- if (workstations) {
- let ws = workstations.filter(
- w => {return w.id == this.user().wsid()})[0];
-
- if (ws) {
- this.activeUser.workstation = ws.name;
- this.workstationState = EgAuthWsState.VALID;
- return resolve();
- }
- }
-
- this.workstationState = EgAuthWsState.NOT_FOUND_LOCAL;
- reject();
- });
- });
- }
-
- deleteSession(): void {
- if (this.token()) {
- this.net.request(
- 'open-ils.auth',
- 'open-ils.auth.session.delete', this.token())
- .subscribe(x => console.debug('logged out'))
- }
- }
-
- // Tell all listening browser tabs that it's time to logout.
- // This should only be invoked by one tab.
- broadcastLogout(): void {
- console.debug('Notifying tabs of imminent auth token removal');
- this.authChannel.postMessage({action : 'logout'});
- }
-
- // Remove/reset session data
- cleanup(): void {
- this.activeUser = null;
- this.opChangeUser = null;
- if (this.pollTimeout) {
- clearTimeout(this.pollTimeout);
- this.pollTimeout = null;
- }
- }
-
- // Invalidate server auth token and clean up.
- logout(): void {
- this.deleteSession();
- this.store.clearLoginSessionItems();
- this.cleanup();
- }
-}
--- /dev/null
+import {Injectable} from '@angular/core';
+
+export class EgEvent {
+ code : number;
+ textcode : string;
+ payload : any;
+ desc : string;
+ debug : string;
+ note : string;
+ servertime : string;
+ ilsperm : string;
+ ilspermloc : number;
+ success : Boolean = false;
+
+ toString(): string {
+ let s = `Event: ${this.code}:${this.textcode} -> ${this.desc}`;
+ if (this.ilsperm)
+ s += ` ${this.ilsperm}@${this.ilspermloc}`;
+ if (this.note)
+ s += `\n${this.note}`;
+ return s;
+ }
+}
+
+@Injectable()
+export class EgEventService {
+
+ /**
+ * Returns an EgEvent if 'thing' is an event, null otherwise.
+ */
+ parse(thing: any): EgEvent {
+
+ // All events have a textcode
+ if (thing && typeof thing == 'object' && 'textcode' in thing) {
+
+ let evt = new EgEvent();
+
+ ['textcode','payload','desc','note','servertime','ilsperm']
+ .forEach(field => { evt[field] = thing[field]; });
+
+ evt.debug = thing.stacktrace;
+ evt.code = +(thing.ilsevent || -1);
+ evt.ilspermloc = +(thing.ilspermloc || -1);
+ evt.success = thing.textcode == 'SUCCESS';
+
+ return evt;
+ }
+
+ return null;
+ }
+}
+
+
+++ /dev/null
-import {Injectable} from '@angular/core';
-
-export class EgEvent {
- code : number;
- textcode : string;
- payload : any;
- desc : string;
- debug : string;
- note : string;
- servertime : string;
- ilsperm : string;
- ilspermloc : number;
- success : Boolean = false;
-
- toString(): string {
- let s = `Event: ${this.code}:${this.textcode} -> ${this.desc}`;
- if (this.ilsperm)
- s += ` ${this.ilsperm}@${this.ilspermloc}`;
- if (this.note)
- s += `\n${this.note}`;
- return s;
- }
-}
-
-@Injectable()
-export class EgEventService {
-
- /**
- * Returns an EgEvent if 'thing' is an event, null otherwise.
- */
- parse(thing: any): EgEvent {
-
- // All events have a textcode
- if (thing && typeof thing == 'object' && 'textcode' in thing) {
-
- let evt = new EgEvent();
-
- ['textcode','payload','desc','note','servertime','ilsperm']
- .forEach(field => { evt[field] = thing[field]; });
-
- evt.debug = thing.stacktrace;
- evt.code = +(thing.ilsevent || -1);
- evt.ilspermloc = +(thing.ilspermloc || -1);
- evt.success = thing.textcode == 'SUCCESS';
-
- return evt;
- }
-
- return null;
- }
-}
-
-
--- /dev/null
+import {Injectable} from '@angular/core';
+
+// Added globally by /IDL2js
+declare var _preload_fieldmapper_IDL: Object;
+
+/**
+ * Every IDL object class implements this interface.
+ */
+export interface EgIdlObject {
+ a: any[];
+ classname: string;
+ _isfieldmapper: boolean;
+ // Dynamically appended functions from the IDL.
+ [fields: string]: any;
+}
+
+@Injectable()
+export class EgIdlService {
+
+ classes = {}; // IDL class metadata
+ constructors = {}; // IDL instance generators
+
+ /**
+ * Create a new IDL object instance.
+ */
+ create(cls: string, seed?:any[]): EgIdlObject {
+ if (this.constructors[cls])
+ return new this.constructors[cls](seed);
+ throw new Error(`No such IDL class ${cls}`);
+ }
+
+ parseIdl(): void {
+
+ try {
+ this.classes = _preload_fieldmapper_IDL;
+ } catch (E) {
+ console.error('IDL (IDL2js) not found. Is the system running?');
+ return;
+ }
+
+ /**
+ * Creates the class constructor and getter/setter
+ * methods for each IDL class.
+ */
+ let mkclass = (cls, fields) => {
+ this.classes[cls].classname = cls;
+
+ // This dance lets us encode each IDL object with the
+ // EgIdlObject interface. Useful for adding type restrictions
+ // where desired for functions, etc.
+ let generator:any = ((): EgIdlObject => {
+
+ var x:any = function(seed) {
+ this.a = seed || [];
+ this.classname = cls;
+ this._isfieldmapper = true;
+ };
+
+ fields.forEach(function(field, idx) {
+ x.prototype[field.name] = function(n) {
+ if (arguments.length==1) this.a[idx] = n;
+ return this.a[idx];
+ }
+ });
+
+ return x;
+ });
+
+ this.constructors[cls] = generator();
+
+ // global class constructors required for JSON_v1.js
+ // TODO: polluting the window namespace w/ every IDL class
+ // is less than ideal.
+ window[cls] = this.constructors[cls];
+ }
+
+ for (var cls in this.classes)
+ mkclass(cls, this.classes[cls].fields);
+ };
+}
+
+++ /dev/null
-import {Injectable} from '@angular/core';
-
-// Added globally by /IDL2js
-declare var _preload_fieldmapper_IDL: Object;
-
-/**
- * Every IDL object class implements this interface.
- */
-export interface EgIdlObject {
- a: any[];
- classname: string;
- _isfieldmapper: boolean;
- // Dynamically appended functions from the IDL.
- [fields: string]: any;
-}
-
-@Injectable()
-export class EgIdlService {
-
- classes = {}; // IDL class metadata
- constructors = {}; // IDL instance generators
-
- /**
- * Create a new IDL object instance.
- */
- create(cls: string, seed?:any[]): EgIdlObject {
- if (this.constructors[cls])
- return new this.constructors[cls](seed);
- throw new Error(`No such IDL class ${cls}`);
- }
-
- parseIdl(): void {
-
- try {
- this.classes = _preload_fieldmapper_IDL;
- } catch (E) {
- console.error('IDL (IDL2js) not found. Is the system running?');
- return;
- }
-
- /**
- * Creates the class constructor and getter/setter
- * methods for each IDL class.
- */
- let mkclass = (cls, fields) => {
- this.classes[cls].classname = cls;
-
- // This dance lets us encode each IDL object with the
- // EgIdlObject interface. Useful for adding type restrictions
- // where desired for functions, etc.
- let generator:any = ((): EgIdlObject => {
-
- var x:any = function(seed) {
- this.a = seed || [];
- this.classname = cls;
- this._isfieldmapper = true;
- };
-
- fields.forEach(function(field, idx) {
- x.prototype[field.name] = function(n) {
- if (arguments.length==1) this.a[idx] = n;
- return this.a[idx];
- }
- });
-
- return x;
- });
-
- this.constructors[cls] = generator();
-
- // global class constructors required for JSON_v1.js
- // TODO: polluting the window namespace w/ every IDL class
- // is less than ideal.
- window[cls] = this.constructors[cls];
- }
-
- for (var cls in this.classes)
- mkclass(cls, this.classes[cls].fields);
- };
-}
-
--- /dev/null
+/**
+ *
+ * constructor(private net : EgNetService) {
+ * ...
+ * this.net.request(service, method, param1 [, param2, ...])
+ * .subscribe(
+ * (res) => console.log('received one resopnse: ' + res),
+ * (err) => console.error('recived request error: ' + err),
+ * () => console.log('request complete')
+ * )
+ * );
+ * ...
+ *
+ * // Example translating a net request into a promise.
+ * this.net.request(service, method, param1)
+ * .toPromise().then(result => console.log(result));
+ *
+ * }
+ *
+ * Each response is relayed via Observable.next(). The interface is
+ * the same for streaming and atomic requests.
+ */
+import {Injectable, EventEmitter} from '@angular/core';
+import {Observable, Observer} from 'rxjs/Rx';
+import {EgEventService, EgEvent} from './event.service';
+
+// Global vars from opensrf.js
+// These are availavble at runtime, but are not exported.
+declare var OpenSRF, OSRF_TRANSPORT_TYPE_WS;
+
+export class EgNetRequest {
+ service : string;
+ method : string;
+ params : any[];
+ observer : Observer<any>;
+ superseded : boolean = false;
+ // If set, this will be used instead of a one-off OpenSRF.ClientSession.
+ session? : any;
+ // True if we're using a single-use local session
+ localSession: boolean = true;
+
+ // Last EgEvent encountered by this request.
+ // Most callers will not need to import EgEvent since the parsed
+ // event will be available here.
+ evt: EgEvent;
+
+ constructor(service: string, method: string, params: any[], session?: any) {
+ this.service = service;
+ this.method = method;
+ this.params = params;
+ if (session) {
+ this.session = session;
+ this.localSession = false;
+ } else {
+ this.session = new OpenSRF.ClientSession(service);
+ }
+ }
+}
+
+export interface EgAuthExpiredEvent {
+ // request is set when the auth expiration was determined as a
+ // by-product of making an API call.
+ request?: EgNetRequest;
+
+ // True if this environment (e.g. browser tab) was notified of the
+ // expired auth token from an external source (e.g. another browser tab).
+ viaExternal?: boolean;
+}
+
+@Injectable()
+export class EgNetService {
+
+ permFailed$: EventEmitter<EgNetRequest>;
+ authExpired$: EventEmitter<EgAuthExpiredEvent>;
+
+ // If true, permission failures are emitted via permFailed$
+ // and the active request is marked as superseded.
+ permFailedHasHandler: Boolean = false;
+
+ constructor(
+ private egEvt: EgEventService
+ ) {
+ this.permFailed$ = new EventEmitter<EgNetRequest>();
+ this.authExpired$ = new EventEmitter<EgAuthExpiredEvent>();
+ }
+
+ // Standard request call -- Variadic params version
+ request(service: string, method: string, ...params: any[]): Observable<any> {
+ return this.requestWithParamList(service, method, params);
+ }
+
+ // Array params version
+ requestWithParamList(service: string,
+ method: string, params: any[]): Observable<any> {
+ return this.requestCompiled(
+ new EgNetRequest(service, method, params));
+ }
+
+ // Request with pre-compiled EgNetRequest
+ requestCompiled(request: EgNetRequest): Observable<any> {
+ return Observable.create(
+ observer => {
+ request.observer = observer;
+ this.sendCompiledRequest(request);
+ }
+ );
+ }
+
+ // Send the compiled request to the server via WebSockets
+ sendCompiledRequest(request: EgNetRequest): void {
+ OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS;
+ console.debug(`EgNet: request ${request.method}`);
+
+ request.session.request({
+ async : true, // WS only operates in async mode
+ method : request.method,
+ params : request.params,
+ oncomplete : () => {
+
+ // TODO: teach opensrf.js to call cleanup() inside
+ // disconnect() and teach EgPcrud to call cleanup()
+ // as needed to avoid long-lived session data bloat.
+ if (request.localSession)
+ request.session.cleanup();
+
+ // A superseded request will be complete()'ed by the
+ // superseder at a later time.
+ if (!request.superseded)
+ request.observer.complete();
+ },
+ onresponse : r => {
+ this.dispatchResponse(request, r.recv().content());
+ },
+ onerror : errmsg => {
+ let msg = `${request.method} failed! See server logs. ${errmsg}`;
+ console.error(msg);
+ request.observer.error(msg);
+ },
+ onmethoderror : (req, statCode, statMsg) => {
+ let msg =
+ `${request.method} failed! stat=${statCode} msg=${statMsg}`;
+ console.error(msg);
+
+ if (request.service == 'open-ils.pcrud' && statCode == 401) {
+ // 401 is the PCRUD equivalent of a NO_SESSION event
+ this.authExpired$.emit({request: request});
+ }
+
+ request.observer.error(msg);
+ }
+
+ }).send();
+ }
+
+ // Relay response object to the caller for typical/successful
+ // responses. Applies special handling to response events that
+ // require global attention.
+ private dispatchResponse(request, response): void {
+ request.evt = this.egEvt.parse(response);
+
+ if (request.evt) {
+ switch(request.evt.textcode) {
+
+ case 'NO_SESSION':
+ console.debug(`EgNet emitting event: ${request.evt}`);
+ request.observer.error(request.evt.toString());
+ this.authExpired$.emit({request: request});
+ return;
+
+ case 'PERM_FAILURE':
+ if (this.permFailedHasHandler) {
+ console.debug(`EgNet emitting event: ${request.evt}`);
+ request.superseded = true;
+ this.permFailed$.emit(request);
+ return;
+ }
+ }
+ }
+
+ // Pass the response to the caller.
+ request.observer.next(response);
+ };
+}
+++ /dev/null
-/**
- *
- * constructor(private net : EgNetService) {
- * ...
- * this.net.request(service, method, param1 [, param2, ...])
- * .subscribe(
- * (res) => console.log('received one resopnse: ' + res),
- * (err) => console.error('recived request error: ' + err),
- * () => console.log('request complete')
- * )
- * );
- * ...
- *
- * // Example translating a net request into a promise.
- * this.net.request(service, method, param1)
- * .toPromise().then(result => console.log(result));
- *
- * }
- *
- * Each response is relayed via Observable.next(). The interface is
- * the same for streaming and atomic requests.
- */
-import {Injectable, EventEmitter} from '@angular/core';
-import {Observable, Observer} from 'rxjs/Rx';
-import {EgEventService, EgEvent} from './event';
-
-// Global vars from opensrf.js
-// These are availavble at runtime, but are not exported.
-declare var OpenSRF, OSRF_TRANSPORT_TYPE_WS;
-
-export class EgNetRequest {
- service : string;
- method : string;
- params : any[];
- observer : Observer<any>;
- superseded : boolean = false;
- // If set, this will be used instead of a one-off OpenSRF.ClientSession.
- session? : any;
- // True if we're using a single-use local session
- localSession: boolean = true;
-
- // Last EgEvent encountered by this request.
- // Most callers will not need to import EgEvent since the parsed
- // event will be available here.
- evt: EgEvent;
-
- constructor(service: string, method: string, params: any[], session?: any) {
- this.service = service;
- this.method = method;
- this.params = params;
- if (session) {
- this.session = session;
- this.localSession = false;
- } else {
- this.session = new OpenSRF.ClientSession(service);
- }
- }
-}
-
-export interface EgAuthExpiredEvent {
- // request is set when the auth expiration was determined as a
- // by-product of making an API call.
- request?: EgNetRequest;
-
- // True if this environment (e.g. browser tab) was notified of the
- // expired auth token from an external source (e.g. another browser tab).
- viaExternal?: boolean;
-}
-
-@Injectable()
-export class EgNetService {
-
- permFailed$: EventEmitter<EgNetRequest>;
- authExpired$: EventEmitter<EgAuthExpiredEvent>;
-
- // If true, permission failures are emitted via permFailed$
- // and the active request is marked as superseded.
- permFailedHasHandler: Boolean = false;
-
- constructor(
- private egEvt: EgEventService
- ) {
- this.permFailed$ = new EventEmitter<EgNetRequest>();
- this.authExpired$ = new EventEmitter<EgAuthExpiredEvent>();
- }
-
- // Standard request call -- Variadic params version
- request(service: string, method: string, ...params: any[]): Observable<any> {
- return this.requestWithParamList(service, method, params);
- }
-
- // Array params version
- requestWithParamList(service: string,
- method: string, params: any[]): Observable<any> {
- return this.requestCompiled(
- new EgNetRequest(service, method, params));
- }
-
- // Request with pre-compiled EgNetRequest
- requestCompiled(request: EgNetRequest): Observable<any> {
- return Observable.create(
- observer => {
- request.observer = observer;
- this.sendCompiledRequest(request);
- }
- );
- }
-
- // Send the compiled request to the server via WebSockets
- sendCompiledRequest(request: EgNetRequest): void {
- OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS;
- console.debug(`EgNet: request ${request.method}`);
-
- request.session.request({
- async : true, // WS only operates in async mode
- method : request.method,
- params : request.params,
- oncomplete : () => {
-
- // TODO: teach opensrf.js to call cleanup() inside
- // disconnect() and teach EgPcrud to call cleanup()
- // as needed to avoid long-lived session data bloat.
- if (request.localSession)
- request.session.cleanup();
-
- // A superseded request will be complete()'ed by the
- // superseder at a later time.
- if (!request.superseded)
- request.observer.complete();
- },
- onresponse : r => {
- this.dispatchResponse(request, r.recv().content());
- },
- onerror : errmsg => {
- let msg = `${request.method} failed! See server logs. ${errmsg}`;
- console.error(msg);
- request.observer.error(msg);
- },
- onmethoderror : (req, statCode, statMsg) => {
- let msg =
- `${request.method} failed! stat=${statCode} msg=${statMsg}`;
- console.error(msg);
-
- if (request.service == 'open-ils.pcrud' && statCode == 401) {
- // 401 is the PCRUD equivalent of a NO_SESSION event
- this.authExpired$.emit({request: request});
- }
-
- request.observer.error(msg);
- }
-
- }).send();
- }
-
- // Relay response object to the caller for typical/successful
- // responses. Applies special handling to response events that
- // require global attention.
- private dispatchResponse(request, response): void {
- request.evt = this.egEvt.parse(response);
-
- if (request.evt) {
- switch(request.evt.textcode) {
-
- case 'NO_SESSION':
- console.debug(`EgNet emitting event: ${request.evt}`);
- request.observer.error(request.evt.toString());
- this.authExpired$.emit({request: request});
- return;
-
- case 'PERM_FAILURE':
- if (this.permFailedHasHandler) {
- console.debug(`EgNet emitting event: ${request.evt}`);
- request.superseded = true;
- this.permFailed$.emit(request);
- return;
- }
- }
- }
-
- // Pass the response to the caller.
- request.observer.next(response);
- };
-}
--- /dev/null
+import {Injectable} from '@angular/core';
+import {Observable} from 'rxjs/Rx';
+import {EgIdlObject, EgIdlService} from './idl.service';
+import {EgNetService} from './net.service';
+import {EgAuthService} from './auth.service';
+import {EgPcrudService} from './pcrud.service';
+
+type EgOrgNodeOrId = number | EgIdlObject;
+
+interface OrgFilter {
+ canHaveUsers?: boolean;
+ canHaveVolumes?: boolean;
+ opacVisible?: boolean;
+ inList?: number[];
+ notInList?: number[];
+}
+
+interface OrgSettingsBatch {
+ [key: string]: any;
+}
+
+@Injectable()
+export class EgOrgService {
+
+ private orgList: EgIdlObject[] = [];
+ private orgTree: EgIdlObject; // root node + children
+ private orgMap: {[id:number] : EgIdlObject} = {};
+ private settingsCache: OrgSettingsBatch = {};
+
+ constructor(
+ private net: EgNetService,
+ private auth: EgAuthService,
+ private pcrud: EgPcrudService
+ ) {}
+
+ get(nodeOrId: EgOrgNodeOrId): EgIdlObject {
+ if (typeof nodeOrId == 'object')
+ return nodeOrId;
+ return this.orgMap[nodeOrId];
+ }
+
+ list(): EgIdlObject[] {
+ return this.orgList;
+ }
+
+ /**
+ * Returns a list of org units that match the selected criteria.
+ * All filters must match for an org to be included in the result set.
+ * Unset filter options are ignored.
+ */
+ filterList(filter: OrgFilter, asId?: boolean): any[] {
+ let list = [];
+ this.list().forEach(org => {
+
+ let chu = filter.canHaveUsers;
+ if (chu && !this.canHaveUsers(org)) return;
+ if (chu === false && this.canHaveUsers(org)) return;
+
+ let chv = filter.canHaveVolumes;
+ if (chv && !this.canHaveVolumes(org)) return;
+ if (chv === false && this.canHaveVolumes(org)) return;
+
+ let ov = filter.opacVisible;
+ if (ov && !this.opacVisible(org)) return;
+ if (ov === false && this.opacVisible(org)) return;
+
+ if (filter.inList && filter.inList.indexOf(org.id()) == -1)
+ return;
+
+ if (filter.notInList && filter.notInList.indexOf(org.id()) > -1)
+ return;
+
+ // All filter tests passed. Add it to the list
+ list.push(asId ? org.id() : org);
+ });
+
+ return list;
+ }
+
+ tree(): EgIdlObject {
+ return this.orgTree;
+ }
+
+ // get the root OU
+ root(): EgIdlObject {
+ return this.orgList[0];
+ }
+
+ // list of org_unit objects or IDs for ancestors + me
+ ancestors(nodeOrId: EgOrgNodeOrId, asId?: boolean): any[] {
+ let node = this.get(nodeOrId);
+ if (!node) return [];
+ let nodes = [node];
+ while( (node = this.get(node.parent_ou())))
+ nodes.push(node);
+ if (asId) return nodes.map(n => n.id());
+ return nodes;
+ }
+
+ // tests that a node can have users
+ canHaveUsers(nodeOrId): boolean {
+ return this
+ .get(nodeOrId)
+ .ou_type()
+ .can_have_users() == 't';
+ }
+
+ // tests that a node can have volumes
+ canHaveVolumes(nodeOrId): boolean {
+ return this
+ .get(nodeOrId)
+ .ou_type()
+ .can_have_vols() == 't';
+ }
+
+ opacVisible(nodeOrId): boolean {
+ return this.get(nodeOrId).opac_visible() == 't';
+ }
+
+ // list of org_unit objects or IDs for me + descendants
+ descendants(nodeOrId: EgOrgNodeOrId, asId?: boolean): any[] {
+ let node = this.get(nodeOrId);
+ if (!node) return [];
+ let nodes = [];
+ function descend(n) {
+ nodes.push(n);
+ n.children().forEach(descend);
+ }
+ descend(node);
+ if (asId)
+ return nodes.map(function(n){return n.id()});
+ return nodes;
+ }
+
+ // list of org_unit objects or IDs for ancestors + me + descendants
+ fullPath(nodeOrId: EgOrgNodeOrId, asId?: boolean): any[] {
+ let list = this.ancestors(nodeOrId, false).concat(
+ this.descendants(nodeOrId, false).slice(1));
+ if (asId)
+ return list.map(function(n){return n.id()});
+ return list;
+ }
+
+ sortTree(sortField?: string, node?: EgIdlObject): void {
+ if (!sortField) sortField = 'shortname';
+ if (!node) node = this.orgTree;
+ node.children(
+ node.children.sort((a, b) => {
+ return a[sortField]() < b[sortField]() ? -1 : 1
+ })
+ );
+ node.children.forEach(n => this.sortTree(n));
+ }
+
+ absorbTree(node?: EgIdlObject): void {
+ if (!node) {
+ node = this.orgTree;
+ this.orgMap = {};
+ this.orgList = [];
+ }
+ this.orgMap[node.id()] = node;
+ this.orgList.push(node);
+ node.children().forEach(c => this.absorbTree(c));
+ }
+
+ /**
+ * Grabs all of the org units from the server, chops them up into
+ * various shapes, then returns an "all done" promise.
+ */
+ fetchOrgs(): Promise<void> {
+ return this.pcrud.search('aou', {parent_ou : null},
+ {flesh : -1, flesh_fields : {aou : ['children', 'ou_type']}},
+ {anonymous : true}
+ ).toPromise().then(tree => {
+ // ingest tree, etc.
+ this.orgTree = tree;
+ this.absorbTree();
+ });
+ }
+
+ /**
+ * Populate 'target' with settings from cache where available.
+ * Return the list of settings /not/ pulled from cache.
+ */
+ private settingsFromCache(names: string[], target: any) {
+ let cacheKeys = Object.keys(this.settingsCache);
+
+ cacheKeys.forEach(key => {
+ let matchIdx = names.indexOf(key);
+ if (matchIdx > -1) {
+ target[key] = this.settingsCache[key];
+ names.splice(matchIdx, 1);
+ }
+ });
+
+ return names;
+ }
+
+ /**
+ * Fetch org settings from the network.
+ * 'auth' is null for anonymous lookup.
+ */
+ private settingsFromNet(orgId: number,
+ names: string[], auth?: string): Promise<any> {
+
+ let settings = {};
+ return new Promise((resolve, reject) => {
+ this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.ou_setting.ancestor_default.batch',
+ orgId, names, auth
+ ).subscribe(
+ blob => {
+ Object.keys(blob).forEach(key => {
+ let val = blob[key]; // null or hash
+ settings[key] = val ? val.value : null;
+ });
+ resolve(settings);
+ },
+ err => reject(err)
+ );
+ });
+ }
+
+
+ /**
+ *
+ */
+ settings(names: string[],
+ orgId?: number, anonymous?: boolean): Promise<OrgSettingsBatch> {
+
+ let settings = {};
+ let auth: string = null;
+ let useCache: boolean = false;
+
+ if (this.auth.user()) {
+ if (orgId) {
+ useCache = orgId == this.auth.user().ws_ou();
+ } else {
+ orgId = this.auth.user().ws_ou();
+ useCache = true;
+ }
+
+ // avoid passing auth token when anonymous is requested.
+ if (!anonymous) auth = this.auth.token();
+
+ } else if (!anonymous) {
+ return Promise.reject(
+ 'Use "anonymous" To retrieve org settings without an authtoken');
+ }
+
+ if (useCache) names = this.settingsFromCache(names, settings);
+
+ // All requested settings found in cache (or name list is empty)
+ if (names.length == 0) return Promise.resolve(settings);
+
+ return this.settingsFromNet(orgId, names, auth)
+ .then(settings => {
+ if (useCache) {
+ Object.keys(settings).forEach(key => {
+ this.settingsCache[key] = settings[key];
+ });
+ }
+ return settings;
+ });
+ }
+}
+++ /dev/null
-import {Injectable} from '@angular/core';
-import {Observable} from 'rxjs/Rx';
-import {EgIdlObject, EgIdlService} from './idl';
-import {EgNetService} from './net';
-import {EgAuthService} from './auth';
-import {EgPcrudService} from './pcrud';
-
-type EgOrgNodeOrId = number | EgIdlObject;
-
-interface OrgFilter {
- canHaveUsers?: boolean;
- canHaveVolumes?: boolean;
- opacVisible?: boolean;
- inList?: number[];
- notInList?: number[];
-}
-
-interface OrgSettingsBatch {
- [key: string]: any;
-}
-
-@Injectable()
-export class EgOrgService {
-
- private orgList: EgIdlObject[] = [];
- private orgTree: EgIdlObject; // root node + children
- private orgMap: {[id:number] : EgIdlObject} = {};
- private settingsCache: OrgSettingsBatch = {};
-
- constructor(
- private net: EgNetService,
- private auth: EgAuthService,
- private pcrud: EgPcrudService
- ) {}
-
- get(nodeOrId: EgOrgNodeOrId): EgIdlObject {
- if (typeof nodeOrId == 'object')
- return nodeOrId;
- return this.orgMap[nodeOrId];
- }
-
- list(): EgIdlObject[] {
- return this.orgList;
- }
-
- /**
- * Returns a list of org units that match the selected criteria.
- * All filters must match for an org to be included in the result set.
- * Unset filter options are ignored.
- */
- filterList(filter: OrgFilter, asId?: boolean): any[] {
- let list = [];
- this.list().forEach(org => {
-
- let chu = filter.canHaveUsers;
- if (chu && !this.canHaveUsers(org)) return;
- if (chu === false && this.canHaveUsers(org)) return;
-
- let chv = filter.canHaveVolumes;
- if (chv && !this.canHaveVolumes(org)) return;
- if (chv === false && this.canHaveVolumes(org)) return;
-
- let ov = filter.opacVisible;
- if (ov && !this.opacVisible(org)) return;
- if (ov === false && this.opacVisible(org)) return;
-
- if (filter.inList && filter.inList.indexOf(org.id()) == -1)
- return;
-
- if (filter.notInList && filter.notInList.indexOf(org.id()) > -1)
- return;
-
- // All filter tests passed. Add it to the list
- list.push(asId ? org.id() : org);
- });
-
- return list;
- }
-
- tree(): EgIdlObject {
- return this.orgTree;
- }
-
- // get the root OU
- root(): EgIdlObject {
- return this.orgList[0];
- }
-
- // list of org_unit objects or IDs for ancestors + me
- ancestors(nodeOrId: EgOrgNodeOrId, asId?: boolean): any[] {
- let node = this.get(nodeOrId);
- if (!node) return [];
- let nodes = [node];
- while( (node = this.get(node.parent_ou())))
- nodes.push(node);
- if (asId) return nodes.map(n => n.id());
- return nodes;
- }
-
- // tests that a node can have users
- canHaveUsers(nodeOrId): boolean {
- return this
- .get(nodeOrId)
- .ou_type()
- .can_have_users() == 't';
- }
-
- // tests that a node can have volumes
- canHaveVolumes(nodeOrId): boolean {
- return this
- .get(nodeOrId)
- .ou_type()
- .can_have_vols() == 't';
- }
-
- opacVisible(nodeOrId): boolean {
- return this.get(nodeOrId).opac_visible() == 't';
- }
-
- // list of org_unit objects or IDs for me + descendants
- descendants(nodeOrId: EgOrgNodeOrId, asId?: boolean): any[] {
- let node = this.get(nodeOrId);
- if (!node) return [];
- let nodes = [];
- function descend(n) {
- nodes.push(n);
- n.children().forEach(descend);
- }
- descend(node);
- if (asId)
- return nodes.map(function(n){return n.id()});
- return nodes;
- }
-
- // list of org_unit objects or IDs for ancestors + me + descendants
- fullPath(nodeOrId: EgOrgNodeOrId, asId?: boolean): any[] {
- let list = this.ancestors(nodeOrId, false).concat(
- this.descendants(nodeOrId, false).slice(1));
- if (asId)
- return list.map(function(n){return n.id()});
- return list;
- }
-
- sortTree(sortField?: string, node?: EgIdlObject): void {
- if (!sortField) sortField = 'shortname';
- if (!node) node = this.orgTree;
- node.children(
- node.children.sort((a, b) => {
- return a[sortField]() < b[sortField]() ? -1 : 1
- })
- );
- node.children.forEach(n => this.sortTree(n));
- }
-
- absorbTree(node?: EgIdlObject): void {
- if (!node) {
- node = this.orgTree;
- this.orgMap = {};
- this.orgList = [];
- }
- this.orgMap[node.id()] = node;
- this.orgList.push(node);
- node.children().forEach(c => this.absorbTree(c));
- }
-
- /**
- * Grabs all of the org units from the server, chops them up into
- * various shapes, then returns an "all done" promise.
- */
- fetchOrgs(): Promise<void> {
- return this.pcrud.search('aou', {parent_ou : null},
- {flesh : -1, flesh_fields : {aou : ['children', 'ou_type']}},
- {anonymous : true}
- ).toPromise().then(tree => {
- // ingest tree, etc.
- this.orgTree = tree;
- this.absorbTree();
- });
- }
-
- /**
- * Populate 'target' with settings from cache where available.
- * Return the list of settings /not/ pulled from cache.
- */
- private settingsFromCache(names: string[], target: any) {
- let cacheKeys = Object.keys(this.settingsCache);
-
- cacheKeys.forEach(key => {
- let matchIdx = names.indexOf(key);
- if (matchIdx > -1) {
- target[key] = this.settingsCache[key];
- names.splice(matchIdx, 1);
- }
- });
-
- return names;
- }
-
- /**
- * Fetch org settings from the network.
- * 'auth' is null for anonymous lookup.
- */
- private settingsFromNet(orgId: number,
- names: string[], auth?: string): Promise<any> {
-
- let settings = {};
- return new Promise((resolve, reject) => {
- this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.ou_setting.ancestor_default.batch',
- orgId, names, auth
- ).subscribe(
- blob => {
- Object.keys(blob).forEach(key => {
- let val = blob[key]; // null or hash
- settings[key] = val ? val.value : null;
- });
- resolve(settings);
- },
- err => reject(err)
- );
- });
- }
-
-
- /**
- *
- */
- settings(names: string[],
- orgId?: number, anonymous?: boolean): Promise<OrgSettingsBatch> {
-
- let settings = {};
- let auth: string = null;
- let useCache: boolean = false;
-
- if (this.auth.user()) {
- if (orgId) {
- useCache = orgId == this.auth.user().ws_ou();
- } else {
- orgId = this.auth.user().ws_ou();
- useCache = true;
- }
-
- // avoid passing auth token when anonymous is requested.
- if (!anonymous) auth = this.auth.token();
-
- } else if (!anonymous) {
- return Promise.reject(
- 'Use "anonymous" To retrieve org settings without an authtoken');
- }
-
- if (useCache) names = this.settingsFromCache(names, settings);
-
- // All requested settings found in cache (or name list is empty)
- if (names.length == 0) return Promise.resolve(settings);
-
- return this.settingsFromNet(orgId, names, auth)
- .then(settings => {
- if (useCache) {
- Object.keys(settings).forEach(key => {
- this.settingsCache[key] = settings[key];
- });
- }
- return settings;
- });
- }
-}
--- /dev/null
+import {Injectable} from '@angular/core';
+import {Observable, Observer} from 'rxjs/Rx';
+import {EgIdlService, EgIdlObject} from './idl.service';
+import {EgNetService, EgNetRequest} from './net.service';
+import {EgAuthService} from './auth.service';
+
+// Externally defined. Used here for debugging.
+declare var js2JSON: (jsThing:any) => string;
+declare var OpenSRF: any; // creating sessions
+
+interface EgPcrudReqOps {
+ authoritative?: boolean;
+ anonymous?: boolean;
+ idlist?: boolean;
+ atomic?: boolean;
+}
+
+// For for documentation purposes.
+type EgPcrudResponse = any;
+
+export class EgPcrudContext {
+
+ static verboseLogging: boolean = true; //
+ static identGenerator: number = 0; // for debug logging
+
+ private ident: number;
+ private authoritative: boolean;
+ private xactCloseMode: string;
+ private cudIdx: number;
+ private cudAction: string;
+ private cudLast: EgPcrudResponse;
+ private cudList: EgIdlObject[];
+
+ private idl: EgIdlService;
+ private net: EgNetService;
+ private auth: EgAuthService;
+
+ // Tracks nested CUD actions
+ cudObserver: Observer<EgPcrudResponse>;
+
+ session: any; // OpenSRF.ClientSession
+
+ constructor( // passed in by parent service -- not injected
+ egIdl: EgIdlService,
+ egNet: EgNetService,
+ egAuth: EgAuthService
+ ) {
+ this.idl = egIdl;
+ this.net = egNet;
+ this.auth = egAuth;
+ this.xactCloseMode = 'rollback';
+ this.ident = EgPcrudContext.identGenerator++;
+ this.session = new OpenSRF.ClientSession('open-ils.pcrud');
+ }
+
+ toString(): string {
+ return '[PCRUDContext ' + this.ident + ']';
+ }
+
+ log(msg: string): void {
+ if (EgPcrudContext.verboseLogging)
+ console.debug(this + ': ' + msg);
+ }
+
+ err(msg: string): void {
+ console.error(this + ': ' + msg);
+ }
+
+ token(reqOps?: EgPcrudReqOps): string {
+ return (reqOps && reqOps.anonymous) ?
+ 'ANONYMOUS' : this.auth.token();
+ }
+
+ connect(): Promise<EgPcrudContext> {
+ this.log('connect');
+ return new Promise( (resolve, reject) => {
+ this.session.connect({
+ onconnect : () => { resolve(this); }
+ });
+ })
+ }
+
+ disconnect(): void {
+ this.log('disconnect');
+ this.session.disconnect();
+ }
+
+ retrieve(fmClass: string, pkey: Number | string,
+ pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
+ if (!reqOps) reqOps = {};
+ this.authoritative = reqOps.authoritative || false;
+ return this.dispatch(
+ `open-ils.pcrud.retrieve.${fmClass}`,
+ [this.token(reqOps), pkey, pcrudOps]);
+ }
+
+ retrieveAll(fmClass: string, pcrudOps?: any,
+ reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
+ let search = {};
+ search[this.idl.classes[fmClass].pkey] = {'!=' : null};
+ return this.search(fmClass, search, pcrudOps, reqOps);
+ }
+
+ search(fmClass: string, search: any,
+ pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
+ reqOps = reqOps || {};
+ this.authoritative = reqOps.authoritative || false;
+
+ let returnType = reqOps.idlist ? 'id_list' : 'search';
+ let method = `open-ils.pcrud.${returnType}.${fmClass}`;
+
+ if (reqOps.atomic) method += '.atomic';
+
+ return this.dispatch(method, [this.token(reqOps), search, pcrudOps]);
+ }
+
+ create(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.cud('create', list)
+ }
+ update(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.cud('update', list)
+ }
+ remove(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.cud('delete', list)
+ }
+ autoApply(list: EgIdlObject[]): Observable<EgPcrudResponse> { // RENAMED
+ return this.cud('auto', list)
+ }
+
+ xactClose(): Observable<EgPcrudResponse> {
+ return this.sendRequest(
+ 'open-ils.pcrud.transaction.' + this.xactCloseMode,
+ [this.token()]
+ );
+ };
+
+ xactBegin(): Observable<EgPcrudResponse> {
+ return this.sendRequest(
+ 'open-ils.pcrud.transaction.begin', [this.token()]
+ );
+ };
+
+ private dispatch(method: string, params: any[]): Observable<EgPcrudResponse> {
+ if (this.authoritative) {
+ return this.wrapXact(() => {
+ return this.sendRequest(method, params);
+ });
+ } else {
+ return this.sendRequest(method, params)
+ }
+ };
+
+
+ // => connect
+ // => xact_begin
+ // => action
+ // => xact_close(commit/rollback)
+ // => disconnect
+ wrapXact(mainFunc: () => Observable<EgPcrudResponse>): Observable<EgPcrudResponse> {
+ return Observable.create(observer => {
+
+ // 1. connect
+ this.connect()
+
+ // 2. start the transaction
+ .then(() => {return this.xactBegin().toPromise()})
+
+ // 3. execute the main body
+ .then(() => {
+
+ mainFunc().subscribe(
+ res => observer.next(res),
+ err => observer.error(err),
+ () => {
+ this.xactClose().toPromise().then(() => {
+ // 5. disconnect
+ this.disconnect();
+ // 6. all done
+ observer.complete();
+ });
+ }
+ );
+ })
+ });
+ };
+
+ private sendRequest(method: string,
+ params: any[]): Observable<EgPcrudResponse> {
+
+ this.log(`sendRequest(${method})`);
+
+ return this.net.requestCompiled(
+ new EgNetRequest(
+ 'open-ils.pcrud', method, params, this.session)
+ );
+ }
+
+ private cud(action: string,
+ list: EgIdlObject | EgIdlObject[]): Observable<EgPcrudResponse> {
+
+ this.log(`CUD(): ${action}`);
+
+ this.cudIdx = 0;
+ this.cudAction = action;
+ this.xactCloseMode = 'commit';
+
+ if (!Array.isArray(list)) this.cudList = [list];
+
+ return this.wrapXact(() => {
+ return Observable.create(observer => {
+ this.cudObserver = observer;
+ this.nextCudRequest();
+ });
+ });
+ }
+
+ /**
+ * Loops through the list of objects to update and sends
+ * them one at a time to the server for processing. Once
+ * all are done, the cudObserver is resolved.
+ */
+ nextCudRequest(): void {
+ if (this.cudIdx >= this.cudList.length) {
+ this.cudObserver.complete();
+ return;
+ }
+
+ let action = this.cudAction;
+ let fmObj = this.cudList[this.cudIdx++];
+
+ if (action == 'auto') {
+ if (fmObj.ischanged()) action = 'update';
+ if (fmObj.isnew()) action = 'create';
+ if (fmObj.isdeleted()) action = 'delete';
+
+ if (action == 'auto') {
+ // object does not need updating; move along
+ this.nextCudRequest();
+ }
+ }
+
+ this.sendRequest(
+ `open-ils.pcrud.${action}.${fmObj.classname}`,
+ [this.token(), fmObj]
+ ).subscribe(
+ res => this.cudObserver.next(res),
+ err => this.cudObserver.error(err),
+ () => this.nextCudRequest()
+ );
+ };
+}
+
+@Injectable()
+export class EgPcrudService {
+
+ constructor(
+ private idl: EgIdlService,
+ private net: EgNetService,
+ private auth: EgAuthService
+ ) {}
+
+ // Pass-thru functions for one-off PCRUD calls
+
+ connect(): Promise<EgPcrudContext> {
+ return this.newContext().connect();
+ }
+
+ newContext(): EgPcrudContext {
+ return new EgPcrudContext(this.idl, this.net, this.auth);
+ }
+
+ retrieve(fmClass: string, pkey: Number | string,
+ pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
+ return this.newContext().retrieve(fmClass, pkey, pcrudOps, reqOps);
+ }
+
+ retrieveAll(fmClass: string, pcrudOps?: any,
+ reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
+ return this.newContext().retrieveAll(fmClass, pcrudOps, reqOps);
+ }
+
+ search(fmClass: string, search: any,
+ pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
+ return this.newContext().search(fmClass, search, pcrudOps, reqOps);
+ }
+
+ create(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.newContext().create(list);
+ }
+
+ update(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.newContext().update(list);
+ }
+
+ remove(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.newContext().remove(list);
+ }
+
+ autoApply(list: EgIdlObject[]): Observable<EgPcrudResponse> {
+ return this.newContext().autoApply(list);
+ }
+}
+
+
+++ /dev/null
-import {Injectable} from '@angular/core';
-import {Observable, Observer} from 'rxjs/Rx';
-import {EgIdlService, EgIdlObject} from './idl';
-import {EgNetService, EgNetRequest} from './net';
-import {EgAuthService} from './auth';
-
-// Externally defined. Used here for debugging.
-declare var js2JSON: (jsThing:any) => string;
-declare var OpenSRF: any; // creating sessions
-
-interface EgPcrudReqOps {
- authoritative?: boolean;
- anonymous?: boolean;
- idlist?: boolean;
- atomic?: boolean;
-}
-
-// For for documentation purposes.
-type EgPcrudResponse = any;
-
-export class EgPcrudContext {
-
- static verboseLogging: boolean = true; //
- static identGenerator: number = 0; // for debug logging
-
- private ident: number;
- private authoritative: boolean;
- private xactCloseMode: string;
- private cudIdx: number;
- private cudAction: string;
- private cudLast: EgPcrudResponse;
- private cudList: EgIdlObject[];
-
- private idl: EgIdlService;
- private net: EgNetService;
- private auth: EgAuthService;
-
- // Tracks nested CUD actions
- cudObserver: Observer<EgPcrudResponse>;
-
- session: any; // OpenSRF.ClientSession
-
- constructor( // passed in by parent service -- not injected
- egIdl: EgIdlService,
- egNet: EgNetService,
- egAuth: EgAuthService
- ) {
- this.idl = egIdl;
- this.net = egNet;
- this.auth = egAuth;
- this.xactCloseMode = 'rollback';
- this.ident = EgPcrudContext.identGenerator++;
- this.session = new OpenSRF.ClientSession('open-ils.pcrud');
- }
-
- toString(): string {
- return '[PCRUDContext ' + this.ident + ']';
- }
-
- log(msg: string): void {
- if (EgPcrudContext.verboseLogging)
- console.debug(this + ': ' + msg);
- }
-
- err(msg: string): void {
- console.error(this + ': ' + msg);
- }
-
- token(reqOps?: EgPcrudReqOps): string {
- return (reqOps && reqOps.anonymous) ?
- 'ANONYMOUS' : this.auth.token();
- }
-
- connect(): Promise<EgPcrudContext> {
- this.log('connect');
- return new Promise( (resolve, reject) => {
- this.session.connect({
- onconnect : () => { resolve(this); }
- });
- })
- }
-
- disconnect(): void {
- this.log('disconnect');
- this.session.disconnect();
- }
-
- retrieve(fmClass: string, pkey: Number | string,
- pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
- if (!reqOps) reqOps = {};
- this.authoritative = reqOps.authoritative || false;
- return this.dispatch(
- `open-ils.pcrud.retrieve.${fmClass}`,
- [this.token(reqOps), pkey, pcrudOps]);
- }
-
- retrieveAll(fmClass: string, pcrudOps?: any,
- reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
- let search = {};
- search[this.idl.classes[fmClass].pkey] = {'!=' : null};
- return this.search(fmClass, search, pcrudOps, reqOps);
- }
-
- search(fmClass: string, search: any,
- pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
- reqOps = reqOps || {};
- this.authoritative = reqOps.authoritative || false;
-
- let returnType = reqOps.idlist ? 'id_list' : 'search';
- let method = `open-ils.pcrud.${returnType}.${fmClass}`;
-
- if (reqOps.atomic) method += '.atomic';
-
- return this.dispatch(method, [this.token(reqOps), search, pcrudOps]);
- }
-
- create(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.cud('create', list)
- }
- update(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.cud('update', list)
- }
- remove(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.cud('delete', list)
- }
- autoApply(list: EgIdlObject[]): Observable<EgPcrudResponse> { // RENAMED
- return this.cud('auto', list)
- }
-
- xactClose(): Observable<EgPcrudResponse> {
- return this.sendRequest(
- 'open-ils.pcrud.transaction.' + this.xactCloseMode,
- [this.token()]
- );
- };
-
- xactBegin(): Observable<EgPcrudResponse> {
- return this.sendRequest(
- 'open-ils.pcrud.transaction.begin', [this.token()]
- );
- };
-
- private dispatch(method: string, params: any[]): Observable<EgPcrudResponse> {
- if (this.authoritative) {
- return this.wrapXact(() => {
- return this.sendRequest(method, params);
- });
- } else {
- return this.sendRequest(method, params)
- }
- };
-
-
- // => connect
- // => xact_begin
- // => action
- // => xact_close(commit/rollback)
- // => disconnect
- wrapXact(mainFunc: () => Observable<EgPcrudResponse>): Observable<EgPcrudResponse> {
- return Observable.create(observer => {
-
- // 1. connect
- this.connect()
-
- // 2. start the transaction
- .then(() => {return this.xactBegin().toPromise()})
-
- // 3. execute the main body
- .then(() => {
-
- mainFunc().subscribe(
- res => observer.next(res),
- err => observer.error(err),
- () => {
- this.xactClose().toPromise().then(() => {
- // 5. disconnect
- this.disconnect();
- // 6. all done
- observer.complete();
- });
- }
- );
- })
- });
- };
-
- private sendRequest(method: string,
- params: any[]): Observable<EgPcrudResponse> {
-
- this.log(`sendRequest(${method})`);
-
- return this.net.requestCompiled(
- new EgNetRequest(
- 'open-ils.pcrud', method, params, this.session)
- );
- }
-
- private cud(action: string,
- list: EgIdlObject | EgIdlObject[]): Observable<EgPcrudResponse> {
-
- this.log(`CUD(): ${action}`);
-
- this.cudIdx = 0;
- this.cudAction = action;
- this.xactCloseMode = 'commit';
-
- if (!Array.isArray(list)) this.cudList = [list];
-
- return this.wrapXact(() => {
- return Observable.create(observer => {
- this.cudObserver = observer;
- this.nextCudRequest();
- });
- });
- }
-
- /**
- * Loops through the list of objects to update and sends
- * them one at a time to the server for processing. Once
- * all are done, the cudObserver is resolved.
- */
- nextCudRequest(): void {
- if (this.cudIdx >= this.cudList.length) {
- this.cudObserver.complete();
- return;
- }
-
- let action = this.cudAction;
- let fmObj = this.cudList[this.cudIdx++];
-
- if (action == 'auto') {
- if (fmObj.ischanged()) action = 'update';
- if (fmObj.isnew()) action = 'create';
- if (fmObj.isdeleted()) action = 'delete';
-
- if (action == 'auto') {
- // object does not need updating; move along
- this.nextCudRequest();
- }
- }
-
- this.sendRequest(
- `open-ils.pcrud.${action}.${fmObj.classname}`,
- [this.token(), fmObj]
- ).subscribe(
- res => this.cudObserver.next(res),
- err => this.cudObserver.error(err),
- () => this.nextCudRequest()
- );
- };
-}
-
-@Injectable()
-export class EgPcrudService {
-
- constructor(
- private idl: EgIdlService,
- private net: EgNetService,
- private auth: EgAuthService
- ) {}
-
- // Pass-thru functions for one-off PCRUD calls
-
- connect(): Promise<EgPcrudContext> {
- return this.newContext().connect();
- }
-
- newContext(): EgPcrudContext {
- return new EgPcrudContext(this.idl, this.net, this.auth);
- }
-
- retrieve(fmClass: string, pkey: Number | string,
- pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
- return this.newContext().retrieve(fmClass, pkey, pcrudOps, reqOps);
- }
-
- retrieveAll(fmClass: string, pcrudOps?: any,
- reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
- return this.newContext().retrieveAll(fmClass, pcrudOps, reqOps);
- }
-
- search(fmClass: string, search: any,
- pcrudOps?: any, reqOps?: EgPcrudReqOps): Observable<EgPcrudResponse> {
- return this.newContext().search(fmClass, search, pcrudOps, reqOps);
- }
-
- create(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.newContext().create(list);
- }
-
- update(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.newContext().update(list);
- }
-
- remove(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.newContext().remove(list);
- }
-
- autoApply(list: EgIdlObject[]): Observable<EgPcrudResponse> {
- return this.newContext().autoApply(list);
- }
-}
-
-
--- /dev/null
+import {Injectable} from '@angular/core';
+import {EgNetService} from './net.service';
+import {EgOrgService} from './org.service';
+import {EgAuthService} from './auth.service';
+
+interface HasPermAtResult {
+ [permName: string]: number[];
+}
+
+interface HasPermHereResult {
+ [permName: string]: boolean;
+}
+
+@Injectable()
+export class EgPermService {
+
+ constructor(
+ private net: EgNetService,
+ private org: EgOrgService,
+ private auth: EgAuthService,
+ ) {}
+
+ // workstation not required.
+ hasWorkPermAt(permNames: string[], asId?: boolean): Promise<HasPermAtResult> {
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.user.has_work_perm_at.batch',
+ this.auth.token(), permNames
+ ).toPromise().then(resp => {
+ var answer: HasPermAtResult = {};
+ permNames.forEach(perm => {
+ var orgs = [];
+ resp[perm].forEach(oneOrg => {
+ orgs = orgs.concat(this.org.descendants(oneOrg, asId));
+ });
+ answer[perm] = orgs;
+ });
+
+ return answer;
+ });
+ }
+
+ // workstation required
+ hasWorkPermHere(permNames: string[]): Promise<HasPermHereResult> {
+ let wsId: number = +this.auth.user().wsid();
+
+ if (!wsId)
+ return Promise.reject('hasWorkPermHere requires a workstation');
+
+ return this.hasWorkPermAt(permNames, true).then(resp => {
+ let answer: HasPermHereResult = {};
+ Object.keys(resp).forEach(perm => {
+ answer[perm] = resp[perm].indexOf(wsId) > -1;
+ });
+ return answer;
+ });
+ }
+}
+++ /dev/null
-import {Injectable} from '@angular/core';
-import {EgNetService} from './net';
-import {EgOrgService} from './org';
-import {EgAuthService} from './auth';
-
-interface HasPermAtResult {
- [permName: string]: number[];
-}
-
-interface HasPermHereResult {
- [permName: string]: boolean;
-}
-
-@Injectable()
-export class EgPermService {
-
- constructor(
- private net: EgNetService,
- private org: EgOrgService,
- private auth: EgAuthService,
- ) {}
-
- // workstation not required.
- hasWorkPermAt(permNames: string[], asId?: boolean): Promise<HasPermAtResult> {
- return this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.user.has_work_perm_at.batch',
- this.auth.token(), permNames
- ).toPromise().then(resp => {
- var answer: HasPermAtResult = {};
- permNames.forEach(perm => {
- var orgs = [];
- resp[perm].forEach(oneOrg => {
- orgs = orgs.concat(this.org.descendants(oneOrg, asId));
- });
- answer[perm] = orgs;
- });
-
- return answer;
- });
- }
-
- // workstation required
- hasWorkPermHere(permNames: string[]): Promise<HasPermHereResult> {
- let wsId: number = +this.auth.user().wsid();
-
- if (!wsId)
- return Promise.reject('hasWorkPermHere requires a workstation');
-
- return this.hasWorkPermAt(permNames, true).then(resp => {
- let answer: HasPermHereResult = {};
- Object.keys(resp).forEach(perm => {
- answer[perm] = resp[perm].indexOf(wsId) > -1;
- });
- return answer;
- });
- }
-}
--- /dev/null
+/**
+ * Store and retrieve data from various sources.
+ */
+import {Injectable} from '@angular/core';
+import {Observable} from 'rxjs/Rx';
+import {CookieService} from 'ngx-cookie';
+
+@Injectable()
+export class EgStoreService {
+
+ // Base path for cookie-based storage.
+ // Useful for limiting cookies to subsections of the application.
+ // Store cookies globally by default.
+ // Note cookies shared with /eg/staff must be stored at "/"
+ loginSessionBasePath: string = '/';
+
+ // Set of keys whose values should disappear at logout.
+ loginSessionKeys: string[] = [
+ 'eg.auth.token',
+ 'eg.auth.time',
+ 'eg.auth.token.oc',
+ 'eg.auth.time.oc'
+ ];
+
+ constructor(private cookieService: CookieService) {}
+
+ private parseJson(valJson: string): any {
+ if (valJson == null || valJson == '') return null;
+ try {
+ return JSON.parse(valJson);
+ } catch(E) {
+ console.error(`Failure to parse JSON: ${E} => ${valJson}`);
+ return null;
+ }
+ }
+
+ /**
+ * Add a an app-local login session key
+ */
+ addLoginSessionKey(key: string): void {
+ this.loginSessionKeys.push(key);
+ }
+
+ setItem(key: string, val: any, isJson?: Boolean): Promise<void> {
+ // TODO: route keys appropriately
+ this.setLocalItem(key, val, false);
+ return Promise.resolve();
+ }
+
+ setLocalItem(key: string, val: any, isJson?: Boolean): void {
+ if (!isJson) val = JSON.stringify(val);
+ window.localStorage.setItem(key, val);
+ }
+
+ setServerItem(key: string, val: any): Promise<void> {
+ 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 {
+ if (!isJson) val = JSON.stringify(val);
+ this.cookieService.put(key, val, {path : this.loginSessionBasePath});
+ }
+
+ getItem(key: string): Promise<any> {
+ // TODO: route keys appropriately
+ return Promise.resolve(this.getLocalItem(key));
+ }
+
+ getLocalItem(key: string): any {
+ return this.parseJson(window.localStorage.getItem(key));
+ }
+
+ getServerItem(key: string): Promise<any> {
+ return Promise.resolve();
+ }
+
+ getSessionItem(key: string): any {
+ return this.parseJson(window.sessionStorage.getItem(key));
+ }
+
+ getLoginSessionItem(key: string): any {
+ return this.parseJson(this.cookieService.get(key));
+ }
+
+ removeItem(key: string): Promise<any> {
+ // TODO: route keys appropriately
+ return Promise.resolve(this.removeLocalItem(key));
+ }
+
+ removeLocalItem(key: string): void {
+ window.localStorage.removeItem(key);
+ }
+
+ removeServerItem(key: string): Promise<void> {
+ return Promise.resolve();
+ }
+
+ removeSessionItem(key: string): void {
+ window.sessionStorage.removeItem(key);
+ }
+
+ removeLoginSessionItem(key: string): void {
+ this.cookieService.remove(key, {path : this.loginSessionBasePath});
+ }
+
+ clearLoginSessionItems(): void {
+ this.loginSessionKeys.forEach(
+ key => this.removeLoginSessionItem(key)
+ );
+ }
+}
+
+++ /dev/null
-/**
- * Store and retrieve data from various sources.
- */
-import {Injectable} from '@angular/core';
-import {Observable} from 'rxjs/Rx';
-import {CookieService} from 'ngx-cookie';
-
-@Injectable()
-export class EgStoreService {
-
- // Base path for cookie-based storage.
- // Useful for limiting cookies to subsections of the application.
- // Store cookies globally by default.
- // Note cookies shared with /eg/staff must be stored at "/"
- loginSessionBasePath: string = '/';
-
- // Set of keys whose values should disappear at logout.
- loginSessionKeys: string[] = [
- 'eg.auth.token',
- 'eg.auth.time',
- 'eg.auth.token.oc',
- 'eg.auth.time.oc'
- ];
-
- constructor(private cookieService: CookieService) {}
-
- private parseJson(valJson: string): any {
- if (valJson == null || valJson == '') return null;
- try {
- return JSON.parse(valJson);
- } catch(E) {
- console.error(`Failure to parse JSON: ${E} => ${valJson}`);
- return null;
- }
- }
-
- /**
- * Add a an app-local login session key
- */
- addLoginSessionKey(key: string): void {
- this.loginSessionKeys.push(key);
- }
-
- setItem(key: string, val: any, isJson?: Boolean): Promise<void> {
- // TODO: route keys appropriately
- this.setLocalItem(key, val, false);
- return Promise.resolve();
- }
-
- setLocalItem(key: string, val: any, isJson?: Boolean): void {
- if (!isJson) val = JSON.stringify(val);
- window.localStorage.setItem(key, val);
- }
-
- setServerItem(key: string, val: any): Promise<void> {
- 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 {
- if (!isJson) val = JSON.stringify(val);
- this.cookieService.put(key, val, {path : this.loginSessionBasePath});
- }
-
- getItem(key: string): Promise<any> {
- // TODO: route keys appropriately
- return Promise.resolve(this.getLocalItem(key));
- }
-
- getLocalItem(key: string): any {
- return this.parseJson(window.localStorage.getItem(key));
- }
-
- getServerItem(key: string): Promise<any> {
- return Promise.resolve();
- }
-
- getSessionItem(key: string): any {
- return this.parseJson(window.sessionStorage.getItem(key));
- }
-
- getLoginSessionItem(key: string): any {
- return this.parseJson(this.cookieService.get(key));
- }
-
- removeItem(key: string): Promise<any> {
- // TODO: route keys appropriately
- return Promise.resolve(this.removeLocalItem(key));
- }
-
- removeLocalItem(key: string): void {
- window.localStorage.removeItem(key);
- }
-
- removeServerItem(key: string): Promise<void> {
- return Promise.resolve();
- }
-
- removeSessionItem(key: string): void {
- window.sessionStorage.removeItem(key);
- }
-
- removeLoginSessionItem(key: string): void {
- this.cookieService.remove(key, {path : this.loginSessionBasePath});
- }
-
- clearLoginSessionItems(): void {
- this.loginSessionKeys.forEach(
- key => this.removeLoginSessionItem(key)
- );
- }
-}
-
// Import service handles so we can downgrade them.
import {EgCommonModule} from './common.module';
-import {EgEventService} from '@eg/core/event';
-import {EgStoreService} from '@eg/core/store';
-import {EgIdlService} from '@eg/core/idl';
-import {EgNetService} from '@eg/core/net';
-import {EgAuthService} from '@eg/core/auth';
-import {EgPermService} from '@eg/core/perm';
-import {EgPcrudService} from '@eg/core/pcrud';
-import {EgOrgService} from '@eg/core/org';
+import {EgEventService} from '@eg/core/event.service';
+import {EgStoreService} from '@eg/core/store.service';
+import {EgIdlService} from '@eg/core/idl.service';
+import {EgNetService} from '@eg/core/net.service';
+import {EgAuthService} from '@eg/core/auth.service';
+import {EgPermService} from '@eg/core/perm.service';
+import {EgPcrudService} from '@eg/core/pcrud.service';
+import {EgOrgService} from '@eg/core/org.service';
// Downgraded components
//import {EgDialogComponent} from '@eg/share/dialog/dialog.component';
import {Injectable} from '@angular/core';
import {Router, Resolve, RouterStateSnapshot,
ActivatedRouteSnapshot} from '@angular/router';
-import {EgIdlService} from '@eg/core/idl';
-import {EgOrgService} from '@eg/core/org';
+import {EgIdlService} from '@eg/core/idl.service';
+import {EgOrgService} from '@eg/core/org.service';
@Injectable()
export class EgBaseResolver implements Resolve<Promise<void>> {
import {Injectable} from '@angular/core';
import {ParamMap} from '@angular/router';
-import {EgOrgService} from '@eg/core/org';
+import {EgOrgService} from '@eg/core/org.service';
import {CatalogSearchContext, FacetFilter} from './search-context';
import {CATALOG_CCVM_FILTERS} from './catalog.service';
import {Injectable} from '@angular/core';
-import {EgOrgService} from '@eg/core/org';
-import {EgUnapiService} from '@eg/share/unapi';
-import {EgIdlObject} from '@eg/core/idl';
-import {EgNetService} from '@eg/core/net';
-import {EgPcrudService} from '@eg/core/pcrud';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgUnapiService} from '@eg/share/unapi.service';
+import {EgIdlObject} from '@eg/core/idl.service';
+import {EgNetService} from '@eg/core/net.service';
+import {EgPcrudService} from '@eg/core/pcrud.service';
import {CatalogSearchContext, CatalogSearchState} from './search-context';
export const CATALOG_CCVM_FILTERS = [
-import {EgOrgService} from '@eg/core/org';
-import {EgIdlObject} from '@eg/core/idl';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgIdlObject} from '@eg/core/idl.service';
import {Pager} from '@eg/share/util/pager';
import {Params} from '@angular/router';
import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {map, debounceTime} from 'rxjs/operators';
-import {EgAuthService} from '@eg/core/auth';
-import {EgStoreService} from '@eg/core/store';
-import {EgOrgService} from '@eg/core/org';
-import {EgIdlObject} from '@eg/core/idl';
+import {EgAuthService} from '@eg/core/auth.service';
+import {EgStoreService} from '@eg/core/store.service';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgIdlObject} from '@eg/core/idl.service';
import {NgbTypeaheadSelectItemEvent} from '@ng-bootstrap/ng-bootstrap';
// Use a unicode char for spacing instead of ASCII=32 so the browser
--- /dev/null
+import {Injectable, EventEmitter} from '@angular/core';
+import {EgOrgService} from '@eg/core/org.service';
+
+/*
+TODO: Add Display Fields to UNAPI
+https://library.biz/opac/extras/unapi?id=tag::U2@bre/1{bre.extern,holdings_xml,mra}/BR1/0&format=mods32
+*/
+
+const UNAPI_PATH = '/opac/extras/unapi?id=tag::U2@';
+
+interface EgUnapiParams {
+ target: string; // bre, ...
+ id: number | string; // 1 | 1,2,3,4,5
+ extras: string; // {holdings_xml,mra,...}
+ format: string; // mods32, marxml, ...
+ orgId?: number; // org unit ID
+ depth?: number; // org unit depth
+};
+
+@Injectable()
+export class EgUnapiService {
+
+ constructor(private org: EgOrgService) {}
+
+ createUrl(params: EgUnapiParams): string {
+ let depth = params.depth || 0;
+ let org = params.orgId ? this.org.get(params.orgId) : this.org.root();
+
+ return `${UNAPI_PATH}${params.target}/${params.id}${params.extras}/` +
+ `${org.shortname()}/${depth}&format=${params.format}`;
+ }
+
+ getAsXmlDocument(params: EgUnapiParams): Promise<XMLDocument> {
+ // XReq creates an XML document for us. Seems like the right
+ // tool for the job.
+ let url = this.createUrl(params);
+ return new Promise((resolve, reject) => {
+ var xhttp = new XMLHttpRequest();
+ xhttp.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ if (this.status == 200) {
+ resolve(xhttp.responseXML);
+ } else {
+ reject(`UNAPI request failed for ${url}`);
+ }
+ }
+ }
+ xhttp.open("GET", url, true);
+ xhttp.send();
+ });
+ }
+}
+
+
+++ /dev/null
-import {Injectable, EventEmitter} from '@angular/core';
-import {EgOrgService} from '@eg/core/org';
-
-/*
-TODO: Add Display Fields to UNAPI
-https://library.biz/opac/extras/unapi?id=tag::U2@bre/1{bre.extern,holdings_xml,mra}/BR1/0&format=mods32
-*/
-
-const UNAPI_PATH = '/opac/extras/unapi?id=tag::U2@';
-
-interface EgUnapiParams {
- target: string; // bre, ...
- id: number | string; // 1 | 1,2,3,4,5
- extras: string; // {holdings_xml,mra,...}
- format: string; // mods32, marxml, ...
- orgId?: number; // org unit ID
- depth?: number; // org unit depth
-};
-
-@Injectable()
-export class EgUnapiService {
-
- constructor(private org: EgOrgService) {}
-
- createUrl(params: EgUnapiParams): string {
- let depth = params.depth || 0;
- let org = params.orgId ? this.org.get(params.orgId) : this.org.root();
-
- return `${UNAPI_PATH}${params.target}/${params.id}${params.extras}/` +
- `${org.shortname()}/${depth}&format=${params.format}`;
- }
-
- getAsXmlDocument(params: EgUnapiParams): Promise<XMLDocument> {
- // XReq creates an XML document for us. Seems like the right
- // tool for the job.
- let url = this.createUrl(params);
- return new Promise((resolve, reject) => {
- var xhttp = new XMLHttpRequest();
- xhttp.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status == 200) {
- resolve(xhttp.responseXML);
- } else {
- reject(`UNAPI request failed for ${url}`);
- }
- }
- }
- xhttp.open("GET", url, true);
- xhttp.send();
- });
- }
-}
-
-
import {Component, OnInit, ViewChild} from '@angular/core';
import {Router, ActivatedRoute} from '@angular/router';
-import {EgStoreService} from '@eg/core/store';
-import {EgIdlObject} from '@eg/core/idl';
-import {EgNetService} from '@eg/core/net';
-import {EgPermService} from '@eg/core/perm';
-import {EgAuthService} from '@eg/core/auth';
-import {EgOrgService} from '@eg/core/org';
-import {EgEventService} from '@eg/core/event';
+import {EgStoreService} from '@eg/core/store.service';
+import {EgIdlObject} from '@eg/core/idl.service';
+import {EgNetService} from '@eg/core/net.service';
+import {EgPermService} from '@eg/core/perm.service';
+import {EgAuthService} from '@eg/core/auth.service';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgEventService} from '@eg/core/event.service';
import {EgConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
// Slim version of the WS that's stored in the cache.
import {NgModule} from '@angular/core';
import {EgStaffCommonModule} from '@eg/staff/common.module';
-import {EgUnapiService} from '@eg/share/unapi';
+import {EgUnapiService} from '@eg/share/unapi.service';
import {EgCatalogRoutingModule} from './routing.module';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {EgCatalogUrlService} from '@eg/share/catalog/catalog-url.service';
import {Injectable} from '@angular/core';
import {Router, ActivatedRoute} from '@angular/router';
-import {EgIdlObject} from '@eg/core/idl';
-import {EgOrgService} from '@eg/core/org';
+import {EgIdlObject} from '@eg/core/idl.service';
+import {EgOrgService} from '@eg/core/org.service';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {EgCatalogUrlService} from '@eg/share/catalog/catalog-url.service';
import {CatalogSearchContext} from '@eg/share/catalog/search-context';
import {Component, OnInit, Input} from '@angular/core';
-import {EgNetService} from '@eg/core/net';
+import {EgNetService} from '@eg/core/net.service';
import {StaffCatalogService} from '../catalog.service';
import {Pager} from '@eg/share/util/pager';
-import {EgOrgService} from '@eg/core/org';
+import {EgOrgService} from '@eg/core/org.service';
@Component({
selector: 'eg-catalog-copies',
import {Component, OnInit, Input} from '@angular/core';
import {ActivatedRoute, ParamMap} from '@angular/router';
-import {EgPcrudService} from '@eg/core/pcrud';
-import {EgIdlObject} from '@eg/core/idl';
+import {EgPcrudService} from '@eg/core/pcrud.service';
+import {EgIdlObject} from '@eg/core/idl.service';
import {CatalogSearchContext, CatalogSearchState}
from '@eg/share/catalog/search-context';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {Observable, Observer} from 'rxjs/Rx';
import {Router, Resolve, RouterStateSnapshot,
ActivatedRouteSnapshot} from '@angular/router';
-import {EgStoreService} from '@eg/core/store';
-import {EgNetService} from '@eg/core/net';
-import {EgOrgService} from '@eg/core/org';
-import {EgAuthService} from '@eg/core/auth';
-import {EgPcrudService} from '@eg/core/pcrud';
+import {EgStoreService} from '@eg/core/store.service';
+import {EgNetService} from '@eg/core/net.service';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgAuthService} from '@eg/core/auth.service';
+import {EgPcrudService} from '@eg/core/pcrud.service';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {StaffCatalogService} from './catalog.service';
import {Component, OnInit, Input} from '@angular/core';
import {Router} from '@angular/router';
-import {EgOrgService} from '@eg/core/org';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgNetService} from '@eg/core/net.service';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {CatalogSearchContext} from '@eg/share/catalog/search-context';
-import {EgNetService} from '@eg/core/net';
import {EgCatalogUrlService} from '@eg/share/catalog/catalog-url.service';
import {StaffCatalogService} from '../catalog.service';
import {EgCatalogUrlService} from '@eg/share/catalog/catalog-url.service';
import {CatalogSearchContext, CatalogSearchState}
from '@eg/share/catalog/search-context';
-import {EgPcrudService} from '@eg/core/pcrud';
+import {EgPcrudService} from '@eg/core/pcrud.service';
import {StaffCatalogService} from '../catalog.service';
-import {EgIdlObject} from '@eg/core/idl';
+import {EgIdlObject} from '@eg/core/idl.service';
@Component({
selector: 'eg-catalog-results',
import {Component, OnInit, AfterViewInit, Renderer} from '@angular/core';
-import {EgIdlObject} from '@eg/core/idl';
-import {EgOrgService} from '@eg/core/org';
+import {EgIdlObject} from '@eg/core/idl.service';
+import {EgOrgService} from '@eg/core/org.service';
import {EgCatalogService,} from '@eg/share/catalog/catalog.service';
import {CatalogSearchContext, CatalogSearchState}
from '@eg/share/catalog/search-context';
import {Component, OnInit, Renderer} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
-import {EgNetService} from '@eg/core/net';
-import {EgAuthService} from '@eg/core/auth';
+import {EgNetService} from '@eg/core/net.service';
+import {EgAuthService} from '@eg/core/auth.service';
@Component({
templateUrl: 'bcsearch.component.html'
import {Component, OnInit, Renderer} from '@angular/core';
import {Location} from '@angular/common';
import {Router, ActivatedRoute} from '@angular/router';
-import {EgAuthService, EgAuthWsState} from '@eg/core/auth';
-import {EgStoreService} from '@eg/core/store';
+import {EgAuthService, EgAuthWsState} from '@eg/core/auth.service';
+import {EgStoreService} from '@eg/core/store.service';
@Component({
templateUrl : './login.component.html'
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
-import {EgAuthService} from '@eg/core/auth';
+import {EgAuthService} from '@eg/core/auth.service';
@Component({
selector: 'eg-staff-nav-bar',
import {Observable, Observer} from 'rxjs/Rx';
import {Router, Resolve, RouterStateSnapshot,
ActivatedRoute, ActivatedRouteSnapshot} from '@angular/router';
-import {EgStoreService} from '@eg/core/store';
-import {EgNetService} from '@eg/core/net';
-import {EgAuthService} from '@eg/core/auth';
+import {EgStoreService} from '@eg/core/store.service';
+import {EgNetService} from '@eg/core/net.service';
+import {EgAuthService} from '@eg/core/auth.service';
/**
* Load data used by all staff modules.
import {Component, OnInit, Input} from '@angular/core';
-import {EgNetService} from '@eg/core/net';
-import {EgPcrudService} from '@eg/core/pcrud';
+import {EgNetService} from '@eg/core/net.service';
+import {EgPcrudService} from '@eg/core/pcrud.service';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
@Component({
import {Component, OnInit, NgZone} from '@angular/core';
import {Router, ActivatedRoute, NavigationEnd} from '@angular/router';
-import {EgAuthService, EgAuthWsState} from '@eg/core/auth';
-import {EgNetService} from '@eg/core/net';
+import {EgAuthService, EgAuthWsState} from '@eg/core/auth.service';
+import {EgNetService} from '@eg/core/net.service';
@Component({
templateUrl: 'staff.component.html',