// Only affects *RemoteItem calls.
service.keyCache = {};
+ // Keep a local copy of all retrieved setting summaries, which indicate
+ // which setting types exist for each setting.
+ 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
/**
* Settings with these prefixes will always live in the browser.
*/
- service.browserOnlyPrefixes = ['eg.workstation', 'eg.hatch'];
-
- // For testing (and possibly migration) purposes, hard-code the
- // list of settings that are available to be applied on the server,
- // either via workstation or user settings. Ultimately, the
- // assumption will be that all settings live on the server except
- // those specified by service.browserOnlyPrefixes.
- service.serverSettings = [
- 'eg.circ.checkin.no_precat_alert',
- 'eg.circ.checkin.noop',
- 'eg.circ.checkin.void_overdues',
- 'eg.circ.checkin.auto_print_holds_transits',
- 'eg.circ.checkin.clear_expired',
- 'eg.circ.checkin.retarget_holds',
- 'eg.circ.checkin.retarget_holds_all',
- 'eg.circ.checkin.hold_as_transit',
- 'eg.circ.checkin.manual_float',
- 'circ.checkin.strict_barcode',
- 'eg.circ.patron.summary.collapse',
- 'circ.bills.receiptonpay',
- 'circ.renew.strict_barcode',
- 'cat.holdings_show_copies',
- 'cat.holdings_show_empty',
- 'cat.holdings_show_vols'
+ service.browserOnlyPrefixes = [
+ 'eg.workstation',
+ 'eg.hatch',
+ 'eg.cache',
+ 'current_tag_table_marc21_biblio',
+ 'FFPosTable_REC',
+ 'FFValueTable_REC'
];
- service.keyStoredOnServer = function(key) {
+ service.keyStoredInBrowser = function(key) {
if (service.disableServerSettings) {
- return false;
+ // When server-side storage is disabled, treat every
+ // setting like it's stored locally.
+ return true;
}
var browserOnly = false;
- angular.forEach(service.browserOnlyPrefixes, function(pfx) {
+ service.browserOnlyPrefixes.forEach(function(pfx) {
if (key.match(new RegExp('^' + pfx)))
browserOnly = true;
});
- if (browserOnly) return false;
-
- return service.serverSettings.indexOf(key) > -1
+ return browserOnly;
}
// write a message to the Hatch port
// get the value for a stored item
service.getItem = function(key) {
- if (service.keyStoredOnServer(key))
+ if (!service.keyStoredInBrowser(key)) {
return service.getServerItem(key);
+ }
- if (!service.useSettings())
- return $q.when(service.getLocalItem(key));
+ var deferred = $q.defer();
- if (service.hatchAvailable)
- return service.getRemoteItem(key);
+ service.getBrowserItem(key).then(
+ function(val) { deferred.resolve(val); },
- if (service.keyIsOnCall(key)) {
- console.warn("Unable to getItem from Hatch: " + key +
- ". Retrieving item from local storage instead");
+ 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);
+ }
+ );
+ return deferred.promise;
+ }
+
+ service.getBrowserItem = function(key) {
+ if (service.useSettings()) {
+ if (service.hatchAvailable) {
+ return service.getRemoteItem(key);
+ }
+ } else {
return $q.when(service.getLocalItem(key));
}
-
- console.error("Unable to getItem from Hatch: " + key);
return $q.reject();
}
service.getLocalItem = function(key) {
var val = $window.localStorage.getItem(key);
- if (val == null) return;
+ if (val === null || val === undefined) return;
try {
return JSON.parse(val);
} catch(E) {
*/
service.setItem = function(key, value) {
- if (service.keyStoredOnServer(key))
+ if (!service.keyStoredInBrowser(key)) {
return service.setServerItem(key, value);
+ }
- if (!service.useSettings())
- return $q.when(service.setLocalItem(key, value));
+ var deferred = $q.defer();
+ service.setBrowserItem(key, value).then(
+ function(val) {deferred.resolve(val);},
- if (service.hatchAvailable)
- return service.setRemoteItem(key, value);
+ function() { // Hatch error
- if (service.keyIsOnCall(key)) {
- console.warn("Unable to setItem in Hatch: " +
- key + ". Setting in local storage instead");
+ 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);
+ }
+ );
+ }
+ service.setBrowserItem = function(key, value) {
+ if (service.useSettings()) {
+ if (service.hatchAvailable) {
+ return service.setRemoteItem(key, value);
+ } else {
+ return $q.reject('Unable to get item from hatch');
+ }
+ } else {
return $q.when(service.setLocalItem(key, value));
}
-
- console.error("Unable to setItem in Hatch: " + key);
- return $q.reject();
}
-
service.setServerItem = function(key, value) {
if (!service.auth) service.auth = $injector.get('egAuth');
if (!service.auth.token()) return $q.when();
+
+ // If we have already attempted to retrieve a value for this
+ // setting, then we can tell up front whether applying a value
+ // at the server will be an option. If not, store locally.
+ var summary = service.serverSettingSummaries[key];
+ if (summary &&
+ summary.has_user_setting() === 'f' &&
+ summary.has_workstation_setting() === 'f') {
+
+ console.warn('No server setting type exists for ' + key);
+ service.setLocalItem(key, value);
+ return $q.when();
+ }
+
var settings = {};
settings[key] = value;
+
return egNet.request(
'open-ils.actor',
'open-ils.actor.settings.apply.user_or_ws',
service.auth.token(), settings
- ).then(function(settings) {
- return service.keyCache[key] = value;
+ ).then(function(appliedCount) {
+
+ if (appliedCount === 0) {
+ console.warn('No server setting type exists for ' + key);
+ // We were unable to store the setting on the server,
+ // presumably becuase no server-side setting type exists.
+ // Add to local storage instead.
+ service.setLocalItem(key, value);
+ }
+
+ service.keyCache[key] = value;
+ return appliedCount;
});
}
'open-ils.actor.settings.retrieve.atomic',
[key], service.auth.token()
).then(function(settings) {
- var val = settings[0].value();
- // The server returns null for undefined settings.
- // Treat as undefined for backwards compat.
- service.keyCache[key] = (val === null) ? undefined : val;
- return service.keyCache[key];
+ return service.handleServerItemResponse(settings[0]);
});
}
- service.migrateServerSettings = function(deleteLocal) {
-
- if (!service.auth) service.auth = $injector.get('egAuth');
- if (!service.auth.token()) return $q.reject('no authtoken');
+ service.handleServerItemResponse = function(summary) {
+ var key = summary.name();
+ var val = summary.value();
- var deferred = $q.defer();
- var settings = service.serverSettings.slice(0); // clone
+ summary.value(null); // avoid duplicate value caches
+ service.serverSettingSummaries[key] = summary;
- // Allow get/remove calls to fall back to local options
- // during migration.
- service.disableServerSettings = true;
+ if (val !== null) {
+ // We have a server setting. Nothing left to do.
+ return $q.when(service.keyCache[key] = val);
+ }
- function migrateNext(key) {
+ if (summary.has_user_setting() === 'f' &&
+ summary.has_workstation_setting() === 'f') {
- if (!key) {
- service.disableServerSettings = false;
- return deferred.resolve();
- }
+ console.warn('No server setting type exists for '
+ + key + ', using local value.');
- service.migrateOneServerSetting(key, deleteLocal).then(
- function() {
- deferred.notify('migrated ' + key);
- migrateNext(settings.shift());
- },
- function() {
- service.disableServerSettings = false;
- deferred.reject(
- 'Something failed during settings migration');
- }
- );
+ return service.getBrowserItem(key);
}
- migrateNext(settings.shift());
- return deferred.promise;
- }
+ // A server setting type exists, but no server value exists.
+ // See if we can migrate a local setting to the server.
- service.migrateOneServerSetting = function(key, deleteLocal) {
var deferred = $q.defer();
+ service.getBrowserItem(key).then(function(browserVal) {
- service.getItem(key).then(function(value) {
-
- if (value === undefined || value === null) {
- console.log(key + ' has no value to migrate');
- // Nothing to migrate.
- if (deleteLocal) {
- // for good measure.
- service.removeItem(key);
- }
- return deferred.resolve();
+ if (browserVal === null && browserVal === undefined) {
+ // No local value to migrate.
+ return deferred.resolve(service.keyCache[key] = undefined);
}
- service.setServerItem(key, value).then(
- function() {
- console.debug(
- 'setting ' + key + ' successfully stored on server');
-
- if (!deleteLocal) {
- return deferred.resolve();
+ // Migrate the local value to the server.
+
+ service.setServerItem(key, browserVal).then(
+ function(appliedCount) {
+ if (appliedCount === 1) {
+ console.info('setting ' + key + ' successfully ' +
+ 'migrated to a server setting');
+ service.removeBrowserItem(key); // fire & forget
+ } else {
+ console.error('error migrating setting to server,'
+ + ' falling back to local value');
}
-
- service.removeItem(key).then(function() {
- console.debug(
- 'setting ' + key + ' removed from workstation');
- deferred.resolve();
- });
- },
- function() {
- deferred.reject('applying server setting ' + key);
+ deferred.resolve(service.keyCache[key] = undefined);
}
);
- })
+ });
return deferred.promise;
}
function(setting) {
var val = setting.value();
// The server returns null for undefined settings.
- // Treat as undefined for backwards compat.
+ // Treat as undefined locally for backwards compat.
service.keyCache[setting.name()] =
foundValues[setting.name()] =
(val === null) ? undefined : val;
// If the value is raw, pass it as 'value'. If it was
// externally JSONified, pass it via jsonified.
service.setLocalItem = function(key, value, jsonified) {
- if (jsonified === undefined )
+ if (jsonified === undefined ) {
jsonified = JSON.stringify(value);
+ } else if (value === undefined) {
+ return;
+ }
$window.localStorage.setItem(key, jsonified);
}
// remove a stored item
service.removeItem = function(key) {
- if (service.keyStoredOnServer(key))
+
+ if (!service.keyStoredInBrowser(key)) {
return service.removeServerItem(key);
+ }
- if (!service.useSettings())
- return $q.when(service.removeLocalItem(key));
+ var deferred = $q.defer();
+ service.removeBrowserItem(key).then(
+ function(response) {deferred.resolve(response);},
+ function() { // Hatch error
- if (service.hatchAvailable)
- return service.removeRemoteItem(key);
+ if (service.keyIsOnCall(key)) {
+ console.warn("Unable to removeItem from Hatch: " + key +
+ ". Removing item from local storage instead");
- 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);
+ }
+ );
+
+ return deferred.promise;
+ }
+
+ service.removeBrowserItem = function(key) {
+ if (service.useSettings()) {
+ if (service.hatchAvailable) {
+ return service.removeRemoteItem(key);
+ } else {
+ return $q.reject('error talking to Hatch');
+ }
+ } else {
return $q.when(service.removeLocalItem(key));
}
-
- console.error("Unable to removeItem from Hatch: " + key);
- return $q.reject();
}
service.removeServerItem = function(key) {