From ba2da493f40dbf62d7a8903832edf4d348c80cdc Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Mon, 22 Aug 2016 17:35:44 +0300 Subject: [PATCH] Bug 17003: Add API route to get checkout's renewability GET /checkouts/{checkout_id}/renewability (renewability status) Response: - 200: renewability { renewable: true/false, error: "error message" } To test: 1. Login to Koha 2. Checkout something for yourself 3. Make GET request to http://yourlibrary/api/v1/checkouts/YYY/renewability where YYY is checkout_id of your checkout. 4. Observe returned data. If not renewable, an error should also be presented. 5. Run t/db_dependent/api/v1/checkouts.t Signed-off-by: Jiri Kozlovsky I've signed-off this because I've made no major change and the funcionality remains the same. Changes made: 1. Added x-koha-authorization to the paths definition 2. Changed checkout_id parameter definition to the reference 3. Moved error raised when syspref OpacRenewalAllowed disabled in front of possible error "Checkout doesn't exist" (don't give users hope to renew it when not found, but tell them renewal is not allowed at all instead) --- Koha/REST/V1/Checkout.pm | 35 ++++++++++++++++++++++++++++ api/v1/swagger/definitions.json | 3 +++ api/v1/swagger/definitions/renewability.json | 13 +++++++++++ api/v1/swagger/paths.json | 3 +++ api/v1/swagger/paths/checkouts.json | 31 ++++++++++++++++++++++++ t/db_dependent/api/v1/checkouts.t | 14 ++++++++++- 6 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 api/v1/swagger/definitions/renewability.json diff --git a/Koha/REST/V1/Checkout.pm b/Koha/REST/V1/Checkout.pm index a454fc4..e50ad4a 100644 --- a/Koha/REST/V1/Checkout.pm +++ b/Koha/REST/V1/Checkout.pm @@ -16,6 +16,7 @@ package Koha::REST::V1::Checkout; # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. use Mojo::Base 'Mojolicious::Controller'; +use Mojo::JSON; use C4::Auth qw( haspermission ); use C4::Context; @@ -124,6 +125,40 @@ sub renew { ); } +sub renewability { + my ($c, $args, $cb) = @_; + + my $user = $c->stash('koha.user'); + + my $OpacRenewalAllowed; + if ($user->borrowernumber == $borrowernumber) { + $OpacRenewalAllowed = C4::Context->preference('OpacRenewalAllowed'); + } + + unless ($user && ($OpacRenewalAllowed + || haspermission($user->userid, { circulate => "circulate_remaining_permissions" }))) { + return $c->$cb({error => "You don't have the required permission"}, 403); + } + + my $checkout_id = $args->{checkout_id}; + my $checkout = Koha::Issues->find($checkout_id); + + if (!$checkout) { + return $c->$cb({ + error => "Checkout doesn't exist" + }, 404); + } + + my $borrowernumber = $checkout->borrowernumber; + my $itemnumber = $checkout->itemnumber; + + my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed( + $borrowernumber, $itemnumber); + + return $c->$cb({ renewable => Mojo::JSON->true, error => undef }, 200) if $can_renew; + return $c->$cb({ renewable => Mojo::JSON->false, error => $error }, 200); +} + =head3 _to_api Helper function that maps a hashref of Koha::Checkout attributes into REST api diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json index afcf6fb..a7dea01 100644 --- a/api/v1/swagger/definitions.json +++ b/api/v1/swagger/definitions.json @@ -32,6 +32,9 @@ "patron_balance": { "$ref": "definitions/patron_balance.json" }, + "renewability": { + "$ref": "definitions/renewability.json" + }, "vendor": { "$ref": "definitions/vendor.json" } diff --git a/api/v1/swagger/definitions/renewability.json b/api/v1/swagger/definitions/renewability.json new file mode 100644 index 0000000..654691e --- /dev/null +++ b/api/v1/swagger/definitions/renewability.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "renewable": { + "type": "boolean", + "description": "Renewability status; true = renewable, false = not renewable" + }, + "error": { + "type": ["string", "null"], + "description": "Description on false renewability." + } + } +} diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json index 607ff12..92d2626 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -35,6 +35,9 @@ "/libraries/{library_id}": { "$ref": "paths/libraries.json#/~1libraries~1{library_id}" }, + "/checkouts/{checkout_id}/renewability": { + "$ref": "paths/checkouts.json#/~1checkouts~1{checkout_id}~1renewability" + }, "/patrons": { "$ref": "paths/patrons.json#/~1patrons" }, diff --git a/api/v1/swagger/paths/checkouts.json b/api/v1/swagger/paths/checkouts.json index 6324d75..e4adfed 100644 --- a/api/v1/swagger/paths/checkouts.json +++ b/api/v1/swagger/paths/checkouts.json @@ -92,5 +92,36 @@ } } } + }, + "/checkouts/{checkout_id}/renewability": { + "get": { + "operationId": "renewabilityCheckout", + "tags": ["patrons", "checkouts"], + "parameters": [{ + "$ref": "../parameters.json#/checkoutIdPathParam" + }], + "produces": ["application/json"], + "responses": { + "200": { + "description": "Checkout renewability", + "schema": { "$ref": "../definitions.json#/renewability" } + }, + "403": { + "description": "Forbidden", + "schema": { "$ref": "../definitions.json#/error" } + }, + "404": { + "description": "Checkout not found", + "schema": { "$ref": "../definitions.json#/error" } + } + }, + "x-koha-authorization": { + "allow-owner": true, + "allow-guarantor": true, + "permissions": { + "circulate": "circulate_remaining_permissions" + } + } + } } } diff --git a/t/db_dependent/api/v1/checkouts.t b/t/db_dependent/api/v1/checkouts.t index a6f340b..77c1ee9 100644 --- a/t/db_dependent/api/v1/checkouts.t +++ b/t/db_dependent/api/v1/checkouts.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 51; +use Test::More tests => 57; use Test::MockModule; use Test::Mojo; use t::lib::Mocks; @@ -146,6 +146,12 @@ $t->post_ok( "//$unauth_userid:$unauth_password@/api/v1/checkouts/" . $issue3->i required_permissions => { circulate => "circulate_remaining_permissions" } }); +$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue2->issue_id . "/renewability"); +$tx->req->cookies({name => 'CGISESSID', value => $patron_session->id}); +$t->request_ok($tx) + ->status_is(200) + ->json_is({ renewable => Mojo::JSON->true, error => undef }); + $t->post_ok( "//$userid:$password@/api/v1/checkouts/" . $issue2->issue_id . "/renewal" ) ->status_is(200) ->json_is('/due_date' => output_pref({ dateformat => "rfc3339", dt => $expected_datedue}) ); @@ -154,3 +160,9 @@ $t->post_ok( "//$userid:$password@/api/v1/checkouts/" . $issue1->issue_id . "/re ->status_is(403) ->json_is({ error => 'Renewal not authorized (too_many)' }); +$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue2->issue_id . "/renewability"); +$tx->req->cookies({name => 'CGISESSID', value => $patron_session->id}); +$t->request_ok($tx) + ->status_is(200) + ->json_is({ renewable => Mojo::JSON->false, error => 'too_many' }); + -- 2.1.4