Bug 31801: Add REST endpoint to modify a biblio

To test:
1. Apply patch
2. Set RESTBasicAuth preference to true
3. Pick a biblio to modify, and modify it's marc record
4. Make a PUT request to /api/v1/biblios/:biblionumber with one of the following content type header
  - application/marcxml+xml
  - application/marc-in-json
  - application/marc
5. Add the following header in the request 'x-framework-id: <framework id>'
5. Check that the biblio was modified
6. Sign off

Signed-off-by: Hammat Wele <hammat.wele@inlibro.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Agustin Moyano 2022-12-23 18:38:04 -03:00 committed by Tomas Cohen Arazi
parent 587615fd9f
commit 4438c4da2e
Signed by: tomascohen
GPG key ID: 0A272EA1B2F3C15F
3 changed files with 560 additions and 2 deletions

View file

@ -22,7 +22,7 @@ use Mojo::Base 'Mojolicious::Controller';
use Koha::Biblios;
use Koha::Ratings;
use Koha::RecordProcessor;
use C4::Biblio qw( DelBiblio AddBiblio );
use C4::Biblio qw( DelBiblio AddBiblio ModBiblio );
use C4::Search qw( FindDuplicate );
use List::MoreUtils qw( any );
@ -541,4 +541,60 @@ sub add {
};
}
=head3 update
Controller function that handles modifying an biblio object
=cut
sub update {
my $c = shift->openapi->valid_input or return;
my $biblionumber = $c->validation->param('biblio_id');
my $biblio = Koha::Biblios->find( $biblionumber );
if ( not defined $biblio ) {
return $c->render(
status => 404,
openapi => { error => "Object not found" }
);
}
try {
my $body = $c->validation->param('Body');
my $flavour = $c->validation->param('x-marc-schema');
$flavour = C4::Context->preference('marcflavour') unless $flavour;
my $record;
my $frameworkcode = $c->validation->param('x-framework-id') || $biblio->frameworkcode;
if ( $c->req->headers->content_type =~ m/application\/marcxml\+xml/ ) {
$record = MARC::Record->new_from_xml( $body, 'UTF-8', $flavour );
} elsif ( $c->req->headers->content_type =~ m/application\/marc-in-json/ ) {
$record = MARC::Record->new_from_mij_structure( $body );
} elsif ( $c->req->headers->content_type =~ m/application\/marc/ ) {
$record = MARC::Record->new_from_usmarc( $body );
} else {
return $c->render(
status => 406,
openapi => [
"application/json",
"application/marcxml+xml",
"application/marc-in-json",
"application/marc"
]
);
}
ModBiblio( $record, $biblionumber, $frameworkcode );
$c->render(
status => 200,
openapi => { id => $biblionumber }
);
}
catch {
$c->unhandled_exception($_);
};
}
1;

View file

@ -149,6 +149,67 @@
x-koha-authorization:
permissions:
editcatalogue: edit_catalogue
put:
x-mojo-to: Biblios#update
operationId: updateBiblio
tags:
- biblios
summary: Update biblio
parameters:
- $ref: "../swagger.yaml#/parameters/biblio_id_pp"
- name: Body
in: body
description: A JSON object or the Marc string describing a biblio
required: true
schema:
type:
- string
- object
- $ref: "../swagger.yaml#/parameters/framework_id_header"
- $ref: "../swagger.yaml#/parameters/marc_schema_header"
- $ref: "../swagger.yaml#/parameters/confirm_not_duplicate_header"
produces:
- application/json
responses:
"200":
description: A biblio
"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"
"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"
x-koha-authorization:
permissions:
editcatalogue: edit_catalogue
"/biblios/{biblio_id}/checkouts":
get:
x-mojo-to: Biblios#get_checkouts

View file

