Bug 24862: Handle annonymous sessions gracefuly
[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 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 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 MARC::Record::MiJ;
27
28 use Try::Tiny;
29
30 =head1 API
31
32 =head2 Class methods
33
34 =head3 get
35
36 Controller function that handles retrieving a single biblio object
37
38 =cut
39
40 sub get {
41     my $c = shift->openapi->valid_input or return;
42
43     my $attributes;
44     $attributes = { prefetch => [ 'metadata' ] } # don't prefetch metadata if not needed
45         unless $c->req->headers->accept =~ m/application\/json/;
46
47     my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, $attributes );
48
49     unless ( $biblio ) {
50         return $c->render(
51             status  => 404,
52             openapi => {
53                 error => "Object not found."
54             }
55         );
56     }
57
58     return try {
59
60         if ( $c->req->headers->accept =~ m/application\/json/ ) {
61             return $c->render(
62                 status => 200,
63                 json   => $c->build_json_biblio( { biblio => $biblio } )
64             );
65         }
66         else {
67             my $record = $biblio->metadata->record;
68
69             $c->respond_to(
70                 marcxml => {
71                     status => 200,
72                     format => 'marcxml',
73                     text   => $record->as_xml_record
74                 },
75                 mij => {
76                     status => 200,
77                     format => 'mij',
78                     text   => $record->to_mij
79                 },
80                 marc => {
81                     status => 200,
82                     format => 'marc',
83                     text   => $record->as_usmarc
84                 },
85                 txt => {
86                     status => 200,
87                     format => 'text/plain',
88                     text   => $record->as_formatted
89                 },
90                 any => {
91                     status  => 406,
92                     openapi => [
93                         "application/json",
94                         "application/marcxml+xml",
95                         "application/marc-in-json",
96                         "application/marc",
97                         "text/plain"
98                     ]
99                 }
100             );
101         }
102     }
103     catch {
104         return $c->render(
105             status  => 500,
106             openapi => { error => "Something went wrong, check the logs ($_)" }
107         );
108     };
109 }
110
111 =head3 delete
112
113 Controller function that handles deleting a biblio object
114
115 =cut
116
117 sub delete {
118     my $c = shift->openapi->valid_input or return;
119
120     my $biblio = Koha::Biblios->find( $c->validation->param('biblio_id') );
121
122     if ( not defined $biblio ) {
123         return $c->render(
124             status  => 404,
125             openapi => { error => "Object not found" }
126         );
127     }
128
129     return try {
130         my $error = DelBiblio( $biblio->id );
131
132         if ($error) {
133             return $c->render(
134                 status  => 409,
135                 openapi => { error => $error }
136             );
137         }
138         else {
139             return $c->render( status => 204, openapi => "" );
140         }
141     }
142     catch {
143         if ( $_->isa('DBIx::Class::Exception') ) {
144             return $c->render(
145                 status  => 500,
146                 openapi => { error => $_->{msg} }
147             );
148         }
149         else {
150             return $c->render(
151                 status  => 500,
152                 openapi => { error => "Something went wrong, check the logs." }
153             );
154         }
155     };
156 }
157
158 =head3 get_public
159
160 Controller function that handles retrieving a single biblio object
161
162 =cut
163
164 sub get_public {
165     my $c = shift->openapi->valid_input or return;
166
167     my $biblio = Koha::Biblios->find(
168         { biblionumber => $c->validation->param('biblio_id') },
169         { prefetch     => ['metadata'] } );
170
171     unless ($biblio) {
172         return $c->render(
173             status  => 404,
174             openapi => {
175                 error => "Object not found."
176             }
177         );
178     }
179
180     return try {
181
182         my $record = $biblio->metadata->record;
183
184         my $opachiddenitems_rules = C4::Context->yaml_preference('OpacHiddenItems');
185         my $patron = $c->stash('koha.user');
186
187         # Check if the biblio should be hidden for unprivileged access
188         # unless there's a logged in user, and there's an exception for it's
189         # category
190         unless ( $patron and $patron->category->override_hidden_items ) {
191             if ( $biblio->hidden_in_opac({ rules => $opachiddenitems_rules }) )
192             {
193                 return $c->render(
194                     status  => 404,
195                     openapi => {
196                         error => "Object not found."
197                     }
198                 );
199             }
200         }
201
202         my $marcflavour = C4::Context->preference("marcflavour");
203
204         my $record_processor = Koha::RecordProcessor->new({
205             filters => 'ViewPolicy',
206             options => {
207                 interface => 'opac',
208                 frameworkcode => $biblio->frameworkcode
209             }
210         });
211         # Apply framework's filtering to MARC::Record object
212         $record_processor->process($record);
213
214         $c->respond_to(
215             marcxml => {
216                 status => 200,
217                 format => 'marcxml',
218                 text   => $record->as_xml_record
219             },
220             mij => {
221                 status => 200,
222                 format => 'mij',
223                 text   => $record->to_mij
224             },
225             marc => {
226                 status => 200,
227                 format => 'marc',
228                 text   => $record->as_usmarc
229             },
230             txt => {
231                 status => 200,
232                 format => 'text/plain',
233                 text   => $record->as_formatted
234             },
235             any => {
236                 status  => 406,
237                 openapi => [
238                     "application/marcxml+xml",
239                     "application/marc-in-json",
240                     "application/marc",
241                     "text/plain"
242                 ]
243             }
244         );
245     }
246     catch {
247         return $c->render(
248             status  => 500,
249             openapi => { error => "Something went wrong, check the logs ($_)" }
250         );
251     };
252 }
253
254 =head2 Internal methods
255
256 =head3 _to_api
257
258 Helper function that maps unblessed Koha::Patron objects into REST api
259 attribute names.
260
261 =cut
262
263 sub _to_api {
264     my $biblio = shift;
265
266     # Rename attributes
267     foreach my $column ( keys %{$Koha::REST::V1::Biblios::to_api_mapping} ) {
268         my $mapped_column = $Koha::REST::V1::Biblios::to_api_mapping->{$column};
269         if ( exists $biblio->{$column}
270             && defined $mapped_column )
271         {
272             # key != undef
273             $biblio->{$mapped_column} = delete $biblio->{$column};
274         }
275         elsif ( exists $biblio->{$column}
276             && !defined $mapped_column )
277         {
278             # key == undef
279             delete $biblio->{$column};
280         }
281     }
282
283     return $biblio;
284 }
285
286
287 =head3 build_json_biblio
288
289 Internal method that returns all the attributes from the biblio and biblioitems tables
290
291 =cut
292
293 sub build_json_biblio {
294     my ( $c, $args ) = @_;
295
296     my $biblio = $args->{biblio};
297
298     my $response = $biblio->TO_JSON;
299     my $biblioitem = $biblio->biblioitem->TO_JSON;
300
301     foreach my $key ( keys %{ $biblioitem } ) {
302         $response->{$key} = $biblioitem->{$key};
303     }
304
305     return _to_api($response);
306 }
307
308 =head2 Global variables
309
310 =head3 $to_api_mapping
311
312 =cut
313
314 our $to_api_mapping = {
315     agerestriction   => 'age_restriction',
316     biblioitemnumber => undef, # meaningless
317     biblionumber     => 'biblio_id',
318     collectionissn   => 'collection_issn',
319     collectiontitle  => 'collection_title',
320     collectionvolume => 'collection_volume',
321     copyrightdate    => 'copyright_date',
322     datecreated      => 'creation_date',
323     editionresponsibility => undef, # obsolete, not mapped
324     editionstatement => 'edition_statement',
325     frameworkcode    => 'framework_id',
326     illus            => 'illustrations',
327     itemtype         => 'item_type',
328     lccn             => 'lc_control_number',
329     place            => 'publication_place',
330     publicationyear  => 'publication_year',
331     publishercode    => 'publisher',
332     seriestitle      => 'series_title',
333     size             => 'material_size',
334     totalissues      => 'serial_total_issues',
335     unititle         => 'uniform_title',
336     volumedate       => 'volume_date',
337     volumedesc       => 'volume_description',
338 };
339
340 1;