Bug 10320 - Integrate OverDrive search into OPAC
authorJesse Weaver <pianohacker@gmail.com>
Thu, 16 May 2013 23:11:15 +0000 (17:11 -0600)
committerGalen Charlton <gmc@esilibrary.com>
Sun, 8 Sep 2013 07:00:40 +0000 (07:00 +0000)
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 <srdjan@catalyst.net.nz>
Signed-off-by: Henry Bankhead <hbankhead@losgatosca.gov>
Signed-off-by: Chris Cormack <chris@bigballofwax.co.nz>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Katrin Fischer <Katrin.Fischer.83@web.de>
Signed-off-by: Galen Charlton <gmc@esilibrary.com>
17 files changed:
C4/External/OverDrive.pm [new file with mode: 0644]
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref
koha-tmpl/opac-tmpl/ccsr/en/js/overdrive.js [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/css/opac.css
koha-tmpl/opac-tmpl/prog/en/js/overdrive.js [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-overdrive-search.tt [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt
koha-tmpl/opac-tmpl/prog/images/Star0.gif [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/images/Star1.gif [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/images/Star2.gif [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/images/Star3.gif [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/images/Star4.gif [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/images/Star5.gif [new file with mode: 0644]
opac/opac-overdrive-search.pl [new file with mode: 0755]
opac/opac-search.pl
opac/svc/overdrive_proxy [new file with mode: 0755]

diff --git a/C4/External/OverDrive.pm b/C4/External/OverDrive.pm
new file mode 100644 (file)
index 0000000..179ffe2
--- /dev/null
@@ -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 <pianohacker@gmail.com>
+
+=cut
index 0651efc..7009933 100755 (executable)
@@ -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)
index ba6a6ac..627f095 100644 (file)
@@ -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 (file)
index 0000000..1bc8c5d
--- /dev/null
@@ -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
+                );
+            } );
+        }
+    };
+} )();
index f8313c0..be2141a 100644 (file)
@@ -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 (file)
index 0000000..1bc8c5d
--- /dev/null
@@ -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 (file)
index 0000000..4ba9f8d
--- /dev/null
@@ -0,0 +1,161 @@
+[% INCLUDE 'doc-head-open.inc' %]
+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog &rsaquo; OverDrive search for '[% q | html %]'
+[% INCLUDE 'doc-head-close.inc' %]
+<script type="text/javascript" src="[% themelang %]/js/overdrive.js"></script>
+<script type="text/javascript">
+var querystring = "[% q |replace( "'", "\'" ) |replace( '\n', '\\n' ) |replace( '\r', '\\r' ) |html %]";
+var results_per_page = [% OPACnumSearchResults %];
+
+function fetch_availability( prod, $tr ) {
+    var $availability_summary = $( '<span class="results_summary"></span>' );
+    $tr.find( '.info' ).append( $availability_summary );
+    $availability_summary.html( '<span class="label">Availability: </span> Loading...' );
+
+    KOHA.OverDrive.Get(
+        prod.links.availability.href,
+        {},
+        function ( data ) {
+            if ( data.error ) return;
+
+            $availability_summary.html( '<span class="label">Copies available: </span><span class="available"><strong>' +  data.copiesAvailable + '</strong> out of ' + data.copiesOwned + '</span>' );
+
+            if ( data.numberOfHolds ) {
+                $availability_summary.find( '.available' ).append( ', waiting holds: <strong>' + data.numberOfHolds + '</strong>' );
+            }
+
+            $tr.find( '.info' ).append( '<span class="results_summary actions"><span class="label">Actions: </span><a href="http://' + prod.contentDetails[0].href + '" ' + ( data.copiesAvailable ? ' class="addtocart">Check out' : ' class="hold">Place hold' ) + '</a></span>' );
+        }
+    );
+}
+
+function search( offset ) {
+    $( '#overdrive-status' ).html( 'Searching OverDrive... <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' );
+
+    KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, results_per_page, offset, function( data ) {
+        if ( data.error ) {
+            $( '#overdrive-status' ).html( '<strong class="unavailable">Error searching OverDrive collection.</strong>' );
+            return;
+        }
+
+        if ( !data.totalItems ) {
+            $( '#overdrive-status' ).html( '<strong>No results found in the library\'s OverDrive collection.</strong>' );
+            return;
+        }
+
+        $( '#results tbody' ).empty();
+
+        $( '#overdrive-status' ).html( '<strong>Found ' + data.totalItems + ' results in the library\'s OverDrive collection.</strong>' );
+
+        for ( var i = 0; data.products[i]; i++ ) {
+            var prod = data.products[i];
+            var results = [];
+
+            results.push( '<tr>' );
+
+            results.push( '<td class="info"><a class="title" href="http://', prod.contentDetails[0].href, '">' );
+            results.push( prod.title );
+            if ( prod.subtitle ) results.push( ', ', prod.subtitle );
+            results.push( '</a>' );
+            results.push( '<p>by ', prod.primaryCreator.name, '</p>' );
+            results.push( '<span class="results_summary"><span class="label">Type: </span>', prod.mediaType, '</span>' );
+            if ( prod.starRating ) results.push( '<span class="results_summary"><span class="label">Average rating: <img src="[% themelang %]/../images/Star', Math.round( parseInt( prod.starRating )), '.gif" title="" style="max-height: 15px; vertical-align: bottom"/></span>' );
+            results.push( '</td>' );
+
+            results.push( '<td>' );
+            if ( prod.images.thumbnail ) {
+                results.push( '<a href="http://', prod.contentDetails[0].href, '">' );
+                results.push( '<img class="thumbnail" src="', prod.images.thumbnail.href, '" />' );
+                results.push( '</a>' );
+            }
+            results.push( '</td>' );
+
+            results.push( '</tr>' );
+            var $tr = $( results.join( '' ));
+            $( '#results tbody' ).append( $tr );
+
+            fetch_availability( prod, $tr );
+        }
+
+        $( '#results tr:odd' ).addClass( 'highlight' );
+
+        var pages = [];
+        var cur_page = offset / results_per_page;
+        var max_page = Math.floor( data.totalItems / results_per_page );
+
+        if ( cur_page != 0 ) {
+            pages.push( '<a class="nav" href="#" data-offset="' + (offset - results_per_page) + '">&lt;&lt; Previous</a>' );
+        }
+
+        for ( var page = Math.max( 0, cur_page - 9 ); page <= Math.min( max_page, cur_page + 9 ); page++ ) {
+            if ( page == cur_page ) {
+                pages.push( ' <span class="current">' + ( page + 1 ) + '</span>' );
+            } else {
+                pages.push( ' <a class="nav" href="#" data-offset="' + ( page * results_per_page ) + '">' + ( page + 1 ) + '</a>' );
+            }
+        }
+
+        if ( cur_page < max_page ) {
+            pages.push( ' <a class="nav" href="#" data-offset="' + (offset + results_per_page) + '">Next >></a>' );
+        }
+
+        if ( pages.length > 1 ) $( '#top-pages, #bottom-pages' ).find( '.pages' ).html( pages.join( '' ) );
+    } );
+}
+
+$( document ).ready( function() {
+    $( '#breadcrumbs p' )
+        .append( ' ' )
+        .append( '<span id="overdrive-status"></span>' );
+
+    $( document ).on( 'click', 'a.nav', function() {
+        search( $( this ).data( 'offset' ) );
+        return false;
+    });
+
+    search( 0 );
+} );
+</script>
+<style>
+.actions a.addtocart {
+    display: inline;
+}
+</style>
+</head>
+<body>
+[% IF ( OpacNav ) %]
+<div id="doc3" class="yui-t1">
+[% ELSE %]
+<div id="doc3" class="yui-t7">
+[% END %]
+   <div id="bd">
+[% INCLUDE 'masthead.inc' %]
+
+       <h1>OverDrive search for '[% q | html %]'</h1>
+    <div id="breadcrumbs">
+        <p></p>
+    </div>
+
+       <div id="yui-main"><div class="yui-b searchresults">
+        <div id="top-pages">
+            <div class="pages">
+            </div>
+        </div>
+        <table id="results">
+            <tbody>
+            </tbody>
+        </table>
+        <div id="bottom-pages">
+            <div class="pages">
+            </div>
+        </div>
+     </div></div>
+
+[% IF ( OpacNav ) %]
+<div class="yui-b"><div id="opacnav" class="container">
+[% INCLUDE 'navigation.inc' %]
+</div></div>
+[% END %]
+
+
+</div>
+[% INCLUDE 'opac-bottom.inc' %]
index b4bd6c3..551a515 100644 (file)
@@ -16,6 +16,7 @@
   <link rel="stylesheet" type="text/css" href="[% themelang %]/css/jquery.rating.css" />
 [% END %]
 
