From 91d3b2280a210214317cbf9b91bb72871c1d891c Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 23 Apr 2019 07:57:31 -0700 Subject: [PATCH] LP1825896 Store workstations in Hatch when available When Hatch is enabled, use Hatch for storing workstation registration information. If workstations are found in localStorage, they are merged into the collection of workstations stored in hatch and removed from localStorage. Include DB udpate to add workstation setting 'eg.hatch.enable.printing' so that it may live on the server. Signed-off-by: Bill Erickson --- Open-ILS/src/eg2/src/app/common.module.ts | 2 +- Open-ILS/src/eg2/src/app/core/auth.service.ts | 24 +-- .../src/app/{share/print => core}/hatch.service.ts | 25 ++- Open-ILS/src/eg2/src/app/core/store.service.ts | 115 ++++++++++- .../src/eg2/src/app/share/print/print.component.ts | 16 +- .../workstations/workstations.component.ts | 27 +-- Open-ILS/src/eg2/src/app/staff/login.component.ts | 12 +- Open-ILS/src/eg2/src/app/staff/resolver.service.ts | 4 + Open-ILS/src/eg2/src/app/staff/staff.component.ts | 1 - Open-ILS/src/sql/Pg/950.data.seed-values.sql | 10 + .../Pg/upgrade/XXXX.data.hatch-enable-print.sql | 18 ++ .../js/ui/default/staff/admin/workstation/app.js | 14 +- Open-ILS/web/js/ui/default/staff/app.js | 4 +- Open-ILS/web/js/ui/default/staff/offline.js | 4 +- Open-ILS/web/js/ui/default/staff/services/hatch.js | 219 +++++++++++++++------ 15 files changed, 381 insertions(+), 114 deletions(-) rename Open-ILS/src/eg2/src/app/{share/print => core}/hatch.service.ts (78%) create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.hatch-enable-print.sql diff --git a/Open-ILS/src/eg2/src/app/common.module.ts b/Open-ILS/src/eg2/src/app/common.module.ts index f1d4467830..80520c79bb 100644 --- a/Open-ILS/src/eg2/src/app/common.module.ts +++ b/Open-ILS/src/eg2/src/app/common.module.ts @@ -14,7 +14,7 @@ They do not have to be added to the providers list. // consider moving these to core... import {FormatService, FormatValuePipe} from '@eg/core/format.service'; -import {HatchService} from '@eg/share/print/hatch.service'; +import {HatchService} from '@eg/core/hatch.service'; import {PrintService} from '@eg/share/print/print.service'; // Globally available components diff --git a/Open-ILS/src/eg2/src/app/core/auth.service.ts b/Open-ILS/src/eg2/src/app/core/auth.service.ts index dad2acdb90..a173d6304a 100644 --- a/Open-ILS/src/eg2/src/app/core/auth.service.ts +++ b/Open-ILS/src/eg2/src/app/core/auth.service.ts @@ -286,22 +286,22 @@ export class AuthService { } return new Promise((resolve, reject) => { - const workstations = - this.store.getLocalItem('eg.workstation.all'); + return this.store.getWorkstations().then(workstations => { - if (workstations) { - const ws = workstations.filter( - w => Number(w.id) === Number(this.user().wsid()))[0]; + if (workstations) { + const ws = workstations.filter( + w => Number(w.id) === Number(this.user().wsid()))[0]; - if (ws) { - this.activeUser.workstation = ws.name; - this.workstationState = AuthWsState.VALID; - return resolve(); + if (ws) { + this.activeUser.workstation = ws.name; + this.workstationState = AuthWsState.VALID; + return resolve(); + } } - } - this.workstationState = AuthWsState.NOT_FOUND_LOCAL; - reject(); + this.workstationState = AuthWsState.NOT_FOUND_LOCAL; + reject(); + }); }); } diff --git a/Open-ILS/src/eg2/src/app/share/print/hatch.service.ts b/Open-ILS/src/eg2/src/app/core/hatch.service.ts similarity index 78% rename from Open-ILS/src/eg2/src/app/share/print/hatch.service.ts rename to Open-ILS/src/eg2/src/app/core/hatch.service.ts index 015088765a..b61ee176e4 100644 --- a/Open-ILS/src/eg2/src/app/share/print/hatch.service.ts +++ b/Open-ILS/src/eg2/src/app/core/hatch.service.ts @@ -22,12 +22,12 @@ export class HatchMessage { } } -@Injectable() +@Injectable({providedIn: 'root'}) export class HatchService { isAvailable: boolean; msgId: number; - messages: {[msgid:number]: HatchMessage}; + messages: {[msgid: number]: HatchMessage}; constructor() { this.isAvailable = null; @@ -44,7 +44,7 @@ export class HatchService { // When the Hatch extension loads, it tacks an attribute onto // the top-level documentElement to indicate it's available. if (!window.document.documentElement.getAttribute('hatch-is-open')) { - console.warn('Could not connect to Hatch'); + console.debug('Could not connect to Hatch'); return this.isAvailable = false; } @@ -62,7 +62,7 @@ export class HatchService { this.handleResponse(event.data); } - }); + }); return this.isAvailable = true; } @@ -87,7 +87,7 @@ export class HatchService { // Handle the data sent back to the browser from Hatch. handleResponse(data: any) { - const msg = this.messages[data.msgid]; + const msg = this.messages[data.msgid]; if (!msg) { console.warn(`No Hatch request found with ID ${data.msgid}`); return; @@ -105,5 +105,20 @@ export class HatchService { msg.rejector(msg); } } + + getItem(key: string): Promise { + const msg = new HatchMessage({action: 'get', key: key}); + return this.sendRequest(msg).then((m: HatchMessage) => m.response); + } + + setItem(key: string, val: any): Promise { + const msg = new HatchMessage({action: 'set', key: key, content: val}); + return this.sendRequest(msg).then((m: HatchMessage) => m.response); + } + + removeItem(key: string): Promise { + const msg = new HatchMessage({action: 'remove', key: key}); + return this.sendRequest(msg).then((m: HatchMessage) => m.response); + } } diff --git a/Open-ILS/src/eg2/src/app/core/store.service.ts b/Open-ILS/src/eg2/src/app/core/store.service.ts index 46dd6214fe..7b239d2ad2 100644 --- a/Open-ILS/src/eg2/src/app/core/store.service.ts +++ b/Open-ILS/src/eg2/src/app/core/store.service.ts @@ -11,6 +11,10 @@ */ import {Injectable} from '@angular/core'; import {CookieService} from 'ngx-cookie'; +import {HatchService} from './hatch.service'; + +const WS_ALL_KEY = 'eg.workstation.all'; +const WS_DEF_KEY = 'eg.workstation.default'; @Injectable({providedIn: 'root'}) export class StoreService { @@ -30,7 +34,8 @@ export class StoreService { ]; constructor( - private cookieService: CookieService) { + private cookieService: CookieService, + private hatch: HatchService) { } private parseJson(valJson: string): any { @@ -74,6 +79,31 @@ export class StoreService { {path : this.loginSessionBasePath, secure: true}); } + setWorkstations(val: any, isJson?: boolean): Promise { + if (this.hatch.isAvailable) { + return this.hatch.setItem(WS_ALL_KEY, val).then( + ok => { + // When clearing workstations, remove the default. + if (!val || val.length === 0) { + return this.hatch.removeItem(WS_DEF_KEY); + } + } + ); + } else { + return Promise.resolve( + this.setLocalItem(WS_ALL_KEY, val, isJson)); + } + } + + setDefaultWorkstation(val: string, isJson?: boolean): Promise { + if (this.hatch.isAvailable) { + return this.hatch.setItem(WS_DEF_KEY, val); + } else { + return Promise.resolve( + this.setLocalItem(WS_DEF_KEY, val, isJson)); + } + } + getLocalItem(key: string): any { return this.parseJson(window.localStorage.getItem(key)); } @@ -86,6 +116,79 @@ export class StoreService { return this.parseJson(this.cookieService.get(key)); } + getWorkstations(): Promise { + if (this.hatch.isAvailable) { + return this.mergeWorkstations().then(ok => { + this.removeLocalItem(WS_ALL_KEY); + return this.hatch.getItem(WS_ALL_KEY); + }); + } else { + return Promise.resolve(this.getLocalItem(WS_ALL_KEY)); + } + } + + // See if any workstatoins are stored in local storage. If so, also + // see if we have any stored in Hatch. If both, merged workstations + // from localStorage in Hatch storage, skipping any whose name + // collide with a workstation in Hatch. If none exist in Hatch, + // copy the localStorage workstations over wholesale. + mergeWorkstations(): Promise { + const existing = this.getLocalItem(WS_ALL_KEY); + + if (!existing || existing.length === 0) { + return Promise.resolve(); + } + + return this.hatch.getItem(WS_ALL_KEY).then(inHatch => { + + if (!inHatch || inHatch.length === 0) { + // Nothing to merge, copy the data over directly + return this.hatch.setItem('eg.workstation.all', existing); + } + + const addMe: any = []; + existing.forEach(ws => { + const match = inHatch.filter(w => w.name === ws.name)[0]; + if (!match) { + console.log( + 'Migrating workstation from local storage to hatch: ' + + ws.name + ); + addMe.push(ws); + } + }); + inHatch = inHatch.concat(addMe); + return this.hatch.setItem(WS_ALL_KEY, inHatch); + }); + } + + getDefaultWorkstation(): Promise { + if (this.hatch.isAvailable) { + return this.hatch.getItem(WS_DEF_KEY).then(name => { + if (name) { + // We have a default in Hatch, remove any lingering + // value from localStorage. + this.removeLocalItem(WS_DEF_KEY); + return name; + } else { + // Nothing in Hatch, see if we have a localStorage + // value to migrate to Hatch + name = this.getLocalItem(WS_DEF_KEY); + if (name) { + console.debug( + 'Migrating default workstation to Hatch ' + name); + return this.hatch.setItem(WS_DEF_KEY, name) + .then(ok => name); + } else { + return null; + } + } + }); + } else { + return Promise.resolve(this.getLocalItem(WS_DEF_KEY)); + } + } + removeLocalItem(key: string): void { window.localStorage.removeItem(key); } @@ -98,6 +201,16 @@ export class StoreService { this.cookieService.remove(key, {path : this.loginSessionBasePath}); } + removeDefaultWorkstation(val: string, isJson?: boolean): Promise { + if (this.hatch.isAvailable) { + return this.hatch.removeItem(WS_DEF_KEY); + } else { + return Promise.resolve( + this.removeLocalItem(WS_DEF_KEY)); + } + } + + clearLoginSessionItems(): void { this.loginSessionKeys.forEach( key => this.removeLoginSessionItem(key) diff --git a/Open-ILS/src/eg2/src/app/share/print/print.component.ts b/Open-ILS/src/eg2/src/app/share/print/print.component.ts index e7754abbd3..33cdcb2641 100644 --- a/Open-ILS/src/eg2/src/app/share/print/print.component.ts +++ b/Open-ILS/src/eg2/src/app/share/print/print.component.ts @@ -2,7 +2,7 @@ import {Component, OnInit, TemplateRef, ElementRef, Renderer2} from '@angular/co import {PrintService, PrintRequest} from './print.service'; import {StoreService} from '@eg/core/store.service'; import {ServerStoreService} from '@eg/core/server-store.service'; -import {HatchService, HatchMessage} from './hatch.service'; +import {HatchService, HatchMessage} from '@eg/core/hatch.service'; @Component({ selector: 'eg-print', @@ -24,6 +24,8 @@ export class PrintComponent implements OnInit { printQueue: PrintRequest[]; + useHatch: boolean; + constructor( private renderer: Renderer2, private elm: ElementRef, @@ -41,6 +43,9 @@ export class PrintComponent implements OnInit { this.htmlContainer = this.renderer.selectRootElement('#eg-print-html-container'); + + this.serverStore.getItem('eg.hatch.enable.printing') + .then(use => this.useHatch = use); } handlePrintRequest(printReq: PrintRequest) { @@ -71,7 +76,7 @@ export class PrintComponent implements OnInit { return; } - if (printReq.text && !this.useHatch()) { + if (printReq.text && !this.useHatch) { // Insert HTML into the browser DOM for in-browser printing only. if (printReq.contentType === 'text/plain') { @@ -113,7 +118,7 @@ export class PrintComponent implements OnInit { show_dialog: printReq.showDialog }); - if (this.useHatch()) { + if (this.useHatch) { this.printViaHatch(printReq); } else { // Here the needed HTML is already in the page. @@ -121,11 +126,6 @@ export class PrintComponent implements OnInit { } } - useHatch(): boolean { - return this.store.getLocalItem('eg.hatch.enable.printing') - && this.hatch.connect(); - } - printViaHatch(printReq: PrintRequest) { // Send a full HTML document to Hatch diff --git a/Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.ts index a5c72e2dff..a1d7c0f93e 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.ts @@ -50,13 +50,18 @@ export class WorkstationsComponent implements OnInit { ) {} ngOnInit() { - this.workstations = this.store.getLocalItem('eg.workstation.all') || []; - this.defaultName = this.store.getLocalItem('eg.workstation.default'); - this.selectedName = this.auth.workstation() || this.defaultName; - const rm = this.route.snapshot.paramMap.get('remove'); - if (rm) { - this.removeSelected(this.removeWorkstation = rm); - } + this.store.getWorkstations() + + .then(wsList => { + this.workstations = wsList || []; + return this.store.getDefaultWorkstation(); + + }).then(def => { + this.defaultName = def; + this.selectedName = this.auth.workstation() || this.defaultName; + const rm = this.route.snapshot.paramMap.get('remove'); + if (rm) { this.removeSelected(this.removeWorkstation = rm); } + }); // TODO: use the org selector limitPerm option this.perm.hasWorkPermAt(['REGISTER_WORKSTATION'], true) @@ -85,7 +90,7 @@ export class WorkstationsComponent implements OnInit { setDefault(): void { if (this.selected()) { this.defaultName = this.selected().name; - this.store.setLocalItem('eg.workstation.default', this.defaultName); + this.store.setDefaultWorkstation(this.defaultName); } } @@ -95,11 +100,11 @@ export class WorkstationsComponent implements OnInit { } this.workstations = this.workstations.filter(w => w.name !== name); - this.store.setLocalItem('eg.workstation.all', this.workstations); + this.store.setWorkstations(this.workstations); if (this.defaultName === name) { this.defaultName = null; - this.store.removeLocalItem('eg.workstation.default'); + this.store.removeWorkstations(); } } @@ -172,7 +177,7 @@ export class WorkstationsComponent implements OnInit { }; this.workstations.push(ws); - this.store.setLocalItem('eg.workstation.all', this.workstations); + this.store.setWorkstations(this.workstations); this.newName = ''; // when registering our first workstation, mark it as the // default and show it as selected in the ws selector. diff --git a/Open-ILS/src/eg2/src/app/staff/login.component.ts b/Open-ILS/src/eg2/src/app/staff/login.component.ts index 2c1ac2a26e..da54267d57 100644 --- a/Open-ILS/src/eg2/src/app/staff/login.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/login.component.ts @@ -35,10 +35,14 @@ export class StaffLoginComponent implements OnInit { // Focus username this.renderer.selectRootElement('#username').focus(); - this.workstations = this.store.getLocalItem('eg.workstation.all'); - this.args.workstation = - this.store.getLocalItem('eg.workstation.default'); - this.applyWorkstation(); + this.store.getWorkstations() + .then(wsList => { + this.workstations = wsList; + return this.store.getDefaultWorkstation(); + }).then(def => { + this.args.workstation = def; + this.applyWorkstation(); + }); } applyWorkstation() { diff --git a/Open-ILS/src/eg2/src/app/staff/resolver.service.ts b/Open-ILS/src/eg2/src/app/staff/resolver.service.ts index 2c94ec76d3..74c924c041 100644 --- a/Open-ILS/src/eg2/src/app/staff/resolver.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/resolver.service.ts @@ -9,6 +9,7 @@ import {AuthService, AuthWsState} from '@eg/core/auth.service'; import {PermService} from '@eg/core/perm.service'; import {OrgService} from '@eg/core/org.service'; import {FormatService} from '@eg/core/format.service'; +import {HatchService} from '@eg/core/hatch.service'; const LOGIN_PATH = '/staff/login'; const WS_MANAGE_PATH = '/staff/admin/workstation/workstations/manage'; @@ -26,6 +27,7 @@ export class StaffResolver implements Resolve> { private router: Router, private route: ActivatedRoute, private ngLocation: Location, + private hatch: HatchService, private store: StoreService, private org: OrgService, private net: NetService, @@ -38,6 +40,8 @@ export class StaffResolver implements Resolve> { route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + this.hatch.connect(); + // Staff cookies stay in /$base/staff/ // NOTE: storing session data at '/' so it can be shared by // Angularjs apps. diff --git a/Open-ILS/src/eg2/src/app/staff/staff.component.ts b/Open-ILS/src/eg2/src/app/staff/staff.component.ts index 492b1df14d..440d5f8036 100644 --- a/Open-ILS/src/eg2/src/app/staff/staff.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/staff.component.ts @@ -63,7 +63,6 @@ export class StaffComponent implements OnInit { // Data fetched via StaffResolver is available here. }); - } /** diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index a6fae4dcc7..0f27cbe1e2 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -19955,3 +19955,13 @@ VALUES ( 'cwst', 'label') ); +INSERT INTO config.workstation_setting_type (name, grp, datatype, label) +VALUES ( + 'eg.hatch.enable.printing', 'gui', 'bool', + oils_i18n_gettext( + 'eg.hatch.enable.printing', + 'Use Hatch for printing', + 'cwst', 'label' + ) +); + diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hatch-enable-print.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hatch-enable-print.sql new file mode 100644 index 0000000000..315c85b0d2 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hatch-enable-print.sql @@ -0,0 +1,18 @@ +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version); + +INSERT INTO config.workstation_setting_type (name, grp, datatype, label) +VALUES ( + 'eg.hatch.enable.printing', 'gui', 'bool', + oils_i18n_gettext( + 'eg.hatch.enable.printing', + 'Use Hatch for printing', + 'cwst', 'label' + ) +); + + +COMMIT; + + diff --git a/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js b/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js index d863844e3d..1d8381f1ba 100644 --- a/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js +++ b/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js @@ -72,16 +72,16 @@ function($q , $timeout , $location , egCore , egConfirmDialog) { var service = {}; service.get_all = function() { - return egCore.hatch.getItem('eg.workstation.all') + return egCore.hatch.getWorkstations() .then(function(all) { return all || [] }); } service.get_default = function() { - return egCore.hatch.getItem('eg.workstation.default'); + return egCore.hatch.getDefaultWorkstation(); } service.set_default = function(name) { - return egCore.hatch.setItem('eg.workstation.default', name); + return egCore.hatch.setDefaultWorkstation(name); } service.register_workstation = function(base_name, name, org_id) { @@ -140,7 +140,7 @@ function($q , $timeout , $location , egCore , egConfirmDialog) { return service.get_all() .then(function(all) { all.push(new_ws); - return egCore.hatch.setItem('eg.workstation.all', all) + return egCore.hatch.setWorkstations(all) .then(function() { return new_ws }); }); } @@ -150,13 +150,13 @@ function($q , $timeout , $location , egCore , egConfirmDialog) { service.remove_workstation = function(name) { console.debug('Removing workstation: ' + name); - return egCore.hatch.getItem('eg.workstation.all') + return egCore.hatch.getWorkstations() // remove from list of all workstations .then(function(all) { if (!all) all = []; var keep = all.filter(function(ws) {return ws.name != name}); - return egCore.hatch.setItem('eg.workstation.all', keep) + return egCore.hatch.setWorkstations(keep); }).then(function() { @@ -165,7 +165,7 @@ function($q , $timeout , $location , egCore , egConfirmDialog) { }).then(function(def) { if (def == name) { console.debug('Removing default workstation: ' + name); - return egCore.hatch.removeItem('eg.workstation.default'); + return egCore.hatch.removeDefaultWorkstation(); } }); } diff --git a/Open-ILS/web/js/ui/default/staff/app.js b/Open-ILS/web/js/ui/default/staff/app.js index 053f4014a6..e38b76f92d 100644 --- a/Open-ILS/web/js/ui/default/staff/app.js +++ b/Open-ILS/web/js/ui/default/staff/app.js @@ -60,7 +60,7 @@ function($routeProvider , $locationProvider) { // if the user is already logged in, jump to splash page if (egCore.auth.user()) $location.path('/'); - egCore.hatch.getItem('eg.workstation.all') + egCore.hatch.getWorkstations() .then(function(all) { if (all && all.length) { $scope.workstations = all.map(function(a) { return a.name }); @@ -79,7 +79,7 @@ function($routeProvider , $locationProvider) { } } else { // no workstation requested; use the default - egCore.hatch.getItem('eg.workstation.default') + egCore.hatch.getDefaultWorkstation() .then(function(ws) { $scope.args = {workstation : ws} }); diff --git a/Open-ILS/web/js/ui/default/staff/offline.js b/Open-ILS/web/js/ui/default/staff/offline.js index 7d80de6d5f..5c00daa7f1 100644 --- a/Open-ILS/web/js/ui/default/staff/offline.js +++ b/Open-ILS/web/js/ui/default/staff/offline.js @@ -360,7 +360,7 @@ function($routeProvider , $locationProvider , $compileProvider) { if (setting !== undefined) $scope.do_check_changed = true; }); - egCore.hatch.getItem('eg.workstation.all') + egCore.hatch.getWorkstations() .then(function(all) { if (all && all.length) { $scope.workstations = all; @@ -381,7 +381,7 @@ function($routeProvider , $locationProvider , $compileProvider) { } } else { // no workstation requested; use the default - egCore.hatch.getItem('eg.workstation.default') + egCore.hatch.getDefaultWorkstation() .then(function(ws) { var ws_obj = all.filter(function(w) { return ws == w.name diff --git a/Open-ILS/web/js/ui/default/staff/services/hatch.js b/Open-ILS/web/js/ui/default/staff/services/hatch.js index 5b6f9235d2..c7e2f39485 100644 --- a/Open-ILS/web/js/ui/default/staff/services/hatch.js +++ b/Open-ILS/web/js/ui/default/staff/services/hatch.js @@ -44,36 +44,11 @@ angular.module('egCoreMod') service.serverSettingSummaries = {}; /** - * List string prefixes for On-Call storage keys. On-Call keys - * are those that can be set/get/remove'd from localStorage when - * Hatch is not avaialable, even though Hatch is configured as the - * primary storage location for the key in question. On-Call keys - * are those that allow the user to login and perform basic admin - * tasks (like disabling Hatch) even when Hatch is down. - * AKA Browser Staff Run Level 3. - * Note that no attempt is made to synchronize data between Hatch - * and localStorage for On-Call keys. Only one destation is active - * at a time and each maintains its own data separately. - */ - service.onCallPrefixes = ['eg.workstation']; - - // Returns true if the key can be set/get in localStorage even when - // Hatch is not available. - service.keyIsOnCall = function(key) { - var oncall = false; - angular.forEach(service.onCallPrefixes, function(pfx) { - if (key.match(new RegExp('^' + pfx))) - oncall = true; - }); - return oncall; - } - - /** * Settings with these prefixes will always live in the browser. */ service.browserOnlyPrefixes = [ - 'eg.workstation', - 'eg.hatch', + 'eg.hatch.enable.settings', // deprecated + 'eg.hatch.enable.offline', // deprecated 'eg.cache', 'current_tag_table_marc21_biblio', 'FFPos', @@ -233,24 +208,169 @@ angular.module('egCoreMod') ); } - // TODO: once Hatch is printing-only, should probably store - // this preference on the server. service.usePrinting = function() { - return service.getLocalItem('eg.hatch.enable.printing'); + return service.getItem('eg.hatch.enable.printing'); } + // DEPRECATED service.useSettings = function() { return service.getLocalItem('eg.hatch.enable.settings'); } + // DEPRECATED service.useOffline = function() { return service.getLocalItem('eg.hatch.enable.offline'); } + service.getWorkstations = function() { + if (service.hatchAvailable) { + return service.mergeWorkstations().then( + function() { + service.removeLocalItem('eg.workstation.all'); + return service.getRemoteItem('eg.workstation.all'); + } + ); + } else { + return $q.when(service.getLocalItem('eg.workstation.all')); + } + } + + // See if any workstations are stored in local storage. If so, also + // see if we have any stored in Hatch. If both, merged workstations + // from localStorage in Hatch storage, skipping any whose name + // collide with a workstation in Hatch. If none exist in Hatch, + // copy the localStorage workstations over wholesale. + service.mergeWorkstations = function() { + var existing = service.getLocalItem('eg.workstation.all'); + + if (!existing || existing.length === 0) { + return $q.when(); + } + + return service.getRemoteItem('eg.workstation.all') + .then(function(inHatch) { + + if (!inHatch || inHatch.length === 0) { + // Nothing to merge, copy the data over directly + console.debug('No workstations in hatch to merge'); + return service.setRemoteItem('eg.workstation.all', existing); + } + + var addMe = []; + existing.forEach(function(ws) { + var match = inHatch.filter( + function(w) {return w.name === ws.name})[0]; + if (!match) { + console.log( + 'Migrating workstation from local storage to hatch: ' + + ws.name + ); + addMe.push(ws); + } + }); + inHatch = inHatch.concat(addMe); + return service.setRemoteItem('eg.workstation.all', inHatch); + }); + } + + service.getDefaultWorkstation = function() { + + if (service.hatchAvailable) { + return service.getRemoteItem('eg.workstation.default') + .then(function(name) { + if (name) { + // We have a default in Hatch, remove any lingering + // value from localStorage. + service.removeLocalItem('eg.workstation.default'); + return name; + } + + name = service.getLocalItem('eg.workstation.default'); + if (name) { + console.log('Migrating default workstation to Hatch ' + name); + return service.setRemoteItem('eg.workstation.default', name) + .then(function() {return name;}); + } + + return null; + }); + } else { + return $q.when(service.getLocalItem('eg.workstation.default')); + } + } + + service.setWorkstations = function(workstations, isJson) { + if (service.hatchAvailable) { + return service.setRemoteItem('eg.workstation.all', workstations); + } else { + return $q.when( + service.setLocalItem('eg.workstation.all', workstations, isJson)); + } + } + + service.setDefaultWorkstation = function(name, isJson) { + if (service.hatchAvailable) { + return service.setRemoteItem('eg.workstation.default', name); + } else { + return $q.when( + service.setLocalItem('eg.workstation.default', name, isJson)); + } + } + + service.removeWorkstations = function() { + if (service.hatchAvailable) { + return service.removeRemoteItem('eg.workstation.all'); + } else { + return $q.when( + service.removeLocalItem('eg.workstation.all')); + } + } + + service.removeDefaultWorkstation = function() { + if (service.hatchAvailable) { + return service.removeRemoteItem('eg.workstation.default'); + } else { + return $q.when( + service.removeLocalItem('eg.workstation.default')); + } + } + + + // Workstation actions always use Hatch when it's available + service.getWorkstationItem = function(key) { + if (service.hatchAvailable) { + return service.getRemoteItem(key); + } else { + return $q.when(service.getLocalItem(key)); + } + } + + service.setWorkstationItem = function(key, value) { + if (service.hatchAvailable) { + return service.setRemoteItem(key, value); + } else { + return $q.when(service.setLocalItem(key, value)); + } + } + + service.removeWorkstationItem = function(key) { + if (service.hatchAvailable) { + return service.removeRemoteItem(key); + } else { + return $q.when(service.removeLocalItem(key)); + } + } + + service.keyIsWorkstation = function(key) { + return Boolean(key.match(/eg.workstation/)); + } + // get the value for a stored item service.getItem = function(key) { - console.debug('getting item: ' + key); + if (service.keyIsWorkstation(key)) { + return service.getWorkstationItem(key); + } if (!service.keyStoredInBrowser(key)) { return service.getServerItem(key); @@ -260,14 +380,7 @@ angular.module('egCoreMod') service.getBrowserItem(key).then( function(val) { deferred.resolve(val); }, - function() { // Hatch error - if (service.keyIsOnCall(key)) { - console.warn("Unable to getItem from Hatch: " + key + - ". Retrieving item from local storage instead"); - deferred.resolve(service.getLocalItem(key)); - } - deferred.reject("Unable to getItem from Hatch: " + key); } ); @@ -388,6 +501,10 @@ angular.module('egCoreMod') */ service.setItem = function(key, value) { + if (service.keyIsWorkstation(key)) { + return service.setWorkstationItem(key, value); + } + if (!service.keyStoredInBrowser(key)) { return service.setServerItem(key, value); } @@ -397,13 +514,6 @@ angular.module('egCoreMod') function(val) {deferred.resolve(val);}, function() { // Hatch error - - if (service.keyIsOnCall(key)) { - console.warn("Unable to setItem in Hatch: " + - key + ". Setting in local storage instead"); - - deferred.resolve(service.setLocalItem(key, value)); - } deferred.reject("Unable to setItem in Hatch: " + key); } ); @@ -627,13 +737,6 @@ angular.module('egCoreMod') if (service.hatchAvailable) return service.appendRemoteItem(key, value); - if (service.keyIsOnCall(key)) { - console.warn("Unable to appendItem in Hatch: " + - key + ". Setting in local storage instead"); - - return $q.when(service.appendLocalItem(key, value)); - } - console.error("Unable to appendItem in Hatch: " + key); return $q.reject(); } @@ -686,6 +789,10 @@ angular.module('egCoreMod') // remove a stored item service.removeItem = function(key) { + if (service.keyIsWorkstation(key)) { + return service.removeWorkstationItem(key); + } + if (!service.keyStoredInBrowser(key)) { return service.removeServerItem(key); } @@ -694,14 +801,6 @@ angular.module('egCoreMod') service.removeBrowserItem(key).then( function(response) {deferred.resolve(response);}, function() { // Hatch error - - if (service.keyIsOnCall(key)) { - console.warn("Unable to removeItem from Hatch: " + key + - ". Removing item from local storage instead"); - - deferred.resolve(service.removeLocalItem(key)); - } - deferred.reject("Unable to removeItem from Hatch: " + key); } ); -- 2.11.0