From 83e18205e2e1d0123174b17029401a1481405060 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Tue, 26 Nov 2019 16:12:37 -0800 Subject: [PATCH] LP#1848550: client-side caching of org settings for AngularJS The web client almost always does live lookups any time it needs to check an org setting. But these settings rarely change, so it would make sense to cache them. They're already cached using Lovefield in order to support offline; this commit checks the cache first, and only does a live lookup if the setting is uncached. The settings cache is cleared on login to ensure stale values don't stick around forever. To refresh the cache, simply logout and then login; cached values will be deleted and the latest values will be retrieved from the server when they are needed. Signed-off-by: Jeff Davis Signed-off-by: Bill Erickson Signed-off-by: Chris Sharp --- .../web/js/ui/default/staff/services/auth.js | 10 ++- .../js/ui/default/staff/services/lovefield.js | 9 +++ .../web/js/ui/default/staff/services/org.js | 72 +++++++++++++++---- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/Open-ILS/web/js/ui/default/staff/services/auth.js b/Open-ILS/web/js/ui/default/staff/services/auth.js index 03e5d43534..50818e5b34 100644 --- a/Open-ILS/web/js/ui/default/staff/services/auth.js +++ b/Open-ILS/web/js/ui/default/staff/services/auth.js @@ -6,8 +6,10 @@ angular.module('egCoreMod') .factory('egAuth', - ['$q','$timeout','$rootScope','$window','$location','egNet','egHatch', -function($q , $timeout , $rootScope , $window , $location , egNet , egHatch) { + ['$q','$timeout','$rootScope','$window','$location','egNet','egHatch','$injector', +function($q , $timeout , $rootScope , $window , $location , egNet , egHatch , $injector) { + + var egLovefield = null; var service = { // the currently active user (au) object @@ -288,9 +290,13 @@ function($q , $timeout , $rootScope , $window , $location , egNet , egHatch) { } service.handle_login_ok = function(args, evt) { + if (!egLovefield) { + egLovefield = $injector.get('egLovefield'); + } service.ws = args.workstation; egHatch.setLoginSessionItem('eg.auth.token', evt.payload.authtoken); egHatch.setLoginSessionItem('eg.auth.time', evt.payload.authtime); + egLovefield.destroySettingsCache(); // force refresh of settings cache on login (LP#1848550) service.poll(); } diff --git a/Open-ILS/web/js/ui/default/staff/services/lovefield.js b/Open-ILS/web/js/ui/default/staff/services/lovefield.js index e7ec4960c8..683390aafd 100644 --- a/Open-ILS/web/js/ui/default/staff/services/lovefield.js +++ b/Open-ILS/web/js/ui/default/staff/services/lovefield.js @@ -335,6 +335,15 @@ angular.module('egCoreMod') ); } + service.destroySettingsCache = function () { + if (lf.isOffline || service.cannotConnect) return $q.when(); + return service.request({ + schema: 'cache', + table: 'Setting', + action: 'deleteAll' + }); + } + service.setListInOfflineCache = function (type, list) { if (lf.isOffline || service.cannotConnect) return $q.when(); diff --git a/Open-ILS/web/js/ui/default/staff/services/org.js b/Open-ILS/web/js/ui/default/staff/services/org.js index 36c9ed2e6b..99657d162d 100644 --- a/Open-ILS/web/js/ui/default/staff/services/org.js +++ b/Open-ILS/web/js/ui/default/staff/services/org.js @@ -111,6 +111,9 @@ function($q, egEnv, egAuth, egNet , $injector) { if (!angular.isArray(names)) names = [names]; if (lf.isOffline) { + // for offline, just use whatever we have managed to cache, + // even if the value is expired (since we can't refresh it + // from the server) return egLovefield.getSettingsCache(names).then( function(settings) { var hash = {}; @@ -126,26 +129,71 @@ function($q, egEnv, egAuth, egNet , $injector) { if (!egAuth.user()) return $q.when(); - var deferred = $q.defer(); ou_id = ou_id || egAuth.user().ws_ou(); - var here = (ou_id == egAuth.user().ws_ou()); + if (ou_id != egAuth.user().ws_ou()) { + // we only cache settings for the current working location; + // if we have requested settings for some other org unit, + // skip the cache and pull settings directly from the server + return service.settingsFromServer(names, ou_id); + } + + var deferred = $q.defer(); + + var newNames = []; + angular.forEach(names, function(name) { + if (!angular.isDefined(service.cachedSettings[name])) + // we don't have a value for this setting yet + newNames.push(name) + }); - - if (here) { - // only cache org settings retrieved for the current - // workstation org unit. - var newNames = []; + // only retrieve uncached values + names = newNames; + if (names.length == 0) + return $q.when(service.cachedSettings); + + // get settings from offline cache where possible; + // otherwise, get settings from server + egLovefield.getSettingsCache(names) + .then(function(settings) { + + // populate values from offline cache + angular.forEach(settings, function (s) { + service.cachedSettings[s.name] = s.value; + }); + + // check if any requested settings were not in offline cache + var uncached = []; angular.forEach(names, function(name) { if (!angular.isDefined(service.cachedSettings[name])) - newNames.push(name) + uncached.push(name); }); - // only retrieve uncached values - names = newNames; - if (names.length == 0) - return $q.when(service.cachedSettings); + if (uncached.length == 0) { + // all requested settings were in the offline cache already + deferred.resolve(service.cachedSettings); + } else { + // cache was missing some settings; grab those from the server + service.settingsFromServer(uncached, ou_id) + .then(function() { + deferred.resolve(service.cachedSettings); + }); + } + }); + return deferred.promise; + } + + service.settingsFromServer = function(names, ou_id) { + if (!egLovefield) { + egLovefield = $injector.get('egLovefield'); } + // allow non-array + if (!angular.isArray(names)) names = [names]; + + var deferred = $q.defer(); + ou_id = ou_id || egAuth.user().ws_ou(); + var here = (ou_id == egAuth.user().ws_ou()); + egNet.request( 'open-ils.actor', 'open-ils.actor.ou_setting.ancestor_default.batch', -- 2.43.2