From 4438c4da2e742c9383f30ea9850b8f0a1a3b5712 Mon Sep 17 00:00:00 2001 From: Agustin Moyano Date: Fri, 23 Dec 2022 18:38:04 -0300 Subject: [PATCH] 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: ' 5. Check that the biblio was modified 6. Sign off Signed-off-by: Hammat Wele Signed-off-by: Kyle M Hall Signed-off-by: Tomas Cohen Arazi --- Koha/REST/V1/Biblios.pm | 58 +++- api/v1/swagger/paths/biblios.yaml | 61 ++++ t/db_dependent/api/v1/biblios.t | 443 +++++++++++++++++++++++++++++- 3 files changed, 560 insertions(+), 2 deletions(-) diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index 4f58a4001b..8546afbfd7 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -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; diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index c19ec73380..2480021730 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -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 diff --git a/t/db_dependent/api/v1/biblios.t b/t/db_dependent/api/v1/biblios.t index c5909eece2..5d17ee5ee3 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 => 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| + + + 01102pam a2200289 a 6500 + 2504398 + 20200421093816.0 + 920610s1993 caub s001 0 eng + + 92021731 + + + 05200784384 (Test json) + + + 05200784464 (Test json) + + + DLC + DLC + DLC + + + enggrc + + + PA522 + .M38 1993 + + + 480 + 20 + + + Mastronarde, Donald J. + 389 + + + Introduction to Attic Greek (Using marcxml) / + Donald J. Mastronarde. + + + Berkeley : + University of California Press, + c1993. + + + ix, 425 p. : + maps ; + 26 cm. + + + Includes index. + + + Attic Greek dialect + 7 + + + Contributor biographical information + http://www.loc.gov/catdir/bios/ucal051/92021731.html + + + Publisher description + http://www.loc.gov/catdir/description/ucal041/92021731.html + + + 7 + cbc + orignew + 1 + ocip + 19 + y-gencatlg + + + ddc + BK + + + 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 + + + 3 + 3 + +|; + + 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; }; \ No newline at end of file -- 2.39.5