LP#1367926: Add support for (nearly) direct access to the full unapi backend
authorMike Rylander <mrylander@gmail.com>
Wed, 10 Sep 2014 16:22:44 +0000 (12:22 -0400)
committerKathy Lussier <klussier@masslnc.org>
Thu, 18 Feb 2016 15:52:20 +0000 (10:52 -0500)
Some parts of Evergreen (notably the TPAC), and various 3rd party services,
would benefit from full and direct access to the power of the backend (read:
faster, more complete, more API-stable) unAPI (um) API. Related, many moons
ago, I built a perl module (OpenILS::Utils::TagURI) to make parsing of tag
URIs systematic for use in OpenSearch and unAPI contexts. This branch uses
O::U::TagURI and a simple shim inside open-ils.supercat to expose the power
of that backend unAPI functionality.

By way of example, here is the tag URI to look up a copy, by barcode, and
request the call number, bib and bib attributes at the same time.  The
barcode in this example is "ACQ140":

 tag::U2@acp/ACQ140{acn,bre,mra}/-/0/barcode

The full example URL would be something like:

 http://example.com/opac/extras/unapi?id=tag::U2@acp/ACQ140{acn,bre,mra}/-/0/barcode&format=xml

Here is retrieving a bib in MODS 3.2 with holdings embedded:

 tag::U2@bre/267{holdings_xml,acn,acp,mra}

And the URL:

 http://example.com/opac/extras/unapi?tag::U2@bre/267{holdings_xml,acn,acp,mra}&format=mods32

To test:

Try the example URLs, varying record ID, classes, and includes. Some
classes and includes available are:

* bre (bibs)
* acn (volumes)
* acp (copies)
* biblio_record_entry_feed (multiple bibs)
* holdings_xml
* cbs (bib source)
* circ (circulation checkout and due dates)

Signed-off-by: Mike Rylander <mrylander@gmail.com>
Signed-off-by: Galen Charlton <gmc@esilibrary.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Open-ILS/src/perlmods/lib/OpenILS/Application/SuperCat.pm
Open-ILS/src/perlmods/lib/OpenILS/Utils/TagURI.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/SuperCat.pm

index 1d94ef3..26f2372 100644 (file)
@@ -37,6 +37,7 @@ use OpenSRF::Utils::Logger qw($logger);
 use OpenILS::Utils::Fieldmapper;
 
 use OpenILS::Utils::CStoreEditor q/:funcs/;
+use OpenILS::Utils::TagURI;
 
 
 our (
@@ -731,6 +732,60 @@ Returns the XML representation of the requested bibliographic record's holdings
         }
 );
 
