LP#1626157 More file name best practices
authorBill Erickson <berickxx@gmail.com>
Thu, 12 Apr 2018 21:55:58 +0000 (21:55 +0000)
committerBill Erickson <berickxx@gmail.com>
Thu, 12 Apr 2018 21:55:58 +0000 (21:55 +0000)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
40 files changed:
Open-ILS/src/eg2/src/app/common.module.ts
Open-ILS/src/eg2/src/app/core/auth.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/auth.ts [deleted file]
Open-ILS/src/eg2/src/app/core/event.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/event.ts [deleted file]
Open-ILS/src/eg2/src/app/core/idl.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/idl.ts [deleted file]
Open-ILS/src/eg2/src/app/core/net.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/net.ts [deleted file]
Open-ILS/src/eg2/src/app/core/org.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/org.ts [deleted file]
Open-ILS/src/eg2/src/app/core/pcrud.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/pcrud.ts [deleted file]
Open-ILS/src/eg2/src/app/core/perm.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/perm.ts [deleted file]
Open-ILS/src/eg2/src/app/core/store.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/core/store.ts [deleted file]
Open-ILS/src/eg2/src/app/migration.module.ts
Open-ILS/src/eg2/src/app/resolver.service.ts
Open-ILS/src/eg2/src/app/share/catalog/catalog-url.service.ts
Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/share/catalog/search-context.ts
Open-ILS/src/eg2/src/app/share/org-select.component.ts
Open-ILS/src/eg2/src/app/share/unapi.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/unapi.ts [deleted file]
Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts
Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/resolver.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts
Open-ILS/src/eg2/src/app/staff/circ/patron/bcsearch/bcsearch.component.ts
Open-ILS/src/eg2/src/app/staff/login.component.ts
Open-ILS/src/eg2/src/app/staff/nav.component.ts
Open-ILS/src/eg2/src/app/staff/resolver.service.ts
Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.ts
Open-ILS/src/eg2/src/app/staff/staff.component.ts

