LP1913811 Items out notice summary API batching
authorBill Erickson <berickxx@gmail.com>
Mon, 1 Feb 2021 15:54:18 +0000 (10:54 -0500)
committerChris Sharp <csharp@georgialibraries.org>
Thu, 4 Feb 2021 16:26:02 +0000 (11:26 -0500)
Tweak the open-ils.actor.user.itemsout.notices API to accept an array of
circulation IDs so the call can be batched from the client.  Similarly
modify the AngJS client to request the notice summaries in batch.

Further improves the notices API by removing an unneeded join and a
minor security fix to verify perms based on the in-database user ID
instead of the ID provided by the caller (w/ the note that the API only
returns numbers, not user data).

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jeff Davis <jdavis@sitka.bclibraries.ca>
Signed-off-by: Chris Sharp <csharp@georgialibraries.org>

Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js

index 5d85c79..bbe57e2 100644 (file)
@@ -3766,17 +3766,50 @@ __PACKAGE__->register_method (
     method      => 'get_itemsout_notices',
     api_name    => 'open-ils.actor.user.itemsout.notices',
     stream      => 1,
-    argc        => 3
+    argc        => 2,
+    signature   => {
+        desc => q/Summary counts of circulat notices/,
+        params => [
+            {desc => 'authtoken', type => 'string'},
+            {desc => 'circulation identifiers', type => 'array of numbers'}
+        ],
+        return => q/Stream of summary objects/
+    }
 );
 
-sub get_itemsout_notices{
-    my( $self, $conn, $auth, $circId, $patronId) = @_;
+sub get_itemsout_notices {
+    my ($self, $client, $auth, $circ_ids) = @_;
 
     my $e = new_editor(authtoken => $auth);
     return $e->event unless $e->checkauth;
 
+    $circ_ids = [$circ_ids] unless ref $circ_ids eq 'ARRAY';
+
+    for my $circ_id (@$circ_ids) {
+        my $resp = get_itemsout_notices_impl($e, $circ_id);
+
+        if ($U->is_event($resp)) {
+            $client->respond($resp);
+            return;
+        }
+
+        $client->respond({circ_id => $circ_id, %$resp});
+    }
+
+    return undef;
+}
+
+
+
+sub get_itemsout_notices_impl {
+    my ($e, $circId) = @_;
+
     my $requestorId = $e->requestor->id;
 
+    my $circ = $e->retrieve_action_circulation($circId) or return $e->event;
+
+    my $patronId = $circ->usr;
+
     if( $patronId ne $requestorId ){
         my $user = $e->retrieve_actor_user($requestorId) or return $e->event;
         return $e->event unless $e->allowed('VIEW_CIRCULATIONS', $user->home_ou);
@@ -3796,15 +3829,20 @@ sub get_itemsout_notices{
     #
 
     my $ctx_loc = $e->requestor->ws_ou;
-    my $exclude_courtesy_notices = $U->ou_ancestor_setting_value($ctx_loc, 'webstaff.circ.itemsout_notice_count_excludes_courtesies');
+    my $exclude_courtesy_notices = $U->ou_ancestor_setting_value(
+        $ctx_loc, 'webstaff.circ.itemsout_notice_count_excludes_courtesies');
+
     my $query = {
            select => { atev => ["complete_time"] },
            from => {
                    atev => {
-                           atevdef => { field => "id",fkey => "event_def", join => { ath => { field => "key", fkey => "hook" }} }
+                           atevdef => { field => "id",fkey => "event_def"}
                    }
            },
-           where => {"+ath" => { key => "checkout.due" },"+atevdef" => { active => 't' },"+atev" => { target => $circId, state => 'complete' }}
+           where => {
+            "+atevdef" => { active => 't', hook => 'checkout.due' },
+            "+atev" => { target => $circId, state => 'complete' }
+        }
     };
 
     if ($exclude_courtesy_notices){
@@ -3825,8 +3863,7 @@ sub get_itemsout_notices{
        }
    }
 
-    $conn->respond(\%resblob);
-    return undef;
+    return \%resblob;
 }
 
 __PACKAGE__->register_method (
index 522a08d..ed0f0f5 100644 (file)
@@ -140,7 +140,7 @@ function($scope , $q , $routeParams , $timeout , egCore , egUser , patronSvc ,
                 // we need an order-by to support paging
                 order_by : {circ : ['xact_start']} 
 
-        }).then(deferred.resolve, null, function(circ) {
+        }).then(null, null, function(circ) {
             circ.circ_lib(egCore.org.get(circ.circ_lib())); // local fleshing
 
             // Translate bib display field JSON blobs to JS.
@@ -160,21 +160,31 @@ function($scope , $q , $routeParams , $timeout , egCore , egUser , patronSvc ,
                 return part.label()
             }).join(',');
 
-           // call open-ils to get overdue notice count and  Last notice date
-           
-           egCore.net.request(
-               'open-ils.actor',
-               'open-ils.actor.user.itemsout.notices',
-               egCore.auth.token(), circ.id(), $scope.patron_id)
-           .then(function(notice){
-               if (notice.numNotices){
-                   circ.action_trigger_event_count = notice.numNotices;
-                   circ.action_trigger_latest_event_date = notice.lastDt;
-              }
-               patronSvc.items_out.push(circ);
-           });
-
-              if (rendered++ >= offset && rendered <= count){ deferred.notify(circ) };
+           patronSvc.items_out.push(circ);
+
+        }).then(function() {
+
+            var circIds = patronSvc.items_out.map(function(circ) { return circ.id() });
+
+            egCore.net.request(
+                'open-ils.actor',
+                'open-ils.actor.user.itemsout.notices',
+                egCore.auth.token(), circIds
+
+            ).then(deferred.resolve, null, function(notice) {
+
+                var circ = patronSvc.items_out.filter(
+                    function(circ) {return circ.id() == notice.circ_id})[0];
+
+                if (notice.numNotices) {
+                    circ.action_trigger_event_count = notice.numNotices;
+                    circ.action_trigger_latest_event_date = notice.lastDt;
+                }
+
+                if (rendered++ >= offset && rendered <= count) {
+                    deferred.notify(circ);
+                };
+            });
         });
 
         return deferred.promise;