+sub u2 {
+    my $self = shift;
+    my $client = shift;
+
+    my $u2 = shift;
+    my $format = shift || 'xml';
+
+    $u2 = OpenILS::Utils::TagURI->new($u2);
+    return '' unless $u2;
+
+    # Use pathinfo on acp as a lookup type specifier.
+    if ($u2->classname eq 'acp' and $u2->pathinfo =~ /\bbarcode\b/) {
+        my( $copy, $evt ) = $U->fetch_copy_by_barcode( $u2->id );
+        $u2->id( $copy->id );
+    }
+
+    return OpenSRF::AppSession->create('open-ils.cstore')->request(
+        "open-ils.cstore.json_query.atomic",
+        { from =>
+            [   'unapi.' . $u2->classname,
+                $u2->id,
+                $format,
+                $u2->classname,
+                '{' . ( $u2->includes ? join( ',', keys %{ $u2->includes } ) : '' ) . '}',
+                $u2->location || undef,
+                $u2->depth || undef
+            ]
+        }
+    )->gather(1)->[0]{'unapi.'. $u2->classname};
+}
+__PACKAGE__->register_method(
+    method    => 'u2',
+    api_name  => 'open-ils.supercat.u2',
+    api_level => 1,
+    argc      => 2,
+    signature =>
+        { desc     => <<"          DESC",
+Returns the XML representation of the requested object
+          DESC
+          params   =>
+            [
+                { name => 'u2',
+                  desc => 'The U2 Tag URI (OpenILS::Utils::TagURI)',
+                  type => 'object' },
+                { name => 'format',
+                  desc => 'For bre and bre feeds, the xml transform format',
+                  type => 'string' }
+            ],
+          'return' =>
+            { desc => 'XML (or transformed) object data',
+              type => 'string' }
+        }
+);
+
 
 sub general_browse {
     my $self = shift;
index a6679f4..7e2adf8 100755 (executable)
@@ -90,8 +90,8 @@ sub parse {
     
         $self->classname($classname);
         $self->id($id);
-        $self->paging(($paging ? [ map { s/^\s*//; s/\s*$//; $_ } split(',', $paging) ] : []));
-        $self->includes(($inc ? { map { /:/ ? split(':') : ($_,undef) } map { s/^\s*//; s/\s*$//; $_ } split(',', $inc) } : {}));
+        $self->paging(($paging ? [ map { s/^\s*//; s/\s*$//; $_ } split(',', $paging) ] : undef));
+        $self->includes(($inc ? { map { /:/ ? split(':') : ($_,undef) } map { s/^\s*//; s/\s*$//; $_ } split(',', $inc) } : undef));
         $self->location($loc);
         $self->depth($depth);
         $self->pathinfo($mods);
@@ -122,7 +122,7 @@ sub toURI {
     $tag .= 'U2@' if ($self->version == 2);
     $tag .= $self->classname . '/' . $self->id;
     $tag .= '['. join(',', @{ $self->paging }) . ']' if defined($self->paging);
-    $tag .= '{'. join(',', map { $_ . ':' . $self->includes->{$_} } keys %{ $self->includes }) . '}' if defined($self->includes);
+    $tag .= '{'. join(',', map { $self->includes->{$_} ? ($_ . ':' . $self->includes->{$_}) : ($_) } keys %{ $self->includes }) . '}' if defined($self->includes);
     $tag .= '/' . $self->location if defined($self->location);
     $tag .= '/' . $self->depth if defined($self->depth);
     $tag .= '/' . $self->pathinfo if defined($self->pathinfo);
index ce5effe..83274ac 100644 (file)
@@ -26,6 +26,7 @@ use OpenILS::Utils::Fieldmapper;
 use OpenILS::WWW::SuperCat::Feed;
 use OpenSRF::Utils::Logger qw/$logger/;
 use OpenILS::Application::AppUtils;
+use OpenILS::Utils::TagURI;
 
 use MARC::Record;
 use MARC::File::XML ( BinaryEncoding => 'UTF-8' );
@@ -444,6 +445,26 @@ sub oisbn {
     return Apache2::Const::OK;
 }
 
+sub unapi2 {
+    my $apache = shift;
+    my $u2 = shift;
+    my $format = shift;
+
+    my $ctype = 'application/xml';
+    # Only bre and biblio_record_entry_feed have tranforms, but we'll ignore that for now
+    if ($u2->classname =~ /^(?:bre|biblio_record_entry_feed)$/ and $format ne 'xml') {
+        # XXX set $ctype to something else
+    }
+
+    print "Content-type: $ctype; charset=utf-8\n\n";
+    print "<?xml version='1.0' encoding='UTF-8' ?>\n";
+    print $supercat
+        ->request("open-ils.supercat.u2", $u2->toURI, $format)
+        ->gather(1);
+
+    return Apache2::Const::OK;
+}
+
 sub unapi {
 
     my $apache = shift;
@@ -465,6 +486,14 @@ sub unapi {
 
 
     my $uri = $cgi->param('id') || '';
+
+    my $format = $cgi->param('format') || '';
+    (my $base_format = $format) =~ s/(-full|-uris)$//o;
+    my $u2uri = OpenILS::Utils::TagURI->new($uri);
+    if ($format and $u2uri->version > 1) {
+        return unapi2($apache, $u2uri, $format);
+    }
+
     my $host = $cgi->virtual_host || $cgi->server_name;
 
     my $skin = $cgi->param('skin') || 'default';
@@ -473,7 +502,6 @@ sub unapi {
     # Enable localized results of copy status, etc
     $supercat->session_locale($locale);
 
-    my $format = $cgi->param('format') || '';
     my $flesh_feed = parse_feed_type($format);
     (my $base_format = $format) =~ s/(-full|-uris)$//o;
     my ($id,$type,$command,$lib,$depth,$paging) = ('','record','');