From c9b78ab130e15391f8c144a7dd1f82014ace4d57 Mon Sep 17 00:00:00 2001 From: Jakub Kotrla Date: Fri, 10 Feb 2017 12:52:03 +0100 Subject: [PATCH] LP#1624366 Evergreen integration with obalkyknih.cz (Czech AC provider) AddedContent Perl plugin to display book covers from Czech provider obalkyknih.cz. Also can display summary, table of content and user reviews. Conflicts: Open-ILS/src/templates/opac/parts/record/summary.tt2 Signed-off-by: Jakub Kotrla Signed-off-by: Jason Stephenson --- Open-ILS/examples/opensrf.xml.example | 18 ++ .../OpenILS/WWW/AddedContent/ObalkyKnih.pm | 292 ++++++++++++++++++ Open-ILS/src/templates/opac/parts/config.tt2 | 8 + .../templates/opac/parts/record/summary.tt2 | 96 +++--- 4 files changed, 370 insertions(+), 44 deletions(-) create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/WWW/AddedContent/ObalkyKnih.pm diff --git a/Open-ILS/examples/opensrf.xml.example b/Open-ILS/examples/opensrf.xml.example index 167611a058..9205229ab3 100644 --- a/Open-ILS/examples/opensrf.xml.example +++ b/Open-ILS/examples/opensrf.xml.example @@ -294,6 +294,24 @@ vim:et:ts=4:sw=4: isbn,upc + + + + + + false + + + true + false + + + true + + + +# +# true +# +# true +# true +# +# true +# + +my $AC = 'OpenILS::WWW::AddedContent'; + +# This should work for most setups +my $blank_img = 'http://localhost/opac/images/blank.png'; + +# This URL is always the same for obalkyknih.cz, so there's no advantage to +# pulling from opensrf.xml +my $api_url = 'http://cache.obalkyknih.cz/api/'; + + +sub new { + my( $class, $args ) = @_; + $class = ref $class || $class; + return bless($args, $class); +} + + +# -------------------------------------------------------------------------- +sub expects_keyhash { + # we expect a keyhash as opposed to a simple scalar containing an ISBN + return 1; +} + +# -------------------------------------------------------------------------- +sub jacket_small { + my( $self, $keys ) = @_; + return $self->send_img( + $self->fetch_cover_response('cover_icon_url', $keys)); +} + +sub jacket_medium { + my( $self, $keys ) = @_; + return $self->send_img( + $self->fetch_cover_response('cover_medium_url', $keys)); + +} +sub jacket_large { + my( $self, $keys ) = @_; + return $self->send_img( + $self->fetch_cover_response('cover_preview510_url', $keys)); +} + +# -------------------------------------------------------------------------- + + +# annotations provided by obalkyknih.cz is mapped to evergreen summary +sub summary_html { + my( $self, $keys ) = @_; + my $key = $self->select_key($keys); + + if ($self->{ObalkyKnih}->{summary} eq "false") { return 0; } + + my $book_data = $self->fetch_response_obalky($key); + my $annotation = $book_data->{'annotation'}; + + if (!$annotation) { + $logger->debug("ObalkyKnih.cz no summary for $key"); + return 0; + } + + my $annot_source = $annotation->{'source'}; + my $annot_text = $annotation->{'html'}; + + my $annot_html .= "
$annot_text
\n"; + + $self->send_html($annot_html); +} + + +# obalkyknih.cz provides TOC as text and as PDF plus thumbnail +sub toc_html { + my( $self, $keys ) = @_; + my $key = $self->select_key($keys); + + if ($self->{ObalkyKnih}->{tocPdf} eq "false" && $self->{ObalkyKnih}->{tocText} eq "false") { return 0; } + + my $book_data = $self->fetch_response_obalky($key); + + my $toc_text = $book_data->{toc_full_text}; + my $toc_pdf_url = $book_data->{toc_pdf_url}; + my $toc_thumbnail_url = $book_data->{toc_thumbnail_url}; + + my $toc_html; + if ($self->{ObalkyKnih}->{tocPdf} ne "false" && $toc_pdf_url && $toc_thumbnail_url) { + $toc_html .= "
"; + $toc_html .= "TOC $key"; + $toc_html .= "
"; + } + if ($self->{ObalkyKnih}->{tocText} ne "false" && $toc_text) { + $toc_html .= "
$toc_text
"; + } + + my $toc_html_length = length $toc_html; + + # No table of contents is available for this book; short-circuit + if ($toc_html_length < 1) { + $logger->debug("ObalkyKnih.cz no TOC for $key"); + return 0; + } + + $self->send_html($toc_html); +} + +# user reviews from obalkyknih.cz +sub reviews_html { + my( $self, $keys ) = @_; + my $key = $self->select_key($keys); + + if ($self->{ObalkyKnih}->{reviews} eq "false") { return 0; } + + my $book_data = $self->fetch_response_obalky($key); + my $reviews = $book_data->{'reviews'}; + + if (!$reviews) { + $logger->debug("ObalkyKnih.cz no reviews for $key"); + return 0; + } + + my $reviews_html = ""; + foreach my $review (@$reviews) { + my $created = $review->{created}; + my $html_text = $review->{html_text}; + my $library_name = $review->{library_name}; + + my @createdParsed = gmtime(str2time($created)); + $created = POSIX::strftime("%-d. %-m. %Y\n", @createdParsed); + + $reviews_html .= "
" . + "
$html_text
" . + "
Zdroj: $library_name, $created
" . + "
\n"; + } + + my $rating_count = $book_data->{'rating_count'}; + my $rating_avg100 = $book_data->{'rating_avg100'}; + my $rating_url = $book_data->{'rating_url'}; + + my $rating_html = ""; + if ($rating_count > 0) { + $rating_html = " $rating_avg100 %

