From f8272283e3b9224f4e4817d32869a53e52c27d84 Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Mon, 13 Mar 2023 13:31:23 +0000 Subject: [PATCH] Bug 25870: Add a q_ccl query parameter to /biblios To test: 1) Apply the patch 2) Pick an endpoint tester of your choice, e.g. Insomnia or the ThunderClient if you use VSCode or derivatives. 3) Run a query while using Zebra. 4) Observe the marc-in-json response and check for validity. 5) Run a query while using Elasticsearch. 6) Again, observe the marc-in-json response and check for validity. 7) Not ready for sign-off but please leave a comment or help me on the Koha::Biblios->search thing. --- Koha/REST/V1/Biblios.pm | 75 ++++++++++++++++++++++++++++--- api/v1/swagger/paths/biblios.yaml | 46 +++++++++++++++++++ api/v1/swagger/swagger.yaml | 8 ++++ t/db_dependent/api/v1/biblios.t | 57 ++++++++++++++++++++++- 4 files changed, 179 insertions(+), 7 deletions(-) diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index c8d220e6da..472fc14bf9 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -22,6 +22,7 @@ use Mojo::Base 'Mojolicious::Controller'; use Koha::Biblios; use Koha::Ratings; use Koha::RecordProcessor; +use Koha::SearchEngine::Search; use C4::Biblio qw( DelBiblio AddBiblio ModBiblio ); use C4::Search qw( FindDuplicate ); @@ -144,6 +145,65 @@ 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 $searcher = Koha::SearchEngine::Search->new( { index => 'biblios' } ); + my $query = $c->validation->param('q_ccl'); + + my ( $error, $results, $total_hits ) = $searcher->simple_search_compat( $query, 0, undef ); + + if ( !$total_hits ) { + return $c->render( + status => 404, + openapi => { error => 'Nothing found.' } + ); + } + + return try { + + my $patron = $c->stash('koha.user'); + my $is_public = $c->stash('is_public'); + my $opachiddenitems_rules = C4::Context->yaml_preference('OpacHiddenItems'); + my $searchengine = C4::Context->preference('SearchEngine'); + + my @biblionumbers + = $searchengine eq 'Zebra' + ? map { MARC::Record->new_from_xml( $_, 'UTF-8' )->field('999')->subfield('c') } $results->@* + : map { $_->field('999')->subfield('c') } $results->@*; + my @biblios = map { Koha::Biblios->find( { biblionumber => $_ } ) } @biblionumbers; + my @records = map { + next if ( $is_public + && !( $patron && $patron->category->override_hidden_items ) + && $_->hidden_in_opac( { rules => $opachiddenitems_rules } ) ); + $_->metadata->record; + } @biblios; + + $c->respond_to( + mij => { + status => 200, + format => 'mij', + data => '[' . ( join ',', map { $_->to_mij } @records ) . ']', + }, + any => { + status => 406, + openapi => [ 'application/marc-in-json', ] + } + ); + } + catch { + $c->unhandled_exception($_); + }; +} + =head3 get_public Controller function that handles retrieving a single biblio object @@ -190,13 +250,16 @@ sub get_public { my $marcflavour = C4::Context->preference("marcflavour"); - my $record_processor = Koha::RecordProcessor->new({ - filters => 'ViewPolicy', - options => { - interface => 'opac', - frameworkcode => $biblio->frameworkcode + my $record_processor = Koha::RecordProcessor->new( + { + filters => 'ViewPolicy', + options => { + interface => 'opac', + frameworkcode => $biblio->frameworkcode + } } - }); + ); + # Apply framework's filtering to MARC::Record object $record_processor->process($record); diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index f8cfe00b02..0c3dc6e62a 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -454,6 +454,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 diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 6f7d6972ab..9b69590284 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -289,6 +289,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": @@ -571,6 +573,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 diff --git a/t/db_dependent/api/v1/biblios.t b/t/db_dependent/api/v1/biblios.t index c401b1e1ae..cdab1116d1 100755 --- a/t/db_dependent/api/v1/biblios.t +++ b/t/db_dependent/api/v1/biblios.t @@ -20,7 +20,7 @@ use Modern::Perl; use utf8; use Encode; -use Test::More tests => 11; +use Test::More tests => 12; use Test::MockModule; use Test::Mojo; use Test::Warn; @@ -127,6 +127,61 @@ subtest 'get() 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_items() tests' => sub { plan tests => 8; -- 2.34.1