@ -20,7 +20,7 @@ use Modern::Perl;
use utf8;
use Encode;
use Test::More tests => 9;
use Test::More tests => 10;
use Test::MockModule;
use Test::Mojo;
use Test::Warn;
@ -1140,5 +1140,446 @@ subtest 'post() tests' => sub {
->status_is(200)
->json_has('/id');
$schema->storage->txn_rollback;
};
subtest 'put() tests' => sub {
plan tests => 14;
$schema->storage->txn_begin;
my $patron = $builder->build_object(
{
class => 'Koha::Patrons',
value => { flags => 0 } # no permissions
}
);
my $password = 'thePassword123';
$patron->set_password( { password => $password, skip_validation => 1 } );
my $userid = $patron->userid;
my $frameworkcode = 'BKS';
my $biblio = $builder->build_sample_biblio({frameworkcode => $frameworkcode});
my $biblionumber = $biblio->biblionumber;
my $marcxml = q|<?xml version="1.0" encoding="UTF-8"?>
<record
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
xmlns="http://www.loc.gov/MARC21/slim">
<leader>01102pam a2200289 a 6500</leader>
<controlfield tag="001">2504398</controlfield>
<controlfield tag="005">20200421093816.0</controlfield>
<controlfield tag="008">920610s1993 caub s001 0 eng </controlfield>
<datafield tag="010" ind1=" " ind2=" ">
<subfield code="a"> 92021731 </subfield>
</datafield>
<datafield tag="020" ind1=" " ind2=" ">
<subfield code="a">05200784384 (Test json)</subfield>
</datafield>
<datafield tag="020" ind1=" " ind2=" ">
<subfield code="a">05200784464 (Test json)</subfield>
</datafield>
<datafield tag="040" ind1=" " ind2=" ">
<subfield code="a">DLC</subfield>
<subfield code="c">DLC</subfield>
<subfield code="d">DLC</subfield>
</datafield>
<datafield tag="041" ind1="0" ind2=" ">
<subfield code="a">enggrc</subfield>
</datafield>
<datafield tag="050" ind1="0" ind2="0">
<subfield code="a">PA522</subfield>
<subfield code="b">.M38 1993</subfield>
</datafield>
<datafield tag="082" ind1="0" ind2="0">
<subfield code="a">480</subfield>
<subfield code="2">20</subfield>
</datafield>
<datafield tag="100" ind1="1" ind2=" ">
<subfield code="a">Mastronarde, Donald J.</subfield>
<subfield code="9">389</subfield>
</datafield>
<datafield tag="245" ind1="1" ind2="0">
<subfield code="a">Introduction to Attic Greek (Using marcxml) /</subfield>
<subfield code="c">Donald J. Mastronarde.</subfield>
</datafield>
<datafield tag="260" ind1=" " ind2=" ">
<subfield code="a">Berkeley :</subfield>
<subfield code="b">University of California Press,</subfield>
<subfield code="c">c1993.</subfield>
</datafield>
<datafield tag="300" ind1=" " ind2=" ">
<subfield code="a">ix, 425 p. :</subfield>
<subfield code="b">maps ;</subfield>
<subfield code="c">26 cm.</subfield>
</datafield>
<datafield tag="500" ind1=" " ind2=" ">
<subfield code="a">Includes index.</subfield>
</datafield>
<datafield tag="650" ind1=" " ind2="0">
<subfield code="a">Attic Greek dialect</subfield>
<subfield code="9">7</subfield>
</datafield>
<datafield tag="856" ind1="4" ind2="2">
<subfield code="3">Contributor biographical information</subfield>
<subfield code="u">http://www.loc.gov/catdir/bios/ucal051/92021731.html</subfield>
</datafield>
<datafield tag="856" ind1="4" ind2="2">
<subfield code="3">Publisher description</subfield>
<subfield code="u">http://www.loc.gov/catdir/description/ucal041/92021731.html</subfield>
</datafield>
<datafield tag="906" ind1=" " ind2=" ">
<subfield code="a">7</subfield>
<subfield code="b">cbc</subfield>
<subfield code="c">orignew</subfield>
<subfield code="d">1</subfield>
<subfield code="e">ocip</subfield>
<subfield code="f">19</subfield>
<subfield code="g">y-gencatlg</subfield>
</datafield>
<datafield tag="942" ind1=" " ind2=" ">
<subfield code="2">ddc</subfield>
<subfield code="c">BK</subfield>
</datafield>
<datafield tag="955" ind1=" " ind2=" ">
<subfield code="a">pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93</subfield>
</datafield>
<datafield tag="999" ind1=" " ind2=" ">
<subfield code="c">3</subfield>
<subfield code="d">3</subfield>
</datafield>
</record>|;
my $mij = q|{
"fields": [
{
"001": "2504398"
},
{
"005": "20200421093816.0"
},
{
"008": "920610s1993 caub s001 0 eng "
},
{
"010": {
"ind1": " ",
"subfields": [
{
"a": " 92021731 "
}
],
"ind2": " "
}
},
{
"020": {
"subfields": [
{
"a": "05200784382 (Test mij)"
}
],
"ind2": " ",
"ind1": " "
}
},
{
"020": {
"subfields": [
{
"a": "05200784462 (Test mij)"
}
],
"ind1": " ",
"ind2": " "
}
},
{
"040": {
"subfields": [
{
"a": "DLC"
},
{
"c": "DLC"
},
{
"d": "DLC"
}
],
"ind2": " ",
"ind1": " "
}
},
{
"041": {
"ind2": " ",
"subfields": [
{
"a": "enggrc"
}
],
"ind1": "0"
}
},
{
"050": {
"subfields": [
{
"a": "PA522"
},
{
"b": ".M38 1993"
}
],
"ind1": "0",
"ind2": "0"
}
},
{
"082": {
"subfields": [
{
"a": "480"
},
{
"2": "20"
}
],
"ind2": "0",
"ind1": "0"
}
},
{
"100": {
"ind2": " ",
"subfields": [
{
"a": "Mastronarde, Donald J."
},
{
"9": "389"
}
],
"ind1": "1"
}
},
{
"245": {
"ind1": "1",
"subfields": [
{
"a": "Introduction to Attic Greek (Using mij) /"
},
{
"c": "Donald J. Mastronarde."
}
],
"ind2": "0"
}
},
{
"260": {
"subfields": [
{
"a": "Berkeley :"
},
{
"b": "University of California Press,"
},
{
"c": "c1993."
}
],
"ind2": " ",
"ind1": " "
}
},
{
"300": {
"ind1": " ",
"subfields": [
{
"a": "ix, 425 p. :"
},
{
"b": "maps ;"
},
{
"c": "26 cm."
}
],
"ind2": " "
}
},
{
"500": {
"subfields": [
{
"a": "Includes index."
}
],
"ind1": " ",
"ind2": " "
}
},
{
"650": {
"subfields": [
{
"a": "Attic Greek dialect"
},
{
"9": "7"
}
],
"ind2": "0",
"ind1": " "
}
},
{
"856": {
"subfields": [
{
"3": "Contributor biographical information"
},
{
"u": "http://www.loc.gov/catdir/bios/ucal051/92021731.html"
}
],
"ind2": "2",
"ind1": "4"
}
},
{
"856": {
"ind1": "4",
"subfields": [
{
"3": "Publisher description"
},
{
"u": "http://www.loc.gov/catdir/description/ucal041/92021731.html"
}
],
"ind2": "2"
}
},
{
"906": {
"subfields": [
{
"a": "7"
},
{
"b": "cbc"
},
{
"c": "orignew"
},
{
"d": "1"
},
{
"e": "ocip"
},
{
"f": "19"
},
{
"g": "y-gencatlg"
}
],
"ind1": " ",
"ind2": " "
}
},
{
"942": {
"subfields": [
{
"2": "ddc"
},
{
"c": "BK"
}
],
"ind2": " ",
"ind1": " "
}
},
{
"955": {
"subfields": [
{
"a": "pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93"
}
],
"ind2": " ",
"ind1": " "
}
},
{
"999": {
"subfields": [
{
"c": "3"
},
{
"d": "3"
}
],
"ind1": " ",
"ind2": " "
}
}
],
"leader": "01102pam a2200289 a 8500"
}|;
my $marc = q|01116pam a2200289 a 4500001000800000005001700008008004100025010001700066020002800083020002800111040001800139041001100157050002100168082001200189100003200201245007500233260005600308300003300364500002000397650002700417856009500444856008700539906004500626942001200671955013000683999001300813250439820221223213433.0920610s1993 caub s001 0 eng  a 92021731  a05200784384 (Test json) a05200784464 (Test json) aDLCcDLCdDLC0 aenggrc00aPA522b.M38 199300a4802201 aMastronarde, Donald J.938910aIntroduction to Attic Greek (Using usmarc) /cDonald J. Mastronarde. aBerkeley :bUniversity of California Press,cc1993. aix, 425 p. :bmaps ;c26 cm. aIncludes index. 0aAttic Greek dialect97423Contributor biographical informationuhttp://www.loc.gov/catdir/bios/ucal051/92021731.html423Publisher descriptionuhttp://www.loc.gov/catdir/description/ucal041/92021731.html a7bcbccorignewd1eocipf19gy-gencatlg 2ddccBK apc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93 c715d715|;
$t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber")
->status_is(403, 'Not enough permissions makes it return the right code');
# Add permissions
$builder->build(
{
source => 'UserPermission',
value => {
borrowernumber => $patron->borrowernumber,
module_bit => 9,
code => 'edit_catalogue'
}
}
);
$t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber" => {'Content-Type' => 'application/marcxml+xml', 'x-framework-id' => $frameworkcode} => $marcxml)
->status_is(200)
->json_has('/id');
$biblio = Koha::Biblios->find($biblionumber);
is($biblio->title, 'Introduction to Attic Greek (Using marcxml) /');
$t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber" => {'Content-Type' => 'application/marc-in-json', 'x-framework-id' => $frameworkcode} => $mij)
->status_is(200)
->json_has('/id');
$biblio = Koha::Biblios->find($biblionumber);
is($biblio->title, 'Introduction to Attic Greek (Using mij) /');
$t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber" => {'Content-Type' => 'application/marc', 'x-framework-id' => $frameworkcode} => $marc)
->status_is(200)
->json_has('/id');
$biblio = Koha::Biblios->find($biblionumber);
is($biblio->title, 'Introduction to Attic Greek (Using usmarc) /');
$schema->storage->txn_rollback;
};