Bugzilla – Attachment 42115 Details for
Bug 14656
Delete Bibliographic Records REST API route & permission
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14656 - Delete Bibliographic Records REST API route & permission
Bug-14656---Delete-Bibliographic-Records-REST-API-.patch (text/plain), 19.91 KB, created by
Olli-Antti Kivilahti
on 2015-08-31 11:45:57 UTC
(
hide
)
Description:
Bug 14656 - Delete Bibliographic Records REST API route & permission
Filename:
MIME Type:
Creator:
Olli-Antti Kivilahti
Created:
2015-08-31 11:45:57 UTC
Size:
19.91 KB
patch
obsolete
>From 80e69bafae5a61cde114f768eeb4cd4d8c602be1 Mon Sep 17 00:00:00 2001 >From: Olli-Antti Kivilahti <olli-antti.kivilahti@jns.fi> >Date: Thu, 6 Aug 2015 15:17:00 +0300 >Subject: [PATCH] Bug 14656 - Delete Bibliographic Records REST API route & > permission > >Adds a new permission 'editcatalogue' => 'delete_catalogue' and changes the > /cgi-bin/koha/catalogue/detail.pl?biblionumber=XXX -view >to use the REST API to delete a Biblio. > >Includes PageObject tests and REST API tests and atomicupdate-script > >TEST PLAN: > >-1. Reload the REST API daemon. > For Hypnotoad, start the service again to hot-swap code changes. > For other daemonizers follow vendor instructions ;) > >0. Grant delete_catalogue-permission to the logged in user. >1. Find a Biblio. >2. Delete it. >3. Confirm that the biblio is no longer found. >--- > Koha/REST/V1/Biblios.pm | 28 +++++++ > api/v1/swagger.json | 50 +++++++++++ > .../Bug14656-DeleteBibRecordsRESTAPI+Permission.pl | 33 ++++++++ > .../data/mysql/en/mandatory/userpermissions.sql | 1 + > .../intranet-tmpl/prog/en/includes/cat-toolbar.inc | 40 +++++++-- > t/db_dependent/Api/V1/Biblios.pm | 96 ++++++++++++++++++++++ > t/db_dependent/Catalogue/detail.t | 89 ++++++++++++++++++++ > 7 files changed, 328 insertions(+), 9 deletions(-) > create mode 100644 Koha/REST/V1/Biblios.pm > create mode 100644 installer/data/mysql/atomicupdate/Bug14656-DeleteBibRecordsRESTAPI+Permission.pl > create mode 100644 t/db_dependent/Api/V1/Biblios.pm > create mode 100644 t/db_dependent/Catalogue/detail.t > >diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm >new file mode 100644 >index 0000000..8cc125b >--- /dev/null >+++ b/Koha/REST/V1/Biblios.pm >@@ -0,0 +1,28 @@ >+package Koha::REST::V1::Biblios; >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use Koha::Database; >+ >+sub delete_biblio { >+ my ($c, $args, $cb) = @_; >+ >+ my $schema = Koha::Database->new->schema; >+ >+ my $biblio = $schema->resultset('Biblio')->find({biblionumber => $args->{biblionumber}}); >+ unless ($biblio) { >+ return $c->$cb({error => "Biblio not found"}, 404); >+ } >+ >+ my $itemCount = $schema->resultset('Item')->search({biblionumber => $args->{biblionumber}})->count(); >+ if ($itemCount) { >+ return $c->$cb({error => "Biblio has Items attached. Delete them first."}, 400); >+ } >+ >+ $biblio->delete(); >+ return $c->$cb('', 204); >+} >+ >+1; >diff --git a/api/v1/swagger.json b/api/v1/swagger.json >index 47d8a94..bf56a1d 100644 >--- a/api/v1/swagger.json >+++ b/api/v1/swagger.json >@@ -14,6 +14,49 @@ > }, > "basePath": "/v1", > "paths": { >+ "/biblios/{biblionumber}": { >+ "delete": { >+ "x-mojo-controller": "Koha::REST::V1::Biblios", >+ "x-koha-permission": { >+ "editcatalogue": "delete_catalogue" >+ }, >+ "operationId": "deleteBiblio", >+ "tags": ["biblios"], >+ "summary": "Deletes the given Bibliographic Record", >+ "description": "Can fail if there are dependecies to the Biblio.", >+ "produces": [ >+ "" >+ ], >+ "parameters": [ >+ { >+ "$ref": "#/parameters/biblionumberPathParam" >+ } >+ ], >+ "responses": { >+ "204": { >+ "description": "Deleting the Record succeeded.", >+ "schema": { >+ "type": "string" >+ } >+ }, >+ "404": { >+ "description": "No such Bibliographic record found", >+ "schema": { >+ "$ref": "#/definitions/error" >+ } >+ }, >+ "400": { >+ "description": "Cannot delete the Bibliographic Record due to constraints. A constraint can be for example the presence of dependant Items.", >+ "schema": { >+ "$ref": "#/definitions/error" >+ } >+ } >+ }, >+ "security": [ >+ { "multi_key_auth": [] } >+ ] >+ } >+ }, > "/borrowers": { > "get": { > "x-mojo-controller": "Koha::REST::V1::Borrowers", >@@ -459,6 +502,13 @@ > } > }, > "parameters": { >+ "biblionumberPathParam": { >+ "name": "biblionumber", >+ "in": "path", >+ "description": "Internal biblio identifier", >+ "required": true, >+ "type": "integer" >+ }, > "borrowernumberPathParam": { > "name": "borrowernumber", > "in": "path", >diff --git a/installer/data/mysql/atomicupdate/Bug14656-DeleteBibRecordsRESTAPI+Permission.pl b/installer/data/mysql/atomicupdate/Bug14656-DeleteBibRecordsRESTAPI+Permission.pl >new file mode 100644 >index 0000000..5d48e54 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/Bug14656-DeleteBibRecordsRESTAPI+Permission.pl >@@ -0,0 +1,33 @@ >+#!/usr/bin/perl >+ >+# Copyright Open Source Freedom Fighters >+# >+# 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, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use C4::Context; >+use Koha::AtomicUpdater; >+ >+my $dbh = C4::Context->dbh(); >+my $atomicUpdater = Koha::AtomicUpdater->new(); >+ >+unless($atomicUpdater->find('Bug14656')) { >+ >+ use Koha::Auth::PermissionManager; >+ my $pm = Koha::Auth::PermissionManager->new(); >+ $pm->addPermission({module => 'editcatalogue', code => 'delete_catalogue', description => "Allow deleting bibliographic records"}); >+ >+ print "Upgrade done (Bug 14656: Add biblio delete (delete_catalogue) permission.)\n"; >+} >diff --git a/installer/data/mysql/en/mandatory/userpermissions.sql b/installer/data/mysql/en/mandatory/userpermissions.sql >index c8cae26..c7f8b66 100644 >--- a/installer/data/mysql/en/mandatory/userpermissions.sql >+++ b/installer/data/mysql/en/mandatory/userpermissions.sql >@@ -13,6 +13,7 @@ INSERT INTO permissions (module, code, description) VALUES > ( 'reserveforothers','place_holds', 'Place holds for patrons'), > ( 'reserveforothers','modify_holds_priority', 'Modify holds priority'), > ( 'editcatalogue', 'edit_catalogue', 'Edit catalog (Modify bibliographic/holdings data)'), >+ ( 'editcatalogue', 'delete_catalogue', 'Allow deleting bibliographic records'), > ( 'editcatalogue', 'fast_cataloging', 'Fast cataloging'), > ( 'editcatalogue', 'edit_items', 'Edit items'), > ( 'editcatalogue', 'edit_items_restricted', 'Limit item modification to subfields defined in the SubfieldsToAllowForRestrictedEditing preference (please note that edit_item is still required)'), >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc >index ee39f31..888bcce 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc >@@ -27,7 +27,7 @@ > function addToShelf() { window.open('/cgi-bin/koha/virtualshelves/addbybiblionumber.pl?biblionumber=[% biblionumber %]','Add_to_virtualshelf','width=500,height=400,toolbar=false,scrollbars=yes'); > } > function printBiblio() {window.print(); } >-[% IF CAN_user_editcatalogue_edit_catalogue or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] >+[% IF CAN_user_editcatalogue_edit_catalogue or CAN_user_editcatalogue_delete_catalogue or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] > function confirm_deletion() { > var count = [% count %]; > var holdcount = [% holdcount %]; >@@ -60,12 +60,34 @@ > if ( count > 0 || holdcount > 0 ){ > return false; > } else { >- window.location="/cgi-bin/koha/cataloguing/addbiblio.pl?op=delete&biblionumber=[% biblionumber %]"; >+ deleteBiblio([% biblionumber %]); > } > } else { > return false; > } > } >+ function deleteBiblio (biblionumber) { >+ $.ajax({ >+ "cache": false, >+ "headers": {}, >+ "method": "delete", >+ "type":"delete", >+ "url": "/v1/biblios/"+biblionumber, >+ "dataType": "json", >+ "success": function (data, textStatus, jqXHR) { >+ window.location="/cgi-bin/koha/catalogue/search.pl"; >+ }, >+ "error": function (jqXHR, textStatus, errorThrown) { >+ var errorObject = $.parseJSON( jqXHR.responseText ); >+ if (!errorObject || !errorObject.error) { >+ alert(jqXHR.responseText); >+ } >+ else { >+ alert(errorObject.error); >+ } >+ } >+ }); >+ } > [% END %] > > [% IF CAN_user_editcatalogue_edit_items or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] >@@ -135,7 +157,7 @@ > > [% IF ( CAN_user_editcatalogue_edit_catalogue || CAN_user_editcatalogue_edit_items || > CAN_user_serials_create_subscription ) %] >- <div class="btn-group"> >+ <div id="newDropdownContainer" class="btn-group"> > <button class="btn btn-small dropdown-toggle" data-toggle="dropdown"><i class="icon-plus"></i> New <span class="caret"></span></button> > <ul class="dropdown-menu"> > [% IF ( CAN_user_editcatalogue_edit_catalogue ) %] >@@ -159,8 +181,8 @@ CAN_user_serials_create_subscription ) %] > </div> > [% END %] > >-[% IF ( CAN_user_editcatalogue_edit_catalogue || CAN_user_editcatalogue_edit_items || CAN_user_tools_items_batchmod || CAN_user_tools_items_batchdel ) or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] >- <div class="btn-group"> >+[% IF ( CAN_user_editcatalogue_edit_catalogue || CAN_user_editcatalogue_delete_catalogue || CAN_user_editcatalogue_edit_items || CAN_user_tools_items_batchmod || CAN_user_tools_items_batchdel ) or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] >+ <div id="editDropdownContainer" class="btn-group"> > <button class="btn btn-small dropdown-toggle" data-toggle="dropdown"><i class="icon-pencil"></i> Edit <span class="caret"></span></button> > <ul class="dropdown-menu"> > [% IF CAN_user_editcatalogue_edit_catalogue or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] >@@ -197,7 +219,7 @@ CAN_user_serials_create_subscription ) %] > <li><a href="#" id="z3950copy">Replace record via Z39.50/SRU</a></li> > [% END %] > >- [% IF CAN_user_editcatalogue_edit_catalogue or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] >+ [% IF CAN_user_editcatalogue_edit_catalogue or CAN_user_editcatalogue_delete_catalogue or ( frameworkcode == 'FA' and CAN_user_editcatalogue_fast_cataloging ) %] > [% IF ( count ) %] > <li class="disabled"><a id="deletebiblio" data-toggle="tooltip" data-placement="left" title="[% count %] item(s) are attached to this record. You must delete all items before deleting this record." href="#">Delete record</a></li> > [% ELSE %] >@@ -217,7 +239,7 @@ CAN_user_serials_create_subscription ) %] > </div> > [% END %] > >- <div class="btn-group"> >+ <div id="saveDropdownContainer" class="btn-group"> > <button class="btn btn-small dropdown-toggle" data-toggle="dropdown"><i class="icon-download-alt"></i> Save <span class="caret"></span></button> > <ul class="dropdown-menu"> > <li><a href="/cgi-bin/koha/catalogue/export.pl?format=bibtex&op=export&bib=[% biblionumber %]">BIBTEX</a></li> >@@ -232,7 +254,7 @@ CAN_user_serials_create_subscription ) %] > </div> > > [% IF ( virtualshelves && intranetbookbag ) %] >- <div class="btn-group"> >+ <div id="addtoDropdownContainer" class="btn-group"> > <button class="btn btn-small dropdown-toggle" data-toggle="dropdown">Add to <span class="caret"></span></button> > <ul class="dropdown-menu"> > <li><a href="#" id="addtocart">Cart</a></li> >@@ -250,7 +272,7 @@ CAN_user_serials_create_subscription ) %] > [% IF ( CAN_user_reserveforothers ) %] > [% UNLESS ( norequests ) %] > [% IF ( holdfor ) %] >- <div class="btn-group"> >+ <div id="placeholdDropdownContainer" class="btn-group"> > <button class="btn btn-small dropdown-toggle" data-toggle="dropdown"> > <i class="icon-hold"></i> > Place hold >diff --git a/t/db_dependent/Api/V1/Biblios.pm b/t/db_dependent/Api/V1/Biblios.pm >new file mode 100644 >index 0000000..d601602 >--- /dev/null >+++ b/t/db_dependent/Api/V1/Biblios.pm >@@ -0,0 +1,96 @@ >+package t::db_dependent::Api::V1::Biblios; >+ >+use Modern::Perl; >+use Test::More; >+ >+use t::lib::TestObjects::BiblioFactory; >+use t::lib::TestObjects::ItemFactory; >+use t::lib::TestObjects::ObjectFactory; >+ >+sub delete_n_204 { >+ my ($class, $restTest, $driver) = @_; >+ my $testContext = $restTest->get_testContext(); #Test context will be automatically cleaned after this subtest has been executed. >+ my $activeUser = $restTest->get_activeBorrower(); >+ >+ #Create the test context. >+ my $biblios = t::lib::TestObjects::BiblioFactory->createTestGroup( >+ {'biblio.title' => 'The significant chore of building test faculties', >+ 'biblio.author' => 'Programmer, Broken', >+ 'biblio.copyrightdate' => '2015', >+ 'biblioitems.isbn' => '951967151337', >+ 'biblioitems.itemtype' => 'BK', >+ }, undef, $testContext); >+ my $biblionumber = $biblios->{'951967151337'}->{biblionumber}; >+ >+ #Execute request >+ my $path = $restTest->get_routePath(); >+ $path =~ s/\{biblionumber\}/$biblionumber/; >+ $driver->delete_ok($path => {Accept => 'text/json'}); >+ $driver->status_is(204); >+ >+ #Confirm result >+ my $record = C4::Biblio::GetBiblio( $biblios->{'951967151337'}->{biblionumber} ); >+ ok(not($record), "Biblio deletion confirmed"); >+ >+ return 1; >+} >+ >+sub delete_n_404 { >+ my ($class, $restTest, $driver) = @_; >+ my $testContext = $restTest->get_testContext(); #Test context will be automatically cleaned after this subtest has been executed. >+ my $activeUser = $restTest->get_activeBorrower(); >+ >+ #Create the test context. >+ my $biblios = t::lib::TestObjects::BiblioFactory->createTestGroup( >+ {'biblio.title' => 'The significant chore of building test faculties', >+ 'biblio.author' => 'Programmer, Broken', >+ 'biblio.copyrightdate' => '2015', >+ 'biblioitems.isbn' => '951967151337', >+ 'biblioitems.itemtype' => 'BK', >+ }, undef, $testContext); >+ my $biblionumber = $biblios->{'951967151337'}->{biblionumber}; >+ C4::Biblio::DelBiblio($biblionumber); >+ #Now we have a biblionumber which certainly doesn't exists! >+ >+ #Execute request >+ my $path = $restTest->get_routePath(); >+ $path =~ s/\{biblionumber\}/$biblionumber/; >+ $driver->delete_ok($path => {Accept => 'text/json'}); >+ $driver->status_is(404); >+ >+ return 1; >+} >+ >+sub delete_n_400 { >+ my ($class, $restTest, $driver) = @_; >+ my $testContext = $restTest->get_testContext(); #Test context will be automatically cleaned after this subtest has been executed. >+ my $activeUser = $restTest->get_activeBorrower(); >+ >+ #Create the test context. >+ my $biblios = t::lib::TestObjects::BiblioFactory->createTestGroup( >+ {'biblio.title' => 'The significant chore of building test faculties', >+ 'biblio.author' => 'Programmer, Broken', >+ 'biblio.copyrightdate' => '2015', >+ 'biblioitems.isbn' => '951967151337', >+ 'biblioitems.itemtype' => 'BK', >+ }, undef, $testContext); >+ my $biblionumber = $biblios->{'951967151337'}->{biblionumber}; >+ my $items = t::lib::TestObjects::ItemFactory->createTestGroup([ >+ {biblionumber => $biblionumber, >+ barcode => '11N01'} >+ ], undef, $testContext); >+ >+ #Execute request >+ my $path = $restTest->get_routePath(); >+ $path =~ s/\{biblionumber\}/$biblionumber/; >+ $driver->delete_ok($path => {Accept => 'text/json'}); >+ $driver->status_is(400); >+ >+ #Confirm result >+ my $record = C4::Biblio::GetBiblio( $biblios->{'951967151337'}->{biblionumber} ); >+ ok($record, "Biblio deletion aborted due to attached Items"); >+ >+ return 1; >+} >+ >+1; >\ No newline at end of file >diff --git a/t/db_dependent/Catalogue/detail.t b/t/db_dependent/Catalogue/detail.t >new file mode 100644 >index 0000000..0976be3 >--- /dev/null >+++ b/t/db_dependent/Catalogue/detail.t >@@ -0,0 +1,89 @@ >+#!/usr/bin/perl >+ >+# Copyright 2015 Open Source Freedom Fighters >+# >+# 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 <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::More; >+use Scalar::Util qw(blessed); >+ >+use t::lib::Page::Catalogue::Detail; >+use t::lib::TestObjects::BorrowerFactory; >+use t::lib::TestObjects::BiblioFactory; >+use Koha::Auth::PermissionManager; >+ >+ >+##Setting up the test context >+my $testContext = {}; >+ >+my $password = '1234'; >+my $borrowerFactory = t::lib::TestObjects::BorrowerFactory->new(); >+my $borrowers = $borrowerFactory->createTestGroup([ >+ {firstname => 'Polli-Pantti', >+ surname => 'Pipi', >+ cardnumber => '1A01', >+ branchcode => 'CPL', >+ userid => 'pipi_padmin', >+ password => $password, >+ }, >+ ], undef, $testContext); >+ >+##Test context set, starting testing: >+eval { #run in a eval-block so we don't die without tearing down the test context >+ >+ subtest "Test Delete Biblio" => sub { >+ testDeleteBiblio(); >+ }; >+ >+}; >+if ($@) { #Catch all leaking errors and gracefully terminate. >+ warn $@; >+ tearDown(); >+ exit 1; >+} >+ >+##All tests done, tear down test context >+tearDown(); >+done_testing; >+ >+sub tearDown { >+ t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); >+} >+ >+sub testDeleteBiblio { >+ my $permissionManager = Koha::Auth::PermissionManager->new(); >+ $permissionManager->grantPermissions($borrowers->{'1A01'}, {catalogue => 'staff_login', >+ editcatalogue => 'delete_catalogue', >+ }); >+ my $biblios = t::lib::TestObjects::BiblioFactory->createTestGroup( >+ {'biblio.title' => 'The significant chore of building test faculties', >+ 'biblio.author' => 'Programmer, Broken', >+ 'biblio.copyrightdate' => '2015', >+ 'biblioitems.isbn' => '951967151337', >+ 'biblioitems.itemtype' => 'BK', >+ }, undef, $testContext); >+ >+ my $detail = t::lib::Page::Catalogue::Detail->new({biblionumber => $biblios->{'951967151337'}->{biblionumber}}); >+ >+ $detail->doPasswordLogin($borrowers->{'1A01'}->userid, $password) >+ ->isBiblioMatch($biblios->{'951967151337'}) >+ ->deleteBiblio(); >+ >+ my $record = C4::Biblio::GetBiblio( $biblios->{'951967151337'}->{biblionumber} ); >+ ok(not($record), "Biblio deletion confirmed"); >+} >\ No newline at end of file >-- >1.9.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14656
:
41550
|
42115
|
42329
|
42834