LP#1709521 Webstaff show recent patrons
authorBill Erickson <berickxx@gmail.com>
Sat, 12 Aug 2017 15:52:40 +0000 (11:52 -0400)
committerJason Etheridge <jason@EquinoxInitiative.org>
Thu, 31 Aug 2017 03:35:40 +0000 (23:35 -0400)
Adds a new library setting 'ui.staff.max_recent_patrons' which
specifices the number of recently accessed patrons staff may quickly
refetch from the browser client interface.  If no value is set, it
defaults to 1 for backwards compatibility.

If the value is 0 or less, no recent patrons may be retrieved and the
'Retrieve Last Patron' action is hidden.  If the value is > 1 a new
'Retrieve Recent Patrons' menu item appears.  When clicked, the list
of recent patrons is displayed in the patron search interface, most
recently accessed patrons sorted to the top.

For privacy, the recent patrons list expires from the browser when the
authenticion token expires.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Jason Etheridge <jason@EquinoxInitiative.org>
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.data.recent-patrons.sql [new file with mode: 0644]
Open-ILS/src/templates/staff/navbar.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/app.js
Open-ILS/web/js/ui/default/staff/services/navbar.js
Open-ILS/web/js/ui/default/staff/services/patron_search.js
Open-ILS/web/js/ui/default/staff/services/startup.js

index a5e32fe..5505325 100644 (file)
@@ -17161,3 +17161,26 @@ INSERT into config.org_unit_setting_type
         'Define the time zone in which a library physically resides',
         'coust', 'description'),
     'string');
+
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype)
+VALUES (
+    'ui.staff.max_recent_patrons',
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of Retrievable Recent Patrons',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of most recently accessed patrons that can be re-retrieved ' ||
+        'in the staff client.  A value of 0 or less disables the feature',
+        'coust',
+        'description'
+    ),
+    'circ',
+    'integer'
+);
+
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.recent-patrons.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.recent-patrons.sql
new file mode 100644 (file)
index 0000000..3cf897d
--- /dev/null
@@ -0,0 +1,26 @@
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype)
+VALUES (
+    'ui.staff.max_recent_patrons',
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of Retrievable Recent Patrons',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of most recently accessed patrons that can be re-retrieved ' ||
+        'in the staff client.  A value of 0 or less disables the feature',
+        'coust',
+        'description'
+    ),
+    'circ',
+    'integer'
+);
+
+COMMIT;
index 1142bcc..16cd665 100644 (file)
               [% l('Register Patron') %]
             </a>
           </li>
-          <li>
+          <li ng-if="showRecentPatron">
             <a href="./circ/patron/last" target="_self"
               eg-accesskey="[% l('f8') %]" 
               eg-accesskey-desc="[% l('Retrieve Last Patron') %]">
               [% l('Retrieve Last Patron') %]
             </a>
           </li>
+          <li ng-if="showRecentPatrons">
+            <a href="./circ/patron/search?show_recent=1" target="_self"
+              eg-accesskey-desc="[% l('Retrieve Recent Patrons') %]">
+              <span class="glyphicon glyphicon-share-alt"></span>
+              [% l('Retrieve Recent Patrons') %]
+            </a>
+          </li>
           <li>
             <a href="./circ/patron/pending/list" target="_self">
               <span class="glyphicon glyphicon-thumbs-up"></span>
index e942a0c..e7d6430 100644 (file)
@@ -1175,8 +1175,9 @@ function($scope,  $routeParams , $location , egCore , patronSvc) {
        ['$scope','$location','egCore',
 function($scope , $location , egCore) {
 
-    var id = egCore.hatch.getLoginSessionItem('eg.circ.last_patron');
-    if (id) return $location.path('/circ/patron/' + id + '/checkout');
+    var ids = egCore.hatch.getLoginSessionItem('eg.circ.recent_patrons') || [];
+    if (ids.length) 
+        return $location.path('/circ/patron/' + ids[0] + '/checkout');
 
     $scope.no_last = true;
 }])
index 41d5ed8..bae8190 100644 (file)
@@ -109,6 +109,13 @@ angular.module('egCoreMod')
                             $scope.op_changed = egCore.auth.OCtoken() ? true : false;
                             $scope.username = egCore.auth.user().usrname();
                             $scope.workstation = egCore.auth.workstation();
+
+                            egCore.org.settings('ui.staff.max_recent_patrons')
+                            .then(function(s) {
+                                var val = s['ui.staff.max_recent_patrons'];
+                                $scope.showRecentPatron = val > 0;
+                                $scope.showRecentPatrons = val > 1;
+                            });
                         }
                     }
                 );
index ed5c86b..97c9152 100644 (file)
@@ -74,6 +74,60 @@ function($q , $timeout , $location , egCore,  egUser , egConfirmDialog , $locale
         return $q.when();
     }
 