index ea68a75..20a9b5e 100644 (file)
@@ -6,14 +6,14 @@ import {NgModule, ModuleWithProviders} from '@angular/core';
 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: [
diff --git a/Open-ILS/src/eg2/src/app/core/auth.service.ts b/Open-ILS/src/eg2/src/app/core/auth.service.ts
new file mode 100644 (file)
index 0000000..a14fd9f
--- /dev/null
@@ -0,0 +1,292 @@
+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();
+    }
+}
diff --git a/Open-ILS/src/eg2/src/app/core/auth.ts b/Open-ILS/src/eg2/src/app/core/auth.ts
deleted file mode 100644 (file)
index ab4b133..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-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();
-    }
-}
diff --git a/Open-ILS/src/eg2/src/app/core/event.service.ts b/Open-ILS/src/eg2/src/app/core/event.service.ts
new file mode 100644 (file)
index 0000000..33e3f84
--- /dev/null
@@ -0,0 +1,53 @@
+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;
+    }
+}
+
+
diff --git a/Open-ILS/src/eg2/src/app/core/event.ts b/Open-ILS/src/eg2/src/app/core/event.ts
deleted file mode 100644 (file)
index 33e3f84..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-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;
-    }
-}
-
-
diff --git a/Open-ILS/src/eg2/src/app/core/idl.service.ts b/Open-ILS/src/eg2/src/app/core/idl.service.ts
new file mode 100644 (file)
index 0000000..fdbd111
--- /dev/null
@@ -0,0 +1,81 @@
+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);
+    };
+}
+
diff --git a/Open-ILS/src/eg2/src/app/core/idl.ts b/Open-ILS/src/eg2/src/app/core/idl.ts
deleted file mode 100644 (file)
index fdbd111..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-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);
-    };
-}
-
diff --git a/Open-ILS/src/eg2/src/app/core/net.service.ts b/Open-ILS/src/eg2/src/app/core/net.service.ts
new file mode 100644 (file)
index 0000000..bcedfc7
--- /dev/null
@@ -0,0 +1,183 @@
+/**
+ * 
+ * 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);
+    };
+}
diff --git a/Open-ILS/src/eg2/src/app/core/net.ts b/Open-ILS/src/eg2/src/app/core/net.ts
deleted file mode 100644 (file)
index f6ec6b2..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * 
- * 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);
-    };
-}
diff --git a/Open-ILS/src/eg2/src/app/core/org.service.ts b/Open-ILS/src/eg2/src/app/core/org.service.ts
new file mode 100644 (file)
index 0000000..b2ad250
--- /dev/null
@@ -0,0 +1,267 @@
+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;
+        });
+    }
+}
diff --git a/Open-ILS/src/eg2/src/app/core/org.ts b/Open-ILS/src/eg2/src/app/core/org.ts
deleted file mode 100644 (file)
index 0cf87a4..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-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;
-        });
-    }
-}
diff --git a/Open-ILS/src/eg2/src/app/core/pcrud.service.ts b/Open-ILS/src/eg2/src/app/core/pcrud.service.ts
new file mode 100644 (file)
index 0000000..614f0ca
--- /dev/null
@@ -0,0 +1,304 @@
+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);
+    }
+}
+
+
diff --git a/Open-ILS/src/eg2/src/app/core/pcrud.ts b/Open-ILS/src/eg2/src/app/core/pcrud.ts
deleted file mode 100644 (file)
index 6a8dc7d..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-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);
-    }
-}
-
-
diff --git a/Open-ILS/src/eg2/src/app/core/perm.service.ts b/Open-ILS/src/eg2/src/app/core/perm.service.ts
new file mode 100644 (file)
index 0000000..a2c439b
--- /dev/null
@@ -0,0 +1,58 @@
+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;
+        });
+    }
+}
diff --git a/Open-ILS/src/eg2/src/app/core/perm.ts b/Open-ILS/src/eg2/src/app/core/perm.ts
deleted file mode 100644 (file)
index 6f7cd9f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-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;
-        });
-    }
-}
diff --git a/Open-ILS/src/eg2/src/app/core/store.service.ts b/Open-ILS/src/eg2/src/app/core/store.service.ts
new file mode 100644 (file)
index 0000000..218ad83
--- /dev/null
@@ -0,0 +1,117 @@
+/**
+ * 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)
+        );
+    }
+}
+
diff --git a/Open-ILS/src/eg2/src/app/core/store.ts b/Open-ILS/src/eg2/src/app/core/store.ts
deleted file mode 100644 (file)
index 218ad83..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * 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)
-        );
-    }
-}
-
index 92cec10..88c84ae 100644 (file)
@@ -21,14 +21,14 @@ import {Title} from '@angular/platform-browser';
 
 // 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';
index 8fd14d7..0049c40 100644 (file)
@@ -1,8 +1,8 @@
 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>> {
index 932416f..707d44f 100644 (file)
@@ -1,6 +1,6 @@
 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';
 
index 3433695..f59c6c1 100644 (file)
@@ -1,9 +1,9 @@
 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 = [
index 6bd5380..54224ff 100644 (file)
@@ -1,5 +1,5 @@
-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';
 
index 7738215..f502c9e 100644 (file)
@@ -1,10 +1,10 @@
 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 
diff --git a/Open-ILS/src/eg2/src/app/share/unapi.service.ts b/Open-ILS/src/eg2/src/app/share/unapi.service.ts
new file mode 100644 (file)
index 0000000..9034ae4
--- /dev/null
@@ -0,0 +1,54 @@
+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();
+        });
+    }
+}
+
+
diff --git a/Open-ILS/src/eg2/src/app/share/unapi.ts b/Open-ILS/src/eg2/src/app/share/unapi.ts
deleted file mode 100644 (file)
index 28c2589..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-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();
-        });
-    }
-}
-
-
index 690a485..6ee04d2 100644 (file)
@@ -1,12 +1,12 @@
 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.
index 80a1499..7438ec9 100644 (file)
@@ -1,6 +1,6 @@
 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';
index 0cf04ca..6cfc715 100644 (file)
@@ -1,7 +1,7 @@
 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';
index cae7920..d4b6957 100644 (file)
@@ -1,8 +1,8 @@
 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',
index 61e5759..7df0e4a 100644 (file)
@@ -1,7 +1,7 @@
 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';
index 8452323..f081fc2 100644 (file)
@@ -2,11 +2,11 @@ import {Injectable} from '@angular/core';
 import {Observable, Observer} from 'rxjs/Rx';
 import {Router, Resolve, RouterStateSnapshot,
         ActivatedRouteSnapshot} from '@angular/router';
-import {EgStoreService} from '@eg/core/store';
-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';
 
index cf903f5..14f33e2 100644 (file)
@@ -1,9 +1,9 @@
 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';
 
index ff9c259..a970154 100644 (file)
@@ -6,9 +6,9 @@ import {EgCatalogService} from '@eg/share/catalog/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',
index 615e608..cf6d66d 100644 (file)
@@ -1,6 +1,6 @@
 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';
index 35e9e85..86e85f3 100644 (file)
@@ -1,7 +1,7 @@
 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'
index 85d0490..d46bb74 100644 (file)
@@ -1,8 +1,8 @@
 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'
index 7b87841..32577ad 100644 (file)
@@ -1,6 +1,6 @@
 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',
index 63a86f9..530aeb1 100644 (file)
@@ -3,9 +3,9 @@ import {Location} from '@angular/common';
 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.
index 877b18a..c672add 100644 (file)
@@ -1,6 +1,6 @@
 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({
index 864beab..7bdce0b 100644 (file)
@@ -1,7 +1,7 @@
 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',