1 package Koha::REST::V1::Biblios;
3 # This file is part of Koha.
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.
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.
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>.
20 use Mojo::Base 'Mojolicious::Controller';
24 use Koha::RecordProcessor;
25 use C4::Biblio qw( DelBiblio AddBiblio ModBiblio );
26 use C4::Search qw( FindDuplicate );
28 use List::MoreUtils qw( any );
29 use MARC::Record::MiJ;
31 use Try::Tiny qw( catch try );
39 Controller function that handles retrieving a single biblio object
44 my $c = shift->openapi->valid_input or return;
47 $attributes = { prefetch => [ 'metadata' ] } # don't prefetch metadata if not needed
48 unless $c->req->headers->accept =~ m/application\/json/;
50 my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, $attributes );
56 error => "Object not found."
63 if ( $c->req->headers->accept =~ m/application\/json/ ) {
66 json => $biblio->to_api
70 my $record = $biblio->metadata->record;
71 my $marcflavour = C4::Context->preference("marcflavour");
77 text => $record->as_xml_record($marcflavour),
82 data => $record->to_mij
87 text => $record->as_usmarc
91 format => 'text/plain',
92 text => $record->as_formatted
98 "application/marcxml+xml",
99 "application/marc-in-json",
108 $c->unhandled_exception($_);
114 Controller function that handles deleting a biblio object
119 my $c = shift->openapi->valid_input or return;
121 my $biblio = Koha::Biblios->find( $c->validation->param('biblio_id') );
123 if ( not defined $biblio ) {
126 openapi => { error => "Object not found" }
131 my $error = DelBiblio( $biblio->id );
136 openapi => { error => $error }
140 return $c->render( status => 204, openapi => "" );
144 $c->unhandled_exception($_);
150 Controller function that handles retrieving a single biblio object
155 my $c = shift->openapi->valid_input or return;
157 my $biblio = Koha::Biblios->find(
158 { biblionumber => $c->validation->param('biblio_id') },
159 { prefetch => ['metadata'] } );
165 error => "Object not found."
172 my $record = $biblio->metadata->record;
174 my $opachiddenitems_rules = C4::Context->yaml_preference('OpacHiddenItems');
175 my $patron = $c->stash('koha.user');
177 # Check if the biblio should be hidden for unprivileged access
178 # unless there's a logged in user, and there's an exception for it's
180 unless ( $patron and $patron->category->override_hidden_items ) {
181 if ( $biblio->hidden_in_opac({ rules => $opachiddenitems_rules }) )
186 error => "Object not found."
192 my $marcflavour = C4::Context->preference("marcflavour");
194 my $record_processor = Koha::RecordProcessor->new({
195 filters => 'ViewPolicy',
198 frameworkcode => $biblio->frameworkcode
201 # Apply framework's filtering to MARC::Record object
202 $record_processor->process($record);
208 text => $record->as_xml_record($marcflavour),
213 data => $record->to_mij
218 text => $record->as_usmarc
222 format => 'text/plain',
223 text => $record->as_formatted
228 "application/marcxml+xml",
229 "application/marc-in-json",
237 $c->unhandled_exception($_);
243 Controller function that handles retrieving biblio's items
248 my $c = shift->openapi->valid_input or return;
250 my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, { prefetch => ['items'] } );
256 error => "Object not found."
263 my $items_rs = $biblio->items;
264 my $items = $c->objects->search( $items_rs );
271 $c->unhandled_exception($_);
277 List Koha::Checkout objects
282 my $c = shift->openapi->valid_input or return;
284 my $checked_in = delete $c->validation->output->{checked_in};
287 my $biblio = Koha::Biblios->find( $c->validation->param('biblio_id') );
292 openapi => { error => 'Object not found' }
298 ? $c->objects->search( $biblio->old_checkouts )
299 : $c->objects->search( $biblio->current_checkouts );
303 openapi => $checkouts
307 $c->unhandled_exception($_);
311 =head3 pickup_locations
313 Method that returns the possible pickup_locations for a given biblio
314 used for building the dropdown selector
318 sub pickup_locations {
319 my $c = shift->openapi->valid_input or return;
321 my $biblio_id = $c->validation->param('biblio_id');
322 my $biblio = Koha::Biblios->find( $biblio_id );
327 openapi => { error => "Biblio not found" }
331 my $patron_id = delete $c->validation->output->{patron_id};
332 my $patron = Koha::Patrons->find( $patron_id );
337 openapi => { error => "Patron not found" }
343 my $pl_set = $biblio->pickup_locations( { patron => $patron } );
346 if ( C4::Context->preference('AllowHoldPolicyOverride') ) {
348 my $libraries_rs = Koha::Libraries->search( { pickup_location => 1 } );
349 my $libraries = $c->objects->search($libraries_rs);
353 $library->{needs_override} = (
354 any { $_->branchcode eq $library->{library_id} }
364 my $pickup_locations = $c->objects->search($pl_set);
365 @response = map { $_->{needs_override} = Mojo::JSON->false; $_; } @{$pickup_locations};
370 openapi => \@response
374 $c->unhandled_exception($_);
378 =head3 get_items_public
380 Controller function that handles retrieving biblio's items, for unprivileged
385 sub get_items_public {
386 my $c = shift->openapi->valid_input or return;
388 my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, { prefetch => ['items'] } );
394 error => "Object not found."
401 my $patron = $c->stash('koha.user');
403 my $items_rs = $biblio->items->filter_by_visible_in_opac({ patron => $patron });
404 my $items = $c->objects->search( $items_rs );
411 $c->unhandled_exception($_);
417 Set rating for the logged in user
423 my $c = shift->openapi->valid_input or return;
425 my $biblio = Koha::Biblios->find( $c->validation->param('biblio_id') );
431 error => "Object not found."
436 my $patron = $c->stash('koha.user');
441 { error => "Cannot rate. Reason: must be logged-in" }
445 my $body = $c->validation->param('body');
446 my $rating_value = $body->{rating};
450 my $rating = Koha::Ratings->find(
452 biblionumber => $biblio->biblionumber,
453 borrowernumber => $patron->borrowernumber,
456 $rating->delete if $rating;
458 if ( $rating_value ) { # Cannot set to 0 from the UI
459 $rating = Koha::Rating->new(
461 biblionumber => $biblio->biblionumber,
462 borrowernumber => $patron->borrowernumber,
463 rating_value => $rating_value,
468 Koha::Ratings->search( { biblionumber => $biblio->biblionumber } );
469 my $average = $ratings->get_avg_rating;
474 rating => $rating && $rating->in_storage ? $rating->rating_value : undef,
476 count => $ratings->count
481 $c->unhandled_exception($_);
487 Controller function that handles creating a biblio object
492 my $c = shift->openapi->valid_input or return;
495 my $headers = $c->req->headers;
497 my $flavour = $headers->header('x-marc-schema');
498 $flavour //= C4::Context->preference('marcflavour');
502 my $frameworkcode = $headers->header('x-framework-id');
503 my $content_type = $headers->content_type;
505 if ( $content_type =~ m/application\/marcxml\+xml/ ) {
506 $record = MARC::Record->new_from_xml( $c->req->body, 'UTF-8', $flavour );
508 elsif ( $content_type =~ m/application\/marc-in-json/ ) {
509 $record = MARC::Record->new_from_mij_structure( $c->req->json );
511 elsif ( $content_type =~ m/application\/marc/ ) {
512 $record = MARC::Record->new_from_usmarc( $c->req->body );
518 "application/marcxml+xml",
519 "application/marc-in-json",
525 my ( $duplicatebiblionumber, $duplicatetitle );
526 ( $duplicatebiblionumber, $duplicatetitle ) = FindDuplicate($record);
528 my $confirm_not_duplicate = $headers->header('x-confirm-not-duplicate');
533 error => "Duplicate biblio $duplicatebiblionumber",
535 ) unless !$duplicatebiblionumber || $confirm_not_duplicate;
537 my ( $biblionumber, $oldbibitemnum );
538 ( $biblionumber, $oldbibitemnum ) = AddBiblio( $record, $frameworkcode );
542 openapi => { id => $biblionumber }
546 $c->unhandled_exception($_);
552 Controller function that handles modifying an biblio object
557 my $c = shift->openapi->valid_input or return;
559 my $biblio_id = $c->param('biblio_id');
560 my $biblio = Koha::Biblios->find($biblio_id);
562 if ( ! defined $biblio ) {
565 openapi => { error => "Object not found" }
570 my $headers = $c->req->headers;
572 my $flavour = $headers->header('x-marc-schema');
573 $flavour //= C4::Context->preference('marcflavour');
575 my $frameworkcode = $headers->header('x-framework-id') || $biblio->frameworkcode;
577 my $content_type = $headers->content_type;
581 if ( $content_type =~ m/application\/marcxml\+xml/ ) {
582 $record = MARC::Record->new_from_xml( $c->req->body, 'UTF-8', $flavour );
584 elsif ( $content_type =~ m/application\/marc-in-json/ ) {
585 $record = MARC::Record->new_from_mij_structure( $c->req->json );
587 elsif ( $content_type =~ m/application\/marc/ ) {
588 $record = MARC::Record->new_from_usmarc( $c->req->body );
595 "application/marcxml+xml",
596 "application/marc-in-json",
602 ModBiblio( $record, $biblio_id, $frameworkcode );
606 openapi => { id => $biblio_id }
610 $c->unhandled_exception($_);
616 Controller function that handles retrieving a single biblio object
621 my $c = shift->openapi->valid_input or return;
625 { prefetch => ['metadata'] } # don't prefetch metadata if not needed
626 unless $c->req->headers->accept =~ m/application\/json/;
628 my $biblios = $c->objects->search_rs( Koha::Biblios->new );
632 if ( $c->req->headers->accept =~ m/application\/json(;.*)?$/ ) {
635 json => $c->objects->to_api( $biblios ),
639 $c->req->headers->accept =~ m/application\/marcxml\+xml(;.*)?$/ )
641 $c->res->headers->add( 'Content-Type', 'application/marcxml+xml' );
644 text => $biblios->print_collection('marcxml')
648 $c->req->headers->accept =~ m/application\/marc-in-json(;.*)?$/ )
650 $c->res->headers->add( 'Content-Type', 'application/marc-in-json' );
653 data => $biblios->print_collection('mij')
656 elsif ( $c->req->headers->accept =~ m/application\/marc(;.*)?$/ ) {
657 $c->res->headers->add( 'Content-Type', 'application/marc' );
660 text => $biblios->print_collection('marc')
663 elsif ( $c->req->headers->accept =~ m/text\/plain(;.*)?$/ ) {
666 text => $biblios->print_collection('txt')
673 "application/json", "application/marcxml+xml",
674 "application/marc-in-json", "application/marc",
681 $c->unhandled_exception($_);