Hodnoceno: ${rating_count}x"; + } + + my $rr_html_length = length($reviews_html . $rating_html); + if ($rr_html_length < 1) { + $logger->debug("ObalkyKnih.cz no reviews for $key"); + return 0; + } + + $self->send_html("$rating_html
$reviews_html
"); +} + +# -------------------------------------------------------------------------- + +sub send_img { + my($self, $response) = @_; + return { + content_type => $response->header('Content-type'), + content => $response->content, + binary => 1 + }; +} + +sub send_html { + my( $self, $content ) = @_; + return 0 unless $content; + + # evergreen has encoding issues, so change non-ASCII chars to HTML entity + $content = encode_entities($content, '^\x00-\x7F'); + + return { content_type => 'text/html; charset=utf-8', content => $content }; +} + +# -------------------------------------------------------------------------- + +# returns the HTTP response object from the URL fetch +sub fetch_response_obalky { + my( $self, $key ) = @_; + + # obalkyknih.cz can also accept nbn, oclc + # Hardcoded to only accept ISBNs in format API_URL/books?isbn=9788086964096 + $key = "books?isbn=$key"; + + my $url = $api_url . $key; + my $response = $AC->get_url($url)->decoded_content((charset => 'UTF-8')); + + $logger->debug("ObalkyKnih.cz for $key response was $response"); + + my $book_results = OpenSRF::Utils::JSON->JSON2perl($response); + my $record = $book_results->[0]; + + # We didn't find a matching book; short-circuit our response + if (!$record) { + $logger->debug("ObalkyKnih.cz for $key no record found"); + return 0; + } + + return $record; +} + + +# returns a cover image from the list of associated items +sub fetch_cover_response { + my( $self, $size, $keys ) = @_; + + my $key = $self->select_key($keys); + my $response = $self->fetch_response_obalky($key); + + # Short-circuit if we get an empty response, or a response + # with no matching records + if (!$response or scalar(keys %$response) == 0) { + $logger->debug("ObalkyKnih.cz for $key no cover url for this book"); + return $AC->get_url($blank_img); + } + + # Try to return a cover image from the record->data metadata + my $cover = $response->{$size}; + + if ($cover) { + return $AC->get_url($cover); + } + + $logger->debug("ObalkyKnih.cz for $key no covers for this book"); + + # Return a blank image + return $AC->get_url($blank_img); +} + + +# return key, i.e. nvl(ISBN, ISSN) +sub select_key { + my ($self, $keys) = @_; + + my $isbn = $keys->{isbn}[0]; + # not used now : my $upc = $keys->{upc}[0]; + my $issn = $keys->{issn}[0]; + + my $key; + if (defined($isbn)) { + $key = $isbn; + } + if (defined($issn)) { + $key = $issn; + } + + return $key; +} + + +1; diff --git a/Open-ILS/src/templates/opac/parts/config.tt2 b/Open-ILS/src/templates/opac/parts/config.tt2 index 3585ba7d96..e32949cd52 100644 --- a/Open-ILS/src/templates/opac/parts/config.tt2 +++ b/Open-ILS/src/templates/opac/parts/config.tt2 @@ -218,4 +218,12 @@ ctx.exclude_electronic_checkbox = 0; # TIME_FORMAT = '%H:%M'; # for 16:32 (24 hour) format ############################################################################## +############################################################################## +# Obalkyknih.cz support +############################################################################## +# Obalkyknihy.cz is free Czech service providing added content and book covers +# Set to 'true' to enable +############################################################################## +# obalkyknih_cz.enabled = 'true'; + %] diff --git a/Open-ILS/src/templates/opac/parts/record/summary.tt2 b/Open-ILS/src/templates/opac/parts/record/summary.tt2 index 0917f003aa..a993be7e0a 100644 --- a/Open-ILS/src/templates/opac/parts/record/summary.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/summary.tt2 @@ -1,3 +1,4 @@ + [% PROCESS "opac/parts/misc_util.tt2"; USE ResolverResolver; ctx.page_title = attrs.title | html @@ -26,14 +27,33 @@ [%- INCLUDE "opac/parts/record/authors.tt2" %]
- [% l('Image of item') %] + [%- IF obalkyknih_cz.enabled == 'true' %] + [%- + isbnissn = ''; + IF attrs.isbns.0; + isbnissn = attrs.isbns.0; + IF (matches = isbnissn.match('^(.+?)(\s.+)$')); + isbnissn = matches.0; + END; + END; + IF attrs.issns.0; + isbnissn=attrs.issns.0; + END; + %] + + [% l('Image of item') %] +
+ [% ELSE %] + [% l('Image of item') %] + + [%- END %]
- - [%- IF attrs.format_label %] [% FOR format IN attrs.all_formats %] [%- search_ou = ctx.search_ou; IF ctx.place_unfillable || @@ -59,44 +78,33 @@
[%- END -%]
- [% IF ctx.user; - INCLUDE "opac/parts/bookbag_actions.tt2"; - %] - [% ELSE; - operation = ctx.mylist.grep(ctx.bre_id).size ? "delete" : "add"; - label = (operation == "add") ? l("Add to my list") : l("Remove from my list"); - %] - - - [% label %] - - [% END %] -
-
- [% IF ctx.mylist.size %] - [%- IF ctx.user; %] - [% l('View My Lists') %][% l(' View My Lists') %] - [%- ELSE %] - [% l('View My Temporary List') %][% l(' View My Temporary List') %] - [%- END %] - [% END %] -
- - [%- IF ctx.refworks.enabled == 'true' %] - [%- INCLUDE 'opac/parts/record/refworks.tt2' %] - [%- END %] - [% IF !ctx.is_staff %] - - [% END %] + [% IF ctx.user; + INCLUDE "opac/parts/bookbag_actions.tt2"; + %] + [% ELSE; + operation = ctx.mylist.grep(ctx.bre_id).size ? "delete" : "add"; + label = (operation == "add") ? l("Add to my list") : l("Remove from my list"); + %] + + + [% label %] + + [% END %] + + + [%- IF ctx.refworks.enabled == 'true' %] + [%- INCLUDE 'opac/parts/record/refworks.tt2' %] + [%- END %] + [%- IF ctx.is_staff %]