From b099568df7300ef478cbd1b09cc027954bca795a Mon Sep 17 00:00:00 2001 From: Julian Maurice Date: Wed, 18 May 2022 11:50:07 +0200 Subject: [PATCH] Bug 30799: Add REST API route to update biblio metadata Example: PUT /api/v1/biblios/{biblio_id}/metadata ... Calling this endpoint will replace the current MARC record with the one given in the request body, by calling C4::Biblio::ModBiblio Test plan: 1. Try requesting this endpoint with your favorite API tool 2. Run `prove t/db_dependent/api/v1/biblios/metadata/put.t` Signed-off-by: Paul Derscheid --- Koha/REST/V1/Biblios.pm | 36 ++++++++ api/v1/swagger/paths/biblios.yaml | 49 +++++++++++ api/v1/swagger/swagger.yaml | 2 + t/db_dependent/api/v1/biblios/metadata/put.t | 90 ++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 t/db_dependent/api/v1/biblios/metadata/put.t diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index c74f5180c6..435057f75f 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -409,4 +409,40 @@ sub get_items_public { }; } +=head3 setMetadata + +Updates biblio metadata + +=cut + +sub setMetadata { + my $c = shift->openapi->valid_input or return; + + my $biblio = Koha::Biblios->find( $c->validation->param('biblio_id') ); + + if ( not defined $biblio ) { + return $c->render( + status => 404, + openapi => { error => "Object not found" } + ); + } + + my $marcxml = $c->validation->param('body'); + my $format = C4::Context->preference('marcflavour') eq 'UNIMARC' ? 'UNIMARC' : 'MARC21'; + my $record = eval { MARC::Record->new_from_xml($marcxml, 'UTF-8', $format) }; + if ($@) { + return $c->render(status => 400, openapi => { error => "$@" }); + } + + my $success = eval { C4::Biblio::ModBiblio( $record, $biblio->id, $biblio->frameworkcode ) }; + if (!$success || $@) { + return $c->render( + status => 500, + openapi => { error => "$@" || "Internal server error" } + ); + } + + return $c->render( status => 204, openapi => "" ); +} + 1; diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index 60e4e951a4..bf319e6d72 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -217,6 +217,55 @@ x-koha-authorization: permissions: catalogue: "1" +"/biblios/{biblio_id}/metadata": + parameters: + - $ref: "../swagger.yaml#/parameters/biblio_id_pp" + put: + x-mojo-to: Biblios#setMetadata + operationId: setBiblioMetadata + tags: + - biblios + summary: Set biblio metadata + parameters: + - name: body + in: body + required: true + schema: + type: string + produces: + - application/json + responses: + "204": + description: Biblio metadata updated + schema: + type: string + "400": + description: Bad request + schema: + $ref: "../swagger.yaml#/definitions/error" + "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" + "500": + description: Internal error + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + editcatalogue: edit_catalogue "/biblios/{biblio_id}/pickup_locations": get: x-mojo-to: Biblios#pickup_locations diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 1ec3a5687d..caeaea29ab 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -99,6 +99,8 @@ paths: $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}~1checkouts" "/biblios/{biblio_id}/items": $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}~1items" + "/biblios/{biblio_id}/metadata": + $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}~1metadata" "/biblios/{biblio_id}/pickup_locations": $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}~1pickup_locations" "/cash_registers/{cash_register_id}/cashups": diff --git a/t/db_dependent/api/v1/biblios/metadata/put.t b/t/db_dependent/api/v1/biblios/metadata/put.t new file mode 100644 index 0000000000..0af4868ccb --- /dev/null +++ b/t/db_dependent/api/v1/biblios/metadata/put.t @@ -0,0 +1,90 @@ +#!/usr/bin/env perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use utf8; +use Encode; + +use Test::More tests => 1; +use Test::MockModule; +use Test::Mojo; +use Test::Warn; +use JSON; + +use t::lib::Mocks; +use t::lib::TestBuilder; + +use C4::Auth; + +use Koha::Biblios; +use Koha::Database; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); + +my $t = Test::Mojo->new('Koha::REST::V1'); + +subtest 'PUT /api/v1/biblios/{biblio_id}/metadata' => sub { + plan tests => 10; + + $schema->storage->txn_begin; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + my $password = 'thePassword123'; + $patron->set_password( { password => $password, skip_validation => 1 } ); + $patron->discard_changes; + my $userid = $patron->userid; + + my $biblio = $builder->build_sample_biblio({ + title => 'The unbearable lightness of being', + author => 'Milan Kundera', + }); + my $biblio_id = $biblio->id; + + $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/metadata") + ->status_is(403); + + $patron->flags(9)->store; + + $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/metadata") + ->status_is(400); + + $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/metadata", "not marcxml") + ->status_is(400) + ->json_like('/error', qr/parser error/); + + my $biblio2 = $builder->build_sample_biblio({ + 'title' => 'Another title', + }); + my $record2 = $biblio2->metadata->record; + + $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/metadata", $record2->as_xml_record) + ->status_is(204); + + $biblio->discard_changes; + is($biblio->title, 'Another title'); + + $schema->storage->txn_rollback; +}; -- 2.20.1