Bug 34520: DBIC schema
[koha.git] / Koha / ERM / Providers / EBSCO.pm
1 package Koha::ERM::Providers::EBSCO;
2
3 use Modern::Perl;
4
5 use HTTP::Request;
6 use LWP::UserAgent;
7 use JSON qw( from_json decode_json encode_json );
8 use List::Util qw( first );
9
10 use Koha::Exceptions;
11
12 use Koha::ERM::EHoldings::Packages;
13
14 sub new {
15     my $class = shift;
16     my $self = {};
17     return bless $self, $class;
18 }
19
20 sub config {
21     return {
22         custid  => C4::Context->preference('ERMProviderEbscoCustomerID') || C4::Context->config('ERMProviderEbscoCustomerID'),
23         api_key => C4::Context->preference('ERMProviderEbscoApiKey') || C4::Context->config('ERMProviderEbscoApiKey'),
24     };
25 }
26
27 sub build_title {
28     my ( $self, $result ) = @_;
29     my $title = {
30         title_id          => $result->{titleId},
31         publication_title => $result->{titleName},
32         # date_first_issue_online => ?,
33         # num_first_vol_online => ?,
34         # num_first_issue_online => ?,
35         # date_last_issue_online => ?,
36         # num_last_vol_online => ?,
37         # num_last_issue_online => ?,
38         # title_url => ?,
39         # embargo_info => ?,
40         # coverage_depth => ?,
41         # notes => ?,
42         publisher_name => $result->{publisherName},
43         publication_type => $result->{pubType},
44         # date_monograph_published_print => ?,
45         # date_monograph_published_online => ?,
46         # monograph_volume => ?,
47         # monograph_edition => ?,
48         # first_editor => ?,
49         # parent_publication_title_id => ?,
50         # preceding_publication_title_id => ?,
51         # access_type => ?,
52     };
53     if ( $result->{contributorsList} ) {
54         my @contributors = @{ $result->{contributorsList} };
55         my $first_author = first { $_->{type} eq 'author' || $_->{type} eq 'Author' } @contributors;
56         if ( $first_author ) {
57             $title->{first_author} = $first_author->{contributor};
58         }
59     }
60     for my $identifier ( @{ $result->{identifiersList} } ) {
61
62         # FIXME $identifier->{type} : 0 for ISSN and 1 for ISBN
63         if ( $identifier->{subtype} == 1 ) {
64             $title->{print_identifier} = $identifier->{id};
65         }
66         elsif ( $identifier->{subtype} == 2 ) {
67             $title->{online_identifier} = $identifier->{id};
68         }
69     }
70     for my $r ( @{ $result->{customerResourcesList} } ) {
71         if ( $r->{isSelected} ) {
72             $title->{is_selected} = 1;
73             last;
74         }
75     }
76
77     return $title;
78 }
79
80 sub build_vendor {
81     my ( $self, $result ) = @_;
82     my $vendor = {
83         vendor_id    => $result->{vendorId},
84         name         => $result->{vendorName},
85         package_type => $result->{packageType},
86     };
87     return $vendor;
88 }
89
90 sub build_package {
91     my ( $self, $result ) = @_;
92     my $local_package = $self->get_local_package(
93         $result->{vendorId} . '-' . $result->{packageId} );
94     my $package = {
95         package_id   => $result->{vendorId} . '-' . $result->{packageId},
96         ( $local_package
97             ? ( koha_internal_id => $local_package->package_id )
98             : () ),
99         name         => $result->{packageName},
100         content_type => $result->{contentType}, # This does not exist in /vendors/1/packages/2/titles/3
101         created_on   => undef,
102         is_selected  => $result->{isSelected},
103         package_type => $result->{packageType},
104         vendor_id    => $result->{vendorId},
105     };
106     return $package;
107 }
108
109 sub build_resource {
110     my ( $self, $result ) = @_;
111     my $resource = {
112         resource_id => $result->{vendorId} . '-'
113           . $result->{packageId} . '-'
114           . $result->{titleId},
115         package_id  => $result->{vendorId} . '-' . $result->{packageId},
116         title_id    => $result->{titleId},
117         is_selected => $result->{isSelected},
118         started_on  => $result->{managedCoverageList}->[0]->{beginCoverage},
119         ended_on    => $result->{managedCoverageList}->[0]->{endCoverage},
120     };
121     return $resource;
122 }
123
124 sub build_additional_params {
125     my ( $self, $query_params ) = @_;
126
127     my $additional_params;
128     if ( $query_params->{q} ) {
129         my $q = from_json $query_params->{q};
130         while ( my ( $attr, $value ) = each %$q ) {
131             $additional_params->{$attr} = $value;
132         }
133     }
134
135     return $additional_params;
136 }
137
138 sub get_local_package {
139     my ( $self, $package_id ) = @_;
140     return Koha::ERM::EHoldings::Packages->find(
141         { provider => 'ebsco', external_id => $package_id } );
142 }
143
144 sub embed {
145     my ( $self, $object, $info, $embed_header ) = @_;
146     $embed_header ||= q{};
147
148     my @embed_resources;
149
150     foreach my $embed_req ( split /\s*,\s*/, $embed_header ) {
151         if ( $embed_req eq 'vendor.name' ) {
152             $object->{vendor} = { name => $info->{vendorName}, };
153         }
154         elsif ( $embed_req eq 'vendor' ) {
155             $object->{vendor} = $self->build_vendor($info);
156         }
157         elsif ( $embed_req eq 'title' ) {
158             $object->{title} = $self->build_title($info);
159         }
160         elsif ( $embed_req eq 'resources+count' ) {
161             $object->{resources_count} = $info->{titleCount};
162         }
163         elsif ( $embed_req eq 'package' ) {
164             $object->{package} = $self->build_package($info);
165         }
166         elsif ( $embed_req eq 'package.name' ) {
167             $object->{package} = { name => $info->{packageName}, };
168         }
169         elsif ( $embed_req eq 'package_agreements.agreement' ) {
170             # How to deal with 'package_agreements.agreement'?
171             $object->{package_agreements} = [];
172             my $package_id = $info->{vendorId} . '-' . $info->{packageId};
173             my $local_package = $self->get_local_package($package_id);
174             if ( $local_package ) {
175                 for my $package_agreement (
176                     @{ $local_package->package_agreements->as_list } )
177                 {
178                     push @{ $object->{package_agreements} },
179                       {
180                         %{ $package_agreement->unblessed },
181                         agreement => $package_agreement->agreement->unblessed,
182                       };
183                 }
184             }
185         }
186         if ( $embed_req eq 'resources' || $embed_req eq 'resources.package' ) {
187             push @embed_resources, $embed_req;
188         }
189     }
190
191     if (@embed_resources) {
192         for my $r ( @{ $info->{customerResourcesList} } ) {
193             my $resource = {};
194             for my $embed_req ( @embed_resources ) {
195                 if ( $embed_req eq 'resources' ) {
196                     $resource = $self->build_resource($r);
197                 }
198                 elsif ( $embed_req eq 'resources.package' ) {
199                     unless ( %$resource ) {
200                         $resource = $self->build_resource($r);
201                     }
202                     $resource->{package} = $self->build_package($r);
203                 }
204             }
205             push @{$object->{resources}}, $resource;
206         }
207     }
208     return $object;
209 }
210
211 sub build_query_pagination {
212     my ( $self, $params ) = @_;
213     my $per_page = $params->{per_page}
214       // C4::Context->preference('RESTdefaultPageSize') // 20;
215     if ( $per_page == -1 || $per_page > 100 ) { $per_page = 100; }
216     my $page = $params->{page} || 1;
217
218     return ( $per_page, $page );
219 }
220
221 sub build_query {
222     my ( $self, $url, $params ) = @_;
223
224     return $url unless $params && %$params;
225     while ( my ( $attr, $value ) = each %$params ) {
226         if ( $attr eq 'name' ) {
227             $url .= '&search=' . $value;
228         }
229         elsif ( $attr eq 'content_type' ) {
230             $url .= '&contenttype=' . $value;
231         }
232         elsif ( $attr eq 'selection_type' ) {
233             $url .= '&selection=' . $value;
234         }
235         elsif ( $attr eq 'publication_title' ) {
236             $url .= '&search=' . $value;
237         }
238         elsif ( $attr eq 'publication_type' ) {
239             $url .= '&resourcetype=' . $value;
240         }
241     }
242     return $url;
243 }
244
245 sub request {
246     my ( $self, $method, $url, $params, $payload ) = @_;
247
248     $url = $self->build_query($url, $params) if $params;
249
250     my $config = $self->config;
251     my $base_url = 'https://api.ebsco.io/rm/rmaccounts/' . $config->{custid};
252     my $request = HTTP::Request->new(
253         $method => $base_url . $url,
254         undef, ( $payload ? encode_json($payload) : undef )
255     );
256     $request->header( 'x-api-key' => $config->{api_key} );
257     $request->header( 'content-type' => 'application/json; charset=UTF-8' );
258     my $ua = LWP::UserAgent->new;
259     my $response = $ua->simple_request($request);
260     if ( $response->code >= 400 ) {
261         my $result = decode_json( $response->decoded_content );
262         my $message;
263         if ( ref($result) eq 'ARRAY' ) {
264             for my $r (@$result) {
265                 $message .= $r->{message};
266             }
267         }
268         else {
269             $message = $result->{message} || $result->{Message} || q{};
270             if ( $result->{errors} ) {
271                 for my $e ( @{ $result->{errors} } ) {
272                     $message .= $e->{message};
273                 }
274             }
275         }
276         warn sprintf "ERROR - EBSCO API %s returned %s - %s\n", $url, $response->code, $message;
277         if ( $response->code == 404 ) {
278             Koha::Exceptions::ObjectNotFound->throw($message);
279         } elsif ( $response->code == 401 ) {
280             Koha::Exceptions::Authorization::Unauthorized->throw($message);
281         } else {
282             die sprintf "ERROR requesting EBSCO API\n%s\ncode %s: %s\n", $url, $response->code,
283               $message;
284         }
285     } elsif ( $response->code == 204 ) { # No content
286         return
287     }
288
289     return decode_json( $response->decoded_content );
290 }
291
292 1;