@@ -, +, @@ --- Koha/REST/V1/Biblios.pm | 121 ++++++++++++++++++++++++++++++ api/v1/swagger/paths/biblios.yaml | 46 ++++++++++++ api/v1/swagger/swagger.yaml | 8 ++ t/db_dependent/api/v1/biblios.t | 57 +++++++++++++- 4 files changed, 231 insertions(+), 1 deletion(-) --- a/Koha/REST/V1/Biblios.pm +++ a/Koha/REST/V1/Biblios.pm @@ -21,6 +21,7 @@ use Mojo::Base 'Mojolicious::Controller'; use Koha::Biblios; use Koha::RecordProcessor; +use Koha::SearchEngine::Search; use C4::Biblio qw( DelBiblio ); use List::MoreUtils qw( any ); @@ -142,6 +143,126 @@ sub delete { }; } +=head3 get_biblios_public + +Controller function that handles retrieving biblios by querying the database +via the searchengine that's currently in use. Use the q_ccl query paramater. + +=cut + +sub get_biblios_public { + + my $c = shift->openapi->valid_input or return; + + my $requested_content_type = $c->req->headers->header('Accept'); + my $searcher = Koha::SearchEngine::Search->new( { index => 'biblios' } ); + my $query = $c->validation->param('q_ccl'); + my $record_processor = Koha::RecordProcessor->new( + { + filters => 'ViewPolicy', + options => { + interface => 'opac', + } + } + ); + + my ( $error, $results, $total_hits ) = + $searcher->simple_search_compat( $query, 0, undef ); + + if ( !$total_hits ) { + return $c->render( + status => 404, + openapi => { + error => 'Nothing found.' + } + ); + } + + sub format_record_by_content_type { + my ($args) = @_; + + if ( $args->{'content_type'} eq 'application/marc-in-json' ) { + for my $record ( @{ $args->{'records'} } ) { + $record = $record->to_mij; + } + return ( q{[} . ( join q{,}, @{ $args->{'records'} } ) . q{]} ); + } + + # Insert additional content types here or above, you know .. alphabetically + } + + sub process_record { + my ($args) = @_; + + my $biblionumber = + $args->{'searcher'}->extract_biblionumber( $args->{'record'} ); + my $biblio = Koha::Biblios->find( { biblionumber => $biblionumber } ); + + if ( + !( + $args->{'patron'} + && $args->{'patron'}->category->override_hidden_items + ) + ) + { + if ( $biblio->hidden_in_opac( { rules => $args->{'rules'} } ) ) { + next; + } + } + + $args->{'processor'}->process( $args->{'record'} ); + + return $args->{'record'}; + } + + return try { + + my $marcflavour = C4::Context->preference('marcflavour'); + + # Apply framework's filtering to MARC::Record object + + my $patron = $c->stash('koha.user'); + my $opachiddenitems_rules = + C4::Context->yaml_preference('OpacHiddenItems'); + + my @records; + for my $result ( @{$results} ) { + + if ( ref($result) eq q{} ) { next; } + + push @records, + process_record( + { + searcher => $searcher, + processor => $record_processor, + record => $result, + patron => $patron, + rules => $opachiddenitems_rules + } + ); + } + + my $response = + format_record_by_content_type( + { content_type => $requested_content_type, records => \@records } ); + + $c->respond_to( + mij => { + status => 200, + format => 'mij', + data => $response + }, + any => { + status => 406, + openapi => [ 'application/marc-in-json', ] + } + ); + } + catch { + $c->unhandled_exception($_); + }; +} + =head3 get_public Controller function that handles retrieving a single biblio object --- a/api/v1/swagger/paths/biblios.yaml +++ a/api/v1/swagger/paths/biblios.yaml @@ -279,6 +279,52 @@ x-koha-authorization: permissions: reserveforothers: place_holds +"/public/biblios": + get: + x-mojo-to: Biblios#get_biblios_public + operationId: getBibliosPublic + tags: + - biblios + summary: Get biblios (public) + parameters: + - $ref: "../swagger.yaml#/parameters/q_ccl" + produces: + - application/marc-in-json + responses: + "200": + description: List of biblios + schema: + type: array + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Biblio not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "406": + description: Not acceptable + schema: + type: array + description: Accepted content-types + items: + type: string + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" "/public/biblios/{biblio_id}": get: x-mojo-to: Biblios#get_public --- a/api/v1/swagger/swagger.yaml +++ a/api/v1/swagger/swagger.yaml @@ -201,6 +201,8 @@ paths: $ref: "./paths/patrons_password.yaml#/~1patrons~1{patron_id}~1password" "/patrons/{patron_id}/password/expiration_date": $ref: "./paths/patrons_password.yaml#/~1patrons~1{patron_id}~1password~1expiration_date" + "/public/biblios": + $ref: "./paths/biblios.yaml#/~1public~1biblios" "/public/biblios/{biblio_id}": $ref: "./paths/biblios.yaml#/~1public~1biblios~1{biblio_id}" "/public/biblios/{biblio_id}/items": @@ -384,6 +386,12 @@ parameters: required: false schema: type: object + q_ccl: + description: CCL query sent as a query parameter + in: query + name: q_ccl + required: false + type: string q_header: description: Query filter sent as a request header in: header --- a/t/db_dependent/api/v1/biblios.t +++ a/t/db_dependent/api/v1/biblios.t @@ -20,7 +20,7 @@ use Modern::Perl; use utf8; use Encode; -use Test::More tests => 7; +use Test::More tests => 8; use Test::MockModule; use Test::Mojo; use Test::Warn; @@ -216,6 +216,61 @@ subtest 'delete() tests' => sub { $schema->storage->txn_rollback; }; +subtest 'get_biblios_public() tests' => sub { + + plan tests => 5; + + $schema->storage->txn_begin; + + my $category = $builder->build_object({ class => 'Koha::Patron::Categories' }); + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + flags => undef, # opac user + categorycode => $category->categorycode + } + } + ); + + my $password = 'thePassword123'; + $patron->set_password( { password => $password, skip_validation => 1 } ); + $patron->discard_changes; + my $userid = $patron->userid; + + # Make sure author in shown in the OPAC + my $subfields = Koha::MarcSubfieldStructures->search({ tagfield => '100' }); + while ( my $subfield = $subfields->next ) { + $subfield->set({ hidden => -1 })->store; + } + Koha::Caches->get_instance()->flush_all; + + $t->get_ok( "//$userid:$password@/api/v1/public/biblios" . q{?q_ccl=test} + => { Accept => 'application/weird+format' } ) + ->status_is(400); + + $t->get_ok( "//$userid:$password@/api/v1/public/biblios" . q{?q_ccl=test} + => { Accept => 'application/marc-in-json' } ) + ->status_is(200); + + subtest 'anonymous access' => sub { + + plan tests => 4; + + $t->get_ok( "/api/v1/public/biblios" . q{?q_ccl=test} + => { Accept => 'application/weird+format' } ) + ->status_is(400); + + $t->get_ok( "/api/v1/public/biblios" . q{?q_ccl=test} + => { Accept => 'application/marc-in-json' } ) + ->status_is(200); + + }; + + $schema->storage->txn_rollback; + +}; + subtest 'get_public() tests' => sub { plan tests => 25; --