View | Details | Raw Unified | Return to bug 16034
Collapse All | Expand All

(-)a/Koha/ExternalContent.pm (+88 lines)
Line 0 Link Here
1
# Copyright 2014 Catalyst
2
#
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 3 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
package Koha::ExternalContent;
19
20
use Modern::Perl;
21
use Carp;
22
use base qw(Class::Accessor);
23
24
use Koha;
25
use Koha::Patrons;
26
use C4::Auth;
27
28
__PACKAGE__->mk_accessors(qw(client koha_session_id koha_patron));
29
30
=head1 NAME
31
32
Koha::ExternalContent
33
34
=head1 SYNOPSIS
35
36
 use Koha::ExternalContent;
37
 my $externalcontent = Koha::ExternalContent->new();
38
39
=head1 METHODS
40
41
=cut
42
43
sub agent_string {
44
    return 'Koha/'.Koha::version();
45
}
46
47
sub new {
48
    my $class     = shift;
49
    my $params    = shift || {};
50
    return bless $params, $class;
51
}
52
53
sub _koha_session {
54
    my $self = shift;
55
    my $session_id = $self->koha_session_id or return;
56
    return C4::Auth::get_session($session_id);
57
}
58
59
sub get_from_koha_session {
60
    my $self = shift;
61
    my $key = shift or croak "No key";
62
    my $session = $self->_koha_session or return;
63
    return $session->param($key);
64
}
65
66
sub set_in_koha_session {
67
    my $self = shift;
68
    my $key = shift or croak "No key";
69
    my $value = shift;
70
    my $session = $self->_koha_session or croak "No Koha session";
71
    return $session->param($key, $value);
72
}
73
74
sub koha_patron {
75
    my $self = shift;
76
77
    if (my $patron = $self->_koha_patron_accessor) {
78
        return $patron;
79
    }
80
81
    my $id = $self->get_from_koha_session('number')
82
      or die "No patron number in session";
83
    my $patron = Koha::Patrons->find($id)
84
      or die "Invalid patron number in session";
85
    return $self->_koha_patron_accessor($patron);
86
}
87
88
1;
(-)a/Koha/ExternalContent/OverDrive.pm (+206 lines)
Line 0 Link Here
1
# Copyright 2014 Catalyst
2
#
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 3 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
package Koha::ExternalContent::OverDrive;
19
20
use Modern::Perl;
21
use Carp;
22
23
use base qw(Koha::ExternalContent);
24
use WebService::ILS::OverDrive::Patron;
25
use C4::Context;
26
use Koha::Logger;
27
28
use constant logger => Koha::Logger->get();
29
30
=head1 NAME
31
32
Koha::ExternalContent::OverDrive
33
34
=head1 SYNOPSIS
35
36
    use Koha::ExternalContent::OverDrive;
37
    my $od_client = Koha::ExternalContent::OverDrive->new();
38
    my $od_auth_url = $od_client->auth_url();