+    service.getRecentPatrons = function() {
+        // avoid getting stuck in a show-recent loop
+        service.showRecent = false;
+
+        if (service.maxRecentPatrons < 1) return $q.when();
+        var patrons = 
+            egCore.hatch.getLoginSessionItem('eg.circ.recent_patrons') || [];
+
+        // Ensure the cached list is no bigger than the current config.
+        // This can happen if the setting changes while logged in.
+        patrons = patrons.slice(0, service.maxRecentPatrons);
+
+        // add home_ou to the list of fleshed fields for recent patrons
+        var fleshFields = egUser.defaultFleshFields.slice(0);
+        fleshFields.push('home_ou');
+
+        var deferred = $q.defer();
+        function getNext() {
+            if (patrons.length == 0) {
+                deferred.resolve();
+                return;
+            }
+            egUser.get(patrons[0], {useFields : fleshFields}).then(
+                function(usr) { // fetch first user
+                    deferred.notify(usr);
+                    patrons.splice(0, 1); // remove first user from list
+                    getNext();
+                }
+            );
+        }
+
+        getNext();
+        return deferred.promise;
+    }
+
+    service.addRecentPatron = function(user_id) {
+        if (service.maxRecentPatrons < 1) return;
+
+        // no need to re-track same user
+        if (service.current && service.current.id() == user_id) return;
+
+        var patrons = 
+            egCore.hatch.getLoginSessionItem('eg.circ.recent_patrons') || [];
+        patrons.splice(0, 0, user_id);  // put this user at front
+        patrons.splice(service.maxRecentPatrons, 1); // remove excess
+
+        // remove any other occurrences of this user, which may have been
+        // added before the most recent user.
+        var idx = patrons.indexOf(user_id, 1);
+        if (idx > 0) patrons.splice(idx, 1);
+
+        egCore.hatch.setLoginSessionItem('eg.circ.recent_patrons', patrons);
+    }
+
     // sets the primary display user, fetching data as necessary.
     service.setPrimary = function(id, user, force) {
         var user_id = id ? id : (user ? user.id() : null);
@@ -82,9 +136,7 @@ function($q , $timeout , $location , egCore,  egUser , egConfirmDialog , $locale
 
         if (!user_id) return $q.reject();
 
-        // when loading a new patron, update the last patron setting
-        if (!service.current || service.current.id() != user_id)
-            egCore.hatch.setLoginSessionItem('eg.circ.last_patron', user_id);
+        service.addRecentPatron(user_id);
 
         // avoid running multiple retrievals for the same patron, which
         // can happen during dbl-click by maintaining a single running
@@ -457,6 +509,22 @@ function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
         selectedItems : function() {return []}
     }
 
+    // Max recents setting is loaded and scrubbed during egStartup.
+    // Copy it to a local variable here for ease of local access.
+    egCore.org.settings('ui.staff.max_recent_patrons').then(function(s) {
+        patronSvc.maxRecentPatrons = s['ui.staff.max_recent_patrons'];
+    });
+
+    // The first time we encounter the show-recent CGI param, put the
+    // service into show-recent mode.  The first time recents are shown,
+    // the service is taken out of show-recent mode so the page does not
+    // get stuck in a show-recent loop.
+    if (patronSvc.showRecent === undefined 
+        && Boolean($location.path().match(/search/))
+        && Boolean($location.search().show_recent)) {
+        patronSvc.showRecent = true;
+    }
+
     // Handle URL-encoded searches
     if ($location.search().search) {
         console.log('URL search = ' + $location.search().search);
@@ -479,7 +547,7 @@ function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
 
     var propagate;
     var propagate_inactive;
-    if (patronSvc.lastSearch) {
+    if (patronSvc.lastSearch && !patronSvc.showRecent) {
         propagate = patronSvc.lastSearch.search;
         // home_ou needs to be treated specially
         propagate.home_ou = {
@@ -525,6 +593,11 @@ function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
     provider.get = function(offset, count) {
         var deferred = $q.defer();
 
+        if (patronSvc.showRecent) {
+            // avoid getting stuck in show-recent mode
+            return patronSvc.getRecentPatrons();
+        }
+
         var fullSearch;
         if (patronSvc.urlSearch) {
             fullSearch = patronSvc.urlSearch;
index 958ff9f..07e1f8c 100644 (file)
@@ -25,14 +25,15 @@ function($q,  $rootScope,  $location,  $window,  egIDL,  egAuth,  egEnv , egOrg
 
     var service = { promise : null }
 
-    // Load date/time format settings on all pages.  Add more .push(...)
-    // calls to add more universal data-loading functions. 
+    // Some org settings affect every page.  Load them during startup.  
+    // Other startup data loaders can be added by appending to egEnv.loaders.
     // egEnv.loaders functions must return a promise.
     egEnv.loaders.push(
         function() {
             return egOrg.settings([
                 'webstaff.format.dates',
                 'webstaff.format.date_and_time',
+                'ui.staff.max_recent_patrons', // affects navbar
                 'lib.timezone'
             ]).then(
                 function(set) {
@@ -40,6 +41,10 @@ function($q,  $rootScope,  $location,  $window,  egIDL,  egAuth,  egEnv , egOrg
                         set['webstaff.format.dates'] || 'shortDate';
                     $rootScope.egDateAndTimeFormat = 
                         set['webstaff.format.date_and_time'] || 'short';
+
+                    // default to 1 for backwards compat.
+                    if (set['ui.staff.max_recent_patrons'] === null)
+                        set['ui.staff.max_recent_patrons'] = 1
                 }
             );
         }