From 2d0bdc80fda5344cd3ef6613d26676267a82142a Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Thu, 16 May 2013 17:11:15 -0600 Subject: [PATCH] Bug 10320 - Integrate OverDrive search into OPAC Show any relevant results from the OverDrive ebook/audiobook service on the OPAC search. This is done by showing a link with "Found xx results in the library's OverDrive collection" at the top of search results and linking to a page that shows the full results. This requires an OverDrive developer account, and is enabled by setting the OverDriveClientKey and OverDriveClientSecret system preferences. In addition, this patch adds the OverDriveLibraryID system preference. Signed-off-by: Srdjan Signed-off-by: Henry Bankhead Signed-off-by: Chris Cormack Signed-off-by: Owen Leonard Signed-off-by: Katrin Fischer Signed-off-by: Galen Charlton --- C4/External/OverDrive.pm | 141 +++++++++++++++ installer/data/mysql/updatedatabase.pl | 15 ++ .../admin/preferences/enhanced_content.pref | 11 ++ koha-tmpl/opac-tmpl/ccsr/en/js/overdrive.js | 61 +++++++ koha-tmpl/opac-tmpl/prog/en/css/opac.css | 10 ++ koha-tmpl/opac-tmpl/prog/en/js/overdrive.js | 61 +++++++ .../prog/en/modules/opac-overdrive-search.tt | 161 ++++++++++++++++++ .../opac-tmpl/prog/en/modules/opac-results.tt | 28 ++- koha-tmpl/opac-tmpl/prog/images/Star0.gif | Bin 0 -> 1360 bytes koha-tmpl/opac-tmpl/prog/images/Star1.gif | Bin 0 -> 1395 bytes koha-tmpl/opac-tmpl/prog/images/Star2.gif | Bin 0 -> 1410 bytes koha-tmpl/opac-tmpl/prog/images/Star3.gif | Bin 0 -> 1391 bytes koha-tmpl/opac-tmpl/prog/images/Star4.gif | Bin 0 -> 1380 bytes koha-tmpl/opac-tmpl/prog/images/Star5.gif | Bin 0 -> 1284 bytes opac/opac-overdrive-search.pl | 45 +++++ opac/opac-search.pl | 6 + opac/svc/overdrive_proxy | 83 +++++++++ 17 files changed, 620 insertions(+), 2 deletions(-) create mode 100644 C4/External/OverDrive.pm create mode 100644 koha-tmpl/opac-tmpl/ccsr/en/js/overdrive.js create mode 100644 koha-tmpl/opac-tmpl/prog/en/js/overdrive.js create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-overdrive-search.tt create mode 100644 koha-tmpl/opac-tmpl/prog/images/Star0.gif create mode 100644 koha-tmpl/opac-tmpl/prog/images/Star1.gif create mode 100644 koha-tmpl/opac-tmpl/prog/images/Star2.gif create mode 100644 koha-tmpl/opac-tmpl/prog/images/Star3.gif create mode 100644 koha-tmpl/opac-tmpl/prog/images/Star4.gif create mode 100644 koha-tmpl/opac-tmpl/prog/images/Star5.gif create mode 100755 opac/opac-overdrive-search.pl create mode 100755 opac/svc/overdrive_proxy diff --git a/C4/External/OverDrive.pm b/C4/External/OverDrive.pm new file mode 100644 index 0000000000..179ffe2137 --- /dev/null +++ b/C4/External/OverDrive.pm @@ -0,0 +1,141 @@ +package C4::External::OverDrive; + +# Copyright (c) 2013 ByWater +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or ( at your option ) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; + +use JSON; +use Koha::Cache; +use HTTP::Request; +use HTTP::Request::Common; +use LWP::Authen::Basic; +use LWP::UserAgent; + +BEGIN { + require Exporter; + our $VERSION = 3.07.00.049; + our @ISA = qw( Exporter ) ; + our @EXPORT = qw( + IsOverDriveEnabled + GetOverDriveToken + ); +} + +sub _request { + my ( $request ) = @_; + my $ua = LWP::UserAgent->new( "Koha " . C4::Context->KOHAVERSION ); + + my $response; + eval { + $response = $ua->request( $request ) ; + }; + if ( $@ ) { + warn "OverDrive request failed: $@"; + return; + } + + return $response; +} + +=head1 NAME + +C4::External::OverDrive - Retrieve OverDrive content availability information + +=head2 FUNCTIONS + +This module provides content search for OverDrive, + +=over + +=item IsOverDriveEnabled + +Returns 1 if all of the necessary system preferences for OverDrive are set. + +=back + +=cut + +sub IsOverDriveEnabled { + return ( + C4::Context->preference( 'OverDriveClientKey' ) && + C4::Context->preference( 'OverDriveClientSecret' ) + ); +} + +=item GetOverDriveToken + +Fetches an OAuth2 auth token for the OverDrive API, reusing an existing token in +Memcache if possible. + +Returns the token ( as "bearer ..." ) or undef on failure. + +=back + +=cut + +sub GetOverDriveToken { + my $key = C4::Context->preference( 'OverDriveClientKey' ); + my $secret = C4::Context->preference( 'OverDriveClientSecret' ); + + return unless ( $key && $secret ) ; + + my $cache; + + eval { $cache = Koha::Cache->new() }; + + my $token; + $cache and $token = $cache->get_from_cache( "overdrive_token" ) and return $token; + + my $request = HTTP::Request::Common::POST( 'https://oauth.overdrive.com/token', [ + grant_type => 'client_credentials' + ] ) ; + $request->header( Authorization => LWP::Authen::Basic->auth_header( $key, $secret ) ); + + my $response = _request( $request ) or return; + if ( $response->header('Content-Type') !~ m!application/json! ) { + warn "Could not connect to OverDrive: " . $response->message; + return; + } + my $contents = from_json( $response->decoded_content ); + + if ( !$response->is_success ) { + warn "Could not log into OverDrive: " . ( $contents ? $contents->{'error_description'} : $response->decoded_content ); + return; + } + + $token = $contents->{'token_type'} . ' ' . $contents->{'access_token'}; + + # Fudge factor to prevent spurious failures + $cache->set_in_cache( 'overdrive_token', $token, $contents->{'expires_in'} - 5 ); + + return $token; +} + +1; +__END__ + +=head1 NOTES + +=cut + +=head1 AUTHOR + +Jesse Weaver + +=cut diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 0651efce89..700993336a 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -7089,6 +7089,21 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.13.00.XXX"; +if(CheckVersion($DBversion)) { + $dbh->do( +"INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OverDriveClientKey','','Client key for OverDrive integration','30','Free')" + ); + $dbh->do( +"INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OverDriveClientSecret','','Client key for OverDrive integration','30','YesNo')" + ); + $dbh->do( +"INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacDriveLibraryID','','Library ID for OverDrive integration','','Integer')" + ); + print "Upgrade to $DBversion done (Bug 10320 - Show results from library's OverDrive collection in OPAC search)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref index ba6a6acf96..627f095c90 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref @@ -326,3 +326,14 @@ Enhanced Content: yes: Enable no: "Don't enable" - the ability to use Koha Plugins. Note, the plugin system must also be enabled in the Koha configuration file to be fully enabled. + OverDrive: + - + - Include OverDrive availability information with the client key + - pref: OverDriveClientKey + - and client secret + - pref: OverDriveClientSecret + - . + - + - "Show items from the OverDrive catalog of library #" + - pref: OverDriveLibraryID + - . diff --git a/koha-tmpl/opac-tmpl/ccsr/en/js/overdrive.js b/koha-tmpl/opac-tmpl/ccsr/en/js/overdrive.js new file mode 100644 index 0000000000..1bc8c5d4d3 --- /dev/null +++ b/koha-tmpl/opac-tmpl/ccsr/en/js/overdrive.js @@ -0,0 +1,61 @@ +if ( typeof KOHA == "undefined" || !KOHA ) { + var KOHA = {}; +} + +KOHA.OverDrive = ( function() { + var proxy_base_url = '/cgi-bin/koha/svc/overdrive_proxy'; + var library_base_url = 'http://api.overdrive.com/v1/libraries/'; + return { + Get: function( url, params, callback ) { + $.ajax( { + type: 'GET', + url: url.replace( /https?:\/\/api.overdrive.com\/v1/, proxy_base_url ), + dataType: 'json', + data: params, + error: function( xhr, error ) { + try { + callback( JSON.parse( xhr.responseText )); + } catch ( e ) { + callback( {error: xhr.responseText || true} ); + } + }, + success: callback + } ); + }, + GetCollectionURL: function( library_id, callback ) { + if ( KOHA.OverDrive.collection_url ) { + callback( KOHA.OverDrive.collection_url ); + return; + } + + KOHA.OverDrive.Get( + library_base_url + library_id, + {}, + function ( data ) { + if ( data.error ) { + callback( data ); + return; + } + + KOHA.OverDrive.collection_url = data.links.products.href; + + callback( data.links.products.href ); + } + ); + }, + Search: function( library_id, q, limit, offset, callback ) { + KOHA.OverDrive.GetCollectionURL( library_id, function( data ) { + if ( data.error ) { + callback( data ); + return; + } + + KOHA.OverDrive.Get( + data, + {q: q, limit: limit, offset: offset}, + callback + ); + } ); + } + }; +} )(); diff --git a/koha-tmpl/opac-tmpl/prog/en/css/opac.css b/koha-tmpl/opac-tmpl/prog/en/css/opac.css index f8313c0683..be2141aaaf 100644 --- a/koha-tmpl/opac-tmpl/prog/en/css/opac.css +++ b/koha-tmpl/opac-tmpl/prog/en/css/opac.css @@ -3029,6 +3029,7 @@ padding: 0.1em 0; .thumbnail-shelfbrowser span { margin: 0px auto; } +<<<<<<< HEAD .sorting_asc { padding-right: 19px; background: url("../../images/asc.gif") no-repeat scroll right center #EEEEEE; @@ -3048,3 +3049,12 @@ padding: 0.1em 0; padding-right: 19px; background: #EEEEEE none; } + +#overdrive-results { + font-weight: bold; + padding-left: 1em; +} + +.throbber { + vertical-align: middle; +} diff --git a/koha-tmpl/opac-tmpl/prog/en/js/overdrive.js b/koha-tmpl/opac-tmpl/prog/en/js/overdrive.js new file mode 100644 index 0000000000..1bc8c5d4d3 --- /dev/null +++ b/koha-tmpl/opac-tmpl/prog/en/js/overdrive.js @@ -0,0 +1,61 @@ +if ( typeof KOHA == "undefined" || !KOHA ) { + var KOHA = {}; +} + +KOHA.OverDrive = ( function() { + var proxy_base_url = '/cgi-bin/koha/svc/overdrive_proxy'; + var library_base_url = 'http://api.overdrive.com/v1/libraries/'; + return { + Get: function( url, params, callback ) { + $.ajax( { + type: 'GET', + url: url.replace( /https?:\/\/api.overdrive.com\/v1/, proxy_base_url ), + dataType: 'json', + data: params, + error: function( xhr, error ) { + try { + callback( JSON.parse( xhr.responseText )); + } catch ( e ) { + callback( {error: xhr.responseText || true} ); + } + }, + success: callback + } ); + }, + GetCollectionURL: function( library_id, callback ) { + if ( KOHA.OverDrive.collection_url ) { + callback( KOHA.OverDrive.collection_url ); + return; + } + + KOHA.OverDrive.Get( + library_base_url + library_id, + {}, + function ( data ) { + if ( data.error ) { + callback( data ); + return; + } + + KOHA.OverDrive.collection_url = data.links.products.href; + + callback( data.links.products.href ); + } + ); + }, + Search: function( library_id, q, limit, offset, callback ) { + KOHA.OverDrive.GetCollectionURL( library_id, function( data ) { + if ( data.error ) { + callback( data ); + return; + } + + KOHA.OverDrive.Get( + data, + {q: q, limit: limit, offset: offset}, + callback + ); + } ); + } + }; +} )(); diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-overdrive-search.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-overdrive-search.tt new file mode 100644 index 0000000000..4ba9f8d15e --- /dev/null +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-overdrive-search.tt @@ -0,0 +1,161 @@ +[% INCLUDE 'doc-head-open.inc' %] +[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › OverDrive search for '[% q | html %]' +[% INCLUDE 'doc-head-close.inc' %] + + + + + +[% IF ( OpacNav ) %] +
+[% ELSE %] +
+[% END %] +
+[% INCLUDE 'masthead.inc' %] + +

OverDrive search for '[% q | html %]'

+ + +
+
+
+
+
+ + + +
+
+
+
+
+
+ +[% IF ( OpacNav ) %] +
+[% INCLUDE 'navigation.inc' %] +
+[% END %] + + +
+[% INCLUDE 'opac-bottom.inc' %] diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt index b4bd6c3db6..551a5151ba 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt @@ -16,6 +16,7 @@ [% END %] + [% IF ( OpacHighlightedWords ) %] [% END %]