39
40
=head1 DESCRIPTION
41
42
A (very) thin wrapper around C<WebService::ILS::OverDrive::Patron>
43
44
Takes "OverDrive*" Koha preferences
45
46
=cut
47
48
sub new {
49
    my $class  = shift;
50
    my $params = shift || {};
51
    $params->{koha_session_id} or croak "No koha_session_id";
52
53
    my $self = $class->SUPER::new($params);
54
    unless ($params->{client}) {
55
        my $client_key     = C4::Context->preference('OverDriveClientKey')
56
          or croak("OverDriveClientKey pref not set");
57
        my $client_secret  = C4::Context->preference('OverDriveClientSecret')
58
          or croak("OverDriveClientSecret pref not set");
59
        my $library_id     = C4::Context->preference('OverDriveLibraryID')
60
          or croak("OverDriveLibraryID pref not set");
61
        my ($token, $token_type) = $self->get_token_from_koha_session();
62
        $self->client( WebService::ILS::OverDrive::Patron->new(
63
            client_id         => $client_key,
64
            client_secret     => $client_secret,
65
            library_id        => $library_id,
66
            access_token      => $token,
67
            access_token_type => $token_type,
68
            user_agent_params => { agent => $class->agent_string }
69
        ) );
70
    }
71
    return $self;
72
}
73
74
=head1 METHODS
75
76
L<WebService::ILS::OverDrive::Patron> methods used without mods:
77
78
=over 4
79
80
=item C<error_message()>
81
82
=back
83
84
C<WebService::ILS::OverDrive::Patron> methods with slightly moded interfaces:
85
86
=head2 auth_url($base_url)
87
88
=head2 auth_by_code($code, $base_url)
89
90
=cut
91
92
use constant AUTH_RETURN_HANDLER => "/cgi-bin/koha/external/overdrive/auth.pl";
93
sub _return_url {
94
    my $self = shift;
95
    my $page_url = shift or croak "Page url not provided";
96
97
    my ($base_url, $page) = ($page_url =~ m!^(https?://[^/]+)(.*)!);
98
    my $return_url = $base_url.AUTH_RETURN_HANDLER;
99
100
    return wantarray ? ($return_url, $page) : $return_url;
101
}
102
103
use constant RETURN_PAGE_SESSION_KEY => "overdrive.return_page";
104
sub get_return_page_from_koha_session {
105
    my $self = shift;
106
    my $return_page = $self->get_from_koha_session(RETURN_PAGE_SESSION_KEY) || "";
107
    $self->logger->debug("get_return_page_from_koha_session: $return_page");
108
    return $return_page;
109
}
110
sub set_return_page_in_koha_session {
111
    my $self = shift;
112
    my $return_page = shift || "";
113
    $self->logger->debug("set_return_page_in_koha_session: $return_page");
114
    return $self->set_in_koha_session( RETURN_PAGE_SESSION_KEY, $return_page );
115
}
116
117
use constant ACCESS_TOKEN_SESSION_KEY => "overdrive.access_token";
118
my $ACCESS_TOKEN_DELIMITER = ":";
119
sub get_token_from_koha_session {
120
    my $self = shift;
121
    my ($token, $token_type)
122
      = split $ACCESS_TOKEN_DELIMITER, $self->get_from_koha_session(ACCESS_TOKEN_SESSION_KEY) || "";
123
    $self->logger->debug("get_token_from_koha_session: ".($token || "(none)"));
124
    return ($token, $token_type);
125
}
126
sub set_token_in_koha_session {
127
    my $self = shift;
128
    my $token = shift || "";
129
    my $token_type = shift || "";
130
    $self->logger->debug("set_token_in_koha_session: $token $token_type");
131
    return $self->set_in_koha_session(
132
        ACCESS_TOKEN_SESSION_KEY,
133
        join($ACCESS_TOKEN_DELIMITER, $token, $token_type)
134
    );
135
}
136
137
sub is_logged_in {
138
    my $self = shift;
139
    my ($token, $token_type) = $self->get_token_from_koha_session();
140
    $token ||= $self->auth_by_saved_token;
141
    return $token;
142
}
143
144
sub auth_url {
145
    my $self = shift;
146
    my $page_url = shift or croak "Page url not provided";
147
148
    my ($return_url, $page) = $self->_return_url($page_url);
149
    $self->set_return_page_in_koha_session($page);
150
    return $self->client->auth_url($return_url);
151
}
152
153
sub auth_by_code {
154
    my $self = shift;
155
    my $code = shift or croak "OverDrive auth code not provided";
156
    my $base_url = shift or croak "App base url not provided";
157
158
    my ($access_token, $access_token_type, $auth_token)
159
      = $self->client->auth_by_code($code, $self->_return_url($base_url));
160
    $access_token or die "Invalid OverDrive code returned";
161
    $self->set_token_in_koha_session($access_token, $access_token_type);
162
163
    $self->koha_patron->set({overdrive_auth_token => $auth_token})->store;
164
    return $self->get_return_page_from_koha_session;
165
}
166
167
sub auth_by_saved_token {
168
    my $self = shift;
169
170
    my $koha_patron = $self->koha_patron;
171
    if (my $auth_token = $koha_patron->overdrive_auth_token) {
172
        my ($access_token, $access_token_type, $new_auth_token)
173
          = $self->client->auth_by_token($auth_token);
174
        $self->set_token_in_koha_session($access_token, $access_token_type);
175
        $koha_patron->set({overdrive_auth_token => $new_auth_token})->store;
176
        return $access_token;
177
    }
178
179
    return;
180
}
181
182
sub forget {
183
    my $self = shift;
184
185
    $self->set_token_in_koha_session("", "");
186
    $self->koha_patron->update({overdrive_auth_token => undef});
187
}
188
189
use vars qw{$AUTOLOAD};
190
sub AUTOLOAD {
191
    my $self = shift;
192
    (my $method = $AUTOLOAD) =~ s/.*:://;
193
    my $od = $self->client;
194
    local $@;
195
    my $ret = eval { $od->$method(@_) };
196
    if ($@) {
197
        if ( $od->is_access_token_error($@) && $self->auth_by_saved_token ) {
198
            return $od->$method(@_);
199
        }
200
        die $@;
201
    }
202
    return $ret;
203
}
204
sub DESTROY { }
205
206
1;
(-)a/Koha/Schema/Result/Borrower.pm (+2 lines)
Lines 616-621 __PACKAGE__->add_columns( Link Here
616
    datetime_undef_if_invalid => 1,
616
    datetime_undef_if_invalid => 1,
617
    is_nullable => 1,
617
    is_nullable => 1,
618
  },
618
  },
619
  "overdrive_auth_token",
620
  { data_type => "text", is_nullable => 1 },
619
);
621
);
620
622
621
=head1 PRIMARY KEY
623
=head1 PRIMARY KEY
(-)a/installer/data/mysql/atomicupdate/overdrive.sql (+1 lines)
Line 0 Link Here
1
ALTER TABLE borrowers ADD overdrive_auth_token text default NULL AFTER lastseen;
(-)a/installer/data/mysql/kohastructure.sql (+1 lines)
Lines 1642-1647 CREATE TABLE `borrowers` ( -- this table includes information about your patrons Link Here
1642
  `checkprevcheckout` varchar(7) NOT NULL default 'inherit', -- produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'.
1642
  `checkprevcheckout` varchar(7) NOT NULL default 'inherit', -- produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'.
1643
  `updated_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- time of last change could be useful for synchronization with external systems (among others)
1643
  `updated_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- time of last change could be useful for synchronization with external systems (among others)
1644
  `lastseen` datetime default NULL, -- last time a patron has been seed (connected at the OPAC or staff interface)
1644
  `lastseen` datetime default NULL, -- last time a patron has been seed (connected at the OPAC or staff interface)
1645
  overdrive_auth_token text default NULL, -- persist OverDrive auth token
1645
  UNIQUE KEY `cardnumber` (`cardnumber`),
1646
  UNIQUE KEY `cardnumber` (`cardnumber`),
1646
  PRIMARY KEY `borrowernumber` (`borrowernumber`),
1647
  PRIMARY KEY `borrowernumber` (`borrowernumber`),
1647
  KEY `categorycode` (`categorycode`),
1648
  KEY `categorycode` (`categorycode`),
(-)a/opac/external/overdrive/auth.pl (+56 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# script to log clicks on links to external urls
4
5
# Copyright 2015 Catalyst IT
6
# This file is part of Koha.
7
#
8
# Koha is free software; you can redistribute it and/or modify it
9
# under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# Koha is distributed in the hope that it will be useful, but
14
# WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with Koha; if not, see <http://www.gnu.org/licenses>.
20
21
use Modern::Perl;
22
use CGI qw ( -utf8 );
23
use URI;
24
use URI::Escape;
25
use C4::Auth qw(checkauth);
26
use Koha::Logger;
27
use Koha::ExternalContent::OverDrive;
28
29
my $logger = Koha::Logger->get({ interface => 'opac' });
30
my $cgi = new CGI;
31
32
my ( $user, $cookie, $sessionID, $flags ) = checkauth( $cgi, 1, {}, 'opac' );
33
my ($redirect_page, $error);
34
if ($user && $sessionID) {
35
    my $od = Koha::ExternalContent::OverDrive->new({ koha_session_id => $sessionID });
36
    if ( my $auth_code = $cgi->param('code') ) {
37
        my $base_url = $cgi->url(-base => 1);
38
        local $@;
39
        $redirect_page = eval { $od->auth_by_code($auth_code, $base_url) };
40
        if ($@) {
41
            $logger->error($@);
42
            $error = $od->error_message($@);
43
        }
44
    }
45
    else {
46
        $error = "Missing OverDrive auth code";
47
    }
48
    $redirect_page ||= $od->get_return_page_from_koha_session;
49
}
50
else {
51
    $error = "User not logged in";
52
}
53
$redirect_page ||= "/cgi-bin/koha/opac-user.pl";
54
my $uri = URI->new($redirect_page);
55
$uri->query_form( $uri->query_form, overdrive_tab => 1, overdrive_error => uri_escape($error || "") );
56
print $cgi->redirect($redirect_page);
(-)a/t/Koha_ExternalContent_OverDrive.t (-1 / +35 lines)
Line 0 Link Here
0
- 
1
use Modern::Perl;
2
3
use t::lib::Mocks;
4
use Test::More tests => 5;                      # last test to print
5
6
local $@;
7
eval { require WebService::ILS::OverDrive::Patron; }
8
  or diag($@);
9
SKIP: {
10
    skip "cannot filnd WebService::ILS::OverDrive::Patron", 5 if $@;
11
12
    use_ok('Koha::ExternalContent::OverDrive');
13
14
    t::lib::Mocks::mock_preference('OverDriveClientKey', 'DUMMY');
15
    t::lib::Mocks::mock_preference('OverDriveClientSecret', 'DUMMY');
16
    t::lib::Mocks::mock_preference('OverDriveLibraryID', 'DUMMY');
17
18
    my $client = Koha::ExternalContent::OverDrive->new({koha_session_id => 'DUMMY'});
19
20
    my $user_agent_string = $client->user_agent->agent();
21
    ok ($user_agent_string =~ m/^Koha/, 'User Agent string is set')
22
      or diag("User Agent string: $user_agent_string");
23
24
    my $base_url = "http://mykoha.org";
25
    ok ($client->auth_url($base_url), 'auth_url()');
26
    local $@;
27
    eval { $client->auth_by_code("blah", $base_url) };
28
    ok($@, "auth_by_code() dies with bogus credentials");
29
    SKIP: {
30
        skip "No exception", 1 unless $@;
31
        my $error_message = $client->error_message($@);
32
        ok($error_message =~ m/Authorization Failed/i, "error_message()")
33
          or diag("Original:\n$@\nTurned into:\n$error_message");
34
    }
35
}

Return to bug 16034