+<script type="text/javascript" src="[% themelang %]/js/overdrive.js"></script>
 <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
 [% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.highlight-3.js"></script>
 [% END %]<script type="text/javascript">
@@ -251,7 +252,10 @@ $(document).ready(function(){
 [% END %]
     $("#holdDetails").hide();
 
-[% IF ( query_desc ) %][% IF ( OpacHighlightedWords ) %]var query_desc = "[% query_desc |replace("'", "\'") |replace('\n', '\\n') |replace('\r', '\\r') |html %]";
+[% IF ( query_desc ) %]
+    var query_desc = "[% query_desc |replace("'", "\'") |replace('\n', '\\n') |replace('\r', '\\r') |html %]";
+    var querystring = "[% querystring |replace("'", "\'") |replace('\n', '\\n') |replace('\r', '\\r') |html %]";
+    [% IF ( OpacHighlightedWords ) %]
         q_array = query_desc.split(" ");
         // ensure that we don't have "" at the end of the array, which can
         // break the highlighter
@@ -260,7 +264,27 @@ $(document).ready(function(){
         }
         highlightOn();
         $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;});
-        $("#highlight_toggle_off").show().click(function() {highlightOff();});[% END %][% END %]
+        $("#highlight_toggle_off").show().click(function() {highlightOff();});
+    [% END %]
+    [% IF ( OverDriveEnabled ) %]
+        var $overdrive_results = $( '<span id="overdrive-results">Searching OverDrive... <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' );
+        $( '#breadcrumbs p' ).eq(0)
+            .append( ' ' )
+            .append( $overdrive_results );
+        KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) {
+            if ( data.error ) {
+                $overdrive_results.html( 'Error searching OverDrive collection' );
+                return;
+            }
+
+            if ( data.totalItems ) {
+                $overdrive_results.html( 'Found <a href="/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) + '">' + data.totalItems + ' results</a> in OverDrive collection' );
+            } else {
+                $overdrive_results.remove();
+            }
+        } );
+    [% END %]
+[% END %]
 
 [% IF ( TagsInputEnabled && loggedinusername ) %]
             $("#tagsel_tag").click(function(){
diff --git a/koha-tmpl/opac-tmpl/prog/images/Star0.gif b/koha-tmpl/opac-tmpl/prog/images/Star0.gif
new file mode 100644 (file)
index 0000000..44ffdf4
Binary files /dev/null and b/koha-tmpl/opac-tmpl/prog/images/Star0.gif differ
diff --git a/koha-tmpl/opac-tmpl/prog/images/Star1.gif b/koha-tmpl/opac-tmpl/prog/images/Star1.gif
new file mode 100644 (file)
index 0000000..2038638
Binary files /dev/null and b/koha-tmpl/opac-tmpl/prog/images/Star1.gif differ
diff --git a/koha-tmpl/opac-tmpl/prog/images/Star2.gif b/koha-tmpl/opac-tmpl/prog/images/Star2.gif
new file mode 100644 (file)
index 0000000..2b60940
Binary files /dev/null and b/koha-tmpl/opac-tmpl/prog/images/Star2.gif differ
diff --git a/koha-tmpl/opac-tmpl/prog/images/Star3.gif b/koha-tmpl/opac-tmpl/prog/images/Star3.gif
new file mode 100644 (file)
index 0000000..3ff6739
Binary files /dev/null and b/koha-tmpl/opac-tmpl/prog/images/Star3.gif differ
diff --git a/koha-tmpl/opac-tmpl/prog/images/Star4.gif b/koha-tmpl/opac-tmpl/prog/images/Star4.gif
new file mode 100644 (file)
index 0000000..473cb32
Binary files /dev/null and b/koha-tmpl/opac-tmpl/prog/images/Star4.gif differ
diff --git a/koha-tmpl/opac-tmpl/prog/images/Star5.gif b/koha-tmpl/opac-tmpl/prog/images/Star5.gif
new file mode 100644 (file)
index 0000000..0a61173
Binary files /dev/null and b/koha-tmpl/opac-tmpl/prog/images/Star5.gif differ
diff --git a/opac/opac-overdrive-search.pl b/opac/opac-overdrive-search.pl
new file mode 100755 (executable)
index 0000000..e4a5504
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/perl
+
+# Copyright 2009 BibLibre SARL
+#
+# 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 CGI;
+
+use C4::Auth qw(:DEFAULT get_session);
+use C4::Output;
+
+my $cgi = new CGI;
+
+# Getting the template and auth
+my ($template, $loggedinuser, $cookie)
+= get_template_and_user({template_name => "opac-overdrive-search.tmpl",
+                                query => $cgi,
+                                type => "opac",
+                                authnotrequired => 1,
+                                flagsrequired => {borrowers => 1},
+                                debug => 1,
+                                });
+
+$template->{'VARS'}->{'q'} = $cgi->param('q');
+$template->{'VARS'}->{'limit'} = C4::Context->preference('OPACnumSearchResults') || 20;
+$template->{'VARS'}->{'OPACnumSearchResults'} = C4::Context->preference('OPACnumSearchResults') || 20;
+$template->{'VARS'}->{'OverDriveLibraryID'} = C4::Context->preference('OverDriveLibraryID');
+
+output_html_with_http_headers $cgi, $cookie, $template->output;
index 76f4fda..2854da6 100755 (executable)
@@ -51,6 +51,7 @@ use C4::Tags qw(get_tags);
 use C4::Branch; # GetBranches
 use C4::SocialData;
 use C4::Ratings;
+use C4::External::OverDrive;
 
 use POSIX qw(ceil floor strftime);
 use URI::Escape;
@@ -886,5 +887,10 @@ $template->{VARS}->{IDreamBooksReviews} = C4::Context->preference('IDreamBooksRe
 $template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer');
 $template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults');
 
+if ($offset == 0 && IsOverDriveEnabled()) {
+    $template->param(OverDriveEnabled => 1);
+    $template->param(OverDriveLibraryID => C4::Context->preference('OverDriveLibraryID'));
+}
+
     $template->param( borrowernumber    => $borrowernumber);
 output_with_http_headers $cgi, $cookie, $template->output, $content_type;
diff --git a/opac/svc/overdrive_proxy b/opac/svc/overdrive_proxy
new file mode 100755 (executable)
index 0000000..5c3086b
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+# Copyright 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.
+
+=head1 NAME
+
+svc/overdrive_proxy: Proxy OAuth'd requests to OverDrive
+
+=head1 SYNOPSIS
+
+svc/overdrive_proxy/libraries/9001 -> https://api.overdrive.com/v1/libraries/9001
+
+=head1 DESCRIPTION
+
+This service proxies incoming requests to the OverDrive OAuth API, to keep the
+JS side from having to deal with cross-origin/authentication issues.
+
+=cut
+
+use strict;
+use warnings;
+
+use CGI qw(-oldstyle_urls);
+use JSON;
+
+use C4::Context;
+use C4::External::OverDrive;
+use C4::Output;
+
+my $query = new CGI;
+
+my $token;
+
+if ( !IsOverDriveEnabled() || !( $token = GetOverDriveToken() ) ) {
+    print $query->header(
+        -status => '400 Bad Request',
+        -content
+    );
+
+    print to_json({
+        error => 'invalid_client',
+        error_description => 'OverDrive login failed'
+    });
+
+    exit;
+}
+
+my $request = HTTP::Request::Common::GET( "https://api.overdrive.com/v1" . $query->path_info . '?' . $query->query_string );
+$request->header( Authorization => $token );
+
+my $ua = LWP::UserAgent->new( "Koha " . C4::Context->KOHAVERSION );
+
+my $response = $ua->request( $request ) ;
+if ( $response->code eq '500' ) {
+    print $query->header(
+        -status => '500 Internal Server Error'
+    );
+
+    warn "OverDrive request failed: " . $response->message;
+    print to_json({
+        error => 'invalid_client',
+        error_description => 'OverDrive request failed'
+    });
+
+    exit;
+}
+
+output_with_http_headers $query, undef, $response->content, 'json', $response->status_line;