From 162d7716bdb2fd3240ac0208122cd3382ec1cf7d Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Thu, 16 May 2013 17:11:15 -0600 Subject: [PATCH] [Signed off] Bug 10320 - Integrate OverDrive search into OPAC This show results from the OverDrive ebook/audiobook service in the OPAC. Added the sysprefs and copied the relevant JS to CCSR. Signed-off-by: Srdjan Signed-off-by: Henry Bankhead --- 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 | 9 + 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 | 47 ++++++ opac/opac-search.pl | 6 + opac/svc/overdrive_proxy | 83 ++++++++++ 17 files changed, 621 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 0000000..91316c0 --- /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 648e161..8db974f 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -6991,6 +6991,21 @@ if ( CheckVersion($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 ba6a6ac..7a0cdcb 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 0000000..1bc8c5d --- /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 84b8489..f990387 100644 --- a/koha-tmpl/opac-tmpl/prog/en/css/opac.css +++ b/koha-tmpl/opac-tmpl/prog/en/css/opac.css @@ -2964,3 +2964,12 @@ padding: 0.1em 0; .thumbnail-shelfbrowser span { margin: 0px auto; } + +#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 0000000..0a04a0b --- /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 0000000..4ba9f8d --- /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 923effa..9b2ea7c 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt @@ -13,6 +13,7 @@ [% IF ( OpacStarRatings == 'all' ) %] [% END %] + [% IF ( OpacHighlightedWords ) %] [% END %]