From c37627e6d4040690e668bf1014d625e6be90170c Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Tue, 13 Jun 2017 14:48:32 +0300 Subject: [PATCH] Bug 18795: DELETE (anonymize) checkout history Anonymize patron's checkout history via REST API DELETE /checkouts/history?borrowernumber=123 To test: 1. prove t/db_dependent/api/v1/checkoutshistory.t 2. Manually send DELETE request to /api/v1/checkouts/history?borrowernumber=123 where 123 is your patron's borrowernumber --- Koha/REST/V1/Checkout.pm | 24 ++++++++++++++ api/v1/swagger/paths/checkouts.json | 54 ++++++++++++++++++++++++++++++ t/db_dependent/api/v1/checkoutshistory.t | 56 +++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/Koha/REST/V1/Checkout.pm b/Koha/REST/V1/Checkout.pm index 480d23f..0db296c 100644 --- a/Koha/REST/V1/Checkout.pm +++ b/Koha/REST/V1/Checkout.pm @@ -279,6 +279,30 @@ sub expanded { return $c->render( status => 200, openapi => $checkouts_json ); } +sub deletehistory { + my $c = shift->openapi->valid_input or return; + + my $borrowernumber = $c->validation->param('borrowernumber'); + my $patron; + return try { + my $patrons = Koha::Patrons->search({ + 'me.borrowernumber' => $borrowernumber + }); + $patrons->anonymise_issue_history; + $patron = $patrons->next; + + return $c->render( status => 200, openapi => {} ); + } + catch { + unless ($patron) { + return $c->render( status => 404, openapi => { + error => "Patron doesn't exist" + }); + } + Koha::Exceptions::rethrow_exception($_); + }; +} + sub _opac_renewal_allowed { my ($user, $borrowernumber) = @_; diff --git a/api/v1/swagger/paths/checkouts.json b/api/v1/swagger/paths/checkouts.json index bbfe491..e67c642 100644 --- a/api/v1/swagger/paths/checkouts.json +++ b/api/v1/swagger/paths/checkouts.json @@ -346,6 +346,60 @@ "circulate_remaining_permissions": "1" } } + }, + "delete": { + "x-mojo-to": "Checkout#deletehistory", + "operationId": "deletehistoryCheckouts", + "tags": ["patrons", "checkouts"], + "parameters": [ + { "$ref": "../parameters.json#/borrowernumberQueryParam" } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Checkout history deleted successfully", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { "$ref": "../definitions.json#/error" } + }, + "404": { + "description": "Borrower not found", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "500": { + "description": "Internal error", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "503": { + "description": "Under maintenance", + "schema": { + "$ref": "../definitions.json#/error" + } + } + }, + "x-koha-authorization": { + "allow-owner": true, + "allow-guarantor": true, + "permissions": { + "circulate_remaining_permissions": "1" + } + } } }, "/checkouts/history/{checkout_id}": { diff --git a/t/db_dependent/api/v1/checkoutshistory.t b/t/db_dependent/api/v1/checkoutshistory.t index 04fa45f..baca549 100644 --- a/t/db_dependent/api/v1/checkoutshistory.t +++ b/t/db_dependent/api/v1/checkoutshistory.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 35; +use Test::More tests => 36; use Test::MockModule; use Test::Mojo; use t::lib::Mocks; @@ -281,6 +281,60 @@ subtest 'test sorting, limit and offset' => sub { ->json_is('/records/3/issue_id' => $issue4->issue_id); }; +subtest 'delete() tests' => sub { + plan tests => 8; + + my $anonymous_patron = $builder->build({ + source => 'Borrower' + })->{borrowernumber}; + t::lib::Mocks::mock_preference('AnonymousPatron', $anonymous_patron); + + my $id = Koha::Old::Checkouts->search({}, { + order_by => {'-desc' => 'issue_id'}})->next; + $id = ($id) ? $id->issue_id+1 : 1; + + my $issue1 = Koha::Old::Checkout->new({ + issue_id => $id, + borrowernumber => $nopermission->{borrowernumber}, + itemnumber => $itemnumber1, + })->store; + my $issue2 = Koha::Old::Checkout->new({ + issue_id => $id+1, + borrowernumber => $nopermission->{borrowernumber}, + itemnumber => $itemnumber1, + })->store; + + $tx = $t->ua->build_tx(DELETE => "/api/v1/checkouts/history" + ."?borrowernumber=".($borrowernumber+1)); + $tx->req->cookies({name => 'CGISESSID', value => $session_nopermission->id}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(DELETE => "/api/v1/checkouts/history" + ."?borrowernumber=".$nopermission->{borrowernumber}); + $tx->req->cookies({name => 'CGISESSID', value => $session_nopermission->id}); + $t->request_ok($tx) + ->status_is(200); + + is(Koha::Old::Checkouts->search({ + borrowernumber => $anonymous_patron, + issue_id => { 'in' => [$id, $id+1] } + })->count, 2, 'Found anonymized checkouts (anonymous patron)'); + + t::lib::Mocks::mock_preference('AnonymousPatron', undef); + + $tx = $t->ua->build_tx(DELETE => "/api/v1/checkouts/history" + ."?borrowernumber=$anonymous_patron"); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $t->request_ok($tx) + ->status_is(200); + + is(Koha::Old::Checkouts->search({ + borrowernumber => undef, + issue_id => { 'in' => [$id, $id+1] } + })->count, 2, 'Found anonymized checkouts (undef patron)'); +}; + Koha::Patrons->find($borrowernumber)->delete(); $tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history?borrowernumber=$borrowernumber"); -- 2.7.4