Bug 27932: Add GET /biblios/:biblio_id/pickup_locations route
[koha.git] / Koha / REST / V1 / Biblios.pm
1 package Koha::REST::V1::Biblios;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use Mojo::Base 'Mojolicious::Controller';
21
22 use Koha::Biblios;
23 use Koha::RecordProcessor;
24 use C4::Biblio qw(DelBiblio);
25
26 use List::MoreUtils qw(any);
27 use MARC::Record::MiJ;
28
29 use Try::Tiny;
30
31 =head1 API
32
33 =head2 Methods
34
35 =head3 get
36
37 Controller function that handles retrieving a single biblio object
38
39 =cut
40
41 sub get {
42     my $c = shift->openapi->valid_input or return;
43
44     my $attributes;
45     $attributes = { prefetch => [ 'metadata' ] } # don't prefetch metadata if not needed
46         unless $c->req->headers->accept =~ m/application\/json/;
47
48     my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, $attributes );
49
50     unless ( $biblio ) {
51         return $c->render(
52             status  => 404,
53             openapi => {
54                 error => "Object not found."
55             }
56         );
57     }
58
59     return try {
60
61         if ( $c->req->headers->accept =~ m/application\/json/ ) {
62             return $c->render(
63                 status => 200,
64                 json   => $biblio->to_api
65             );
66         }
67         else {
68             my $record = $biblio->metadata->record;
69
70             $c->respond_to(
71                 marcxml => {
72                     status => 200,
73                     format => 'marcxml',
74                     text   => $record->as_xml_record
75                 },
76                 mij => {
77                     status => 200,
78                     format => 'mij',
79                     text   => $record->to_mij
80                 },
81                 marc => {
82                     status => 200,
83                     format => 'marc',
84                     text   => $record->as_usmarc
85                 },
86                 txt => {
87                     status => 200,
88                     format => 'text/plain',
89                     text   => $record->as_formatted
90                 },
91                 any => {
92                     status  => 406,
93                     openapi => [
94                         "application/json",
95                         "application/marcxml+xml",
96                         "application/marc-in-json",
97                         "application/marc",
98                         "text/plain"
99                     ]
100                 }
101             );
102         }
103     }
104     catch {
105         $c->unhandled_exception($_);
106     };
107 }
108
109 =head3 delete
110
111 Controller function that handles deleting a biblio object
112
113 =cut
114
115 sub delete {
116     my $c = shift->openapi->valid_input or return;
117
118     my $biblio = Koha::Biblios->find( $c->validation->param('biblio_id') );
119
120     if ( not defined $biblio ) {
121         return $c->render(
122             status  => 404,
123             openapi => { error => "Object not found" }
124         );
125     }
126
127     return try {
128         my $error = DelBiblio( $biblio->id );
129
130         if ($error) {
131             return $c->render(
132                 status  => 409,
133                 openapi => { error => $error }
134             );
135         }
136         else {
137             return $c->render( status => 204, openapi => "" );
138         }
139     }
140     catch {
141         $c->unhandled_exception($_);
142     };
143 }
144
145 =head3 get_public
146
147 Controller function that handles retrieving a single biblio object
148
149 =cut
150
151 sub get_public {
152     my $c = shift->openapi->valid_input or return;
153
154     my $biblio = Koha::Biblios->find(
155         { biblionumber => $c->validation->param('biblio_id') },
156         { prefetch     => ['metadata'] } );
157
158     unless ($biblio) {
159         return $c->render(
160             status  => 404,
161             openapi => {
162                 error => "Object not found."
163             }
164         );
165     }
166
167     return try {
168
169         my $record = $biblio->metadata->record;
170
171         my $opachiddenitems_rules = C4::Context->yaml_preference('OpacHiddenItems');
172         my $patron = $c->stash('koha.user');
173
174         # Check if the biblio should be hidden for unprivileged access
175         # unless there's a logged in user, and there's an exception for it's
176         # category
177         unless ( $patron and $patron->category->override_hidden_items ) {
178             if ( $biblio->hidden_in_opac({ rules => $opachiddenitems_rules }) )
179             {
180                 return $c->render(
181                     status  => 404,
182                     openapi => {
183                         error => "Object not found."
184                     }
185                 );
186             }
187         }
188
189         my $marcflavour = C4::Context->preference("marcflavour");
190
191         my $record_processor = Koha::RecordProcessor->new({
192             filters => 'ViewPolicy',
193             options => {
194                 interface => 'opac',
195                 frameworkcode => $biblio->frameworkcode
196             }
197         });
198         # Apply framework's filtering to MARC::Record object
199         $record_processor->process($record);
200
201         $c->respond_to(
202             marcxml => {
203                 status => 200,
204                 format => 'marcxml',
205                 text   => $record->as_xml_record
206             },
207             mij => {
208                 status => 200,
209                 format => 'mij',
210                 text   => $record->to_mij
211             },
212             marc => {
213                 status => 200,
214                 format => 'marc',
215                 text   => $record->as_usmarc
216             },
217             txt => {
218                 status => 200,
219                 format => 'text/plain',
220                 text   => $record->as_formatted
221             },
222             any => {
223                 status  => 406,
224                 openapi => [
225                     "application/marcxml+xml",
226                     "application/marc-in-json",
227                     "application/marc",
228                     "text/plain"
229                 ]
230             }
231         );
232     }
233     catch {
234         $c->unhandled_exception($_);
235     };
236 }
237
238 =head3 get_items
239
240 Controller function that handles retrieving biblio's items
241
242 =cut
243
244 sub get_items {
245     my $c = shift->openapi->valid_input or return;
246
247     my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, { prefetch => ['items'] } );
248
249     unless ( $biblio ) {
250         return $c->render(
251             status  => 404,
252             openapi => {
253                 error => "Object not found."
254             }
255         );
256     }
257
258     return try {
259
260         my $items_rs = $biblio->items;
261         my $items    = $c->objects->search( $items_rs );
262         return $c->render(
263             status  => 200,
264             openapi => $items
265         );
266     }
267     catch {
268         $c->unhandled_exception($_);
269     };
270 }
271
272 =head3 pickup_locations
273
274 Method that returns the possible pickup_locations for a given biblio
275 used for building the dropdown selector
276
277 =cut
278
279 sub pickup_locations {
280     my $c = shift->openapi->valid_input or return;
281
282     my $biblio_id = $c->validation->param('biblio_id');
283     my $biblio = Koha::Biblios->find( $biblio_id );
284
285     unless ($biblio) {
286         return $c->render(
287             status  => 404,
288             openapi => { error => "Biblio not found" }
289         );
290     }
291
292     my $patron_id = delete $c->validation->output->{patron_id};
293     my $patron    = Koha::Patrons->find( $patron_id );
294
295     unless ($patron) {
296         return $c->render(
297             status  => 400,
298             openapi => { error => "Patron not found" }
299         );
300     }
301
302     return try {
303
304         my $ps_set = $biblio->pickup_locations( { patron => $patron } );
305
306         my $pickup_locations = $c->objects->search( $ps_set );
307         my @response = ();
308
309         if ( C4::Context->preference('AllowHoldPolicyOverride') ) {
310
311             my $libraries_rs = Koha::Libraries->search( { pickup_location => 1 } );
312             my $libraries    = $c->objects->search($libraries_rs);
313
314             @response = map {
315                 my $library = $_;
316                 $library->{needs_override} = (
317                     any { $_->{library_id} eq $library->{library_id} }
318                     @{$pickup_locations}
319                   )
320                   ? Mojo::JSON->false
321                   : Mojo::JSON->true;
322                 $library;
323             } @{$libraries};
324
325             return $c->render(
326                 status  => 200,
327                 openapi => \@response
328             );
329         }
330
331         @response = map { $_->{needs_override} = Mojo::JSON->false; $_; } @{$pickup_locations};
332
333         return $c->render(
334             status  => 200,
335             openapi => \@response
336         );
337     }
338     catch {
339         $c->unhandled_exception($_);
340     };
341 }
342
343 1;