Bugzilla – Attachment 68746 Details for
Bug 16497
Add routes for library retrieval, update and deletion
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 16497: [REST] Add /api/v1/libraries
Bug-16497-REST-Add-apiv1libraries.patch (text/plain), 37.21 KB, created by
Tomás Cohen Arazi (tcohen)
on 2017-10-27 15:09:12 UTC
(
hide
)
Description:
Bug 16497: [REST] Add /api/v1/libraries
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2017-10-27 15:09:12 UTC
Size:
37.21 KB
patch
obsolete
>From b316a5d62e82f851e0307296821e798ab7bf017b Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kozlovsk=C3=BD?= <mail@jkozlovsky.cz> >Date: Sun, 31 Jul 2016 11:46:57 +0200 >Subject: [PATCH] Bug 16497: [REST] Add /api/v1/libraries > >CRUD for libraries via REST API. > >GET /api/v1/libraries - List all libraries >GET /api/v1/libraries/{branchcode} - Get one Library >POST /api/v1/libraries - Add new Library >DELETE /api/v1/libraries/{branchcode} - Delete Library > >Test plan: > - apply patch > - run tests: t/db_dependent/api/v1/libraries.t > - test API with some API tool or simple curl > >e.g.: >curl http://host:port/api/v1/libraries >curl http://host:port/api/v1/libraries/cpl > >Signed-off-by: Josef Moravec <josef.moravec@gmail.com> >Signed-off-by: Benjamin Rokseth <benjamin.rokseth@kul.oslo.kommune.no> >Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> >--- > Koha/REST/V1/Library.pm | 141 +++++++++++ > api/v1/swagger/definitions.json | 3 + > api/v1/swagger/definitions/library.json | 86 +++++++ > api/v1/swagger/parameters.json | 3 + > api/v1/swagger/parameters/library.json | 9 + > api/v1/swagger/paths.json | 6 + > api/v1/swagger/paths/libraries.json | 362 ++++++++++++++++++++++++++++ > api/v1/swagger/x-primitives.json | 6 + > t/db_dependent/api/v1/libraries.t | 413 ++++++++++++++++++++++++++++++++ > 9 files changed, 1029 insertions(+) > create mode 100644 Koha/REST/V1/Library.pm > create mode 100644 api/v1/swagger/definitions/library.json > create mode 100644 api/v1/swagger/parameters/library.json > create mode 100644 api/v1/swagger/paths/libraries.json > create mode 100644 t/db_dependent/api/v1/libraries.t > >diff --git a/Koha/REST/V1/Library.pm b/Koha/REST/V1/Library.pm >new file mode 100644 >index 0000000..9772217 >--- /dev/null >+++ b/Koha/REST/V1/Library.pm >@@ -0,0 +1,141 @@ >+package Koha::REST::V1::Library; >+ >+# 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 Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+use Koha::Libraries; >+ >+use Scalar::Util qw( blessed ); >+ >+use Try::Tiny; >+ >+sub list { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $libraries; >+ my $filter; >+ my $args = $c->req->params->to_hash; >+ >+ for my $filter_param ( keys %$args ) { >+ $filter->{$filter_param} = { LIKE => $args->{$filter_param} . "%" }; >+ } >+ >+ return try { >+ my $libraries = Koha::Libraries->search($filter); >+ return $c->render( status => 200, openapi => $libraries ); >+ } >+ catch { >+ if ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->{msg} } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+} >+ >+sub get { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $branchcode = $c->validation->param('branchcode'); >+ my $library = Koha::Libraries->find({ branchcode => $branchcode }); >+ unless ($library) { >+ return $c->render( status => 404, >+ openapi => { error => "Library not found" } ); >+ } >+ >+ return $c->render( status => 200, openapi => $library ); >+} >+ >+sub add { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ if (Koha::Libraries->find($c->req->json->{branchcode})) { >+ return $c->render( status => 400, >+ openapi => { error => 'Library already exists' } ); >+ } >+ my $library = Koha::Library->new($c->validation->param('body'))->store; >+ my $branchcode = $library->branchcode; >+ $c->res->headers->location($c->req->url->to_string.'/'.$branchcode); >+ return $c->render( status => 201, openapi => $library); >+ } >+ catch { >+ if ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->{msg} } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+} >+ >+sub update { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $library; >+ return try { >+ $library = Koha::Libraries->find($c->validation->param('branchcode')); >+ $library->set($c->validation->param('body'))->store; >+ return $c->render( status => 200, openapi => $library ); >+ } >+ catch { >+ if ( not defined $library ) { >+ return $c->render( status => 404, >+ openapi => { error => "Object not found" }); >+ } >+ elsif ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->{msg} } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+} >+ >+sub delete { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $library; >+ return try { >+ $library = Koha::Libraries->find($c->validation->param('branchcode')); >+ $library->delete; >+ return $c->render( status => 204, openapi => ''); >+ } >+ catch { >+ if ( not defined $library ) { >+ return $c->render( status => 404, openapi => { error => "Object not found" } ); >+ } >+ elsif ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->{msg} } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+} >+ >+1; >diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json >index 340b9a9..7e3ece6 100644 >--- a/api/v1/swagger/definitions.json >+++ b/api/v1/swagger/definitions.json >@@ -11,6 +11,9 @@ > "holds": { > "$ref": "definitions/holds.json" > }, >+ "library": { >+ "$ref": "definitions/library.json" >+ }, > "patron": { > "$ref": "definitions/patron.json" > }, >diff --git a/api/v1/swagger/definitions/library.json b/api/v1/swagger/definitions/library.json >new file mode 100644 >index 0000000..e16390c >--- /dev/null >+++ b/api/v1/swagger/definitions/library.json >@@ -0,0 +1,86 @@ >+{ >+ "type": "object", >+ "properties": { >+ "branchcode": { >+ "$ref": "../x-primitives.json#/branchcode" >+ }, >+ "branchname": { >+ "type": "string", >+ "description": "Printable name of library" >+ }, >+ "branchaddress1": { >+ "type": ["string", "null"], >+ "description": "the first address line of the library" >+ }, >+ "branchaddress2": { >+ "type": ["string", "null"], >+ "description": "the second address line of the library" >+ }, >+ "branchaddress3": { >+ "type": ["string", "null"], >+ "description": "the third address line of the library" >+ }, >+ "branchzip": { >+ "type": ["string", "null"], >+ "description": "the zip or postal code of the library" >+ }, >+ "branchcity": { >+ "type": ["string", "null"], >+ "description": "the city or province of the library" >+ }, >+ "branchstate": { >+ "type": ["string", "null"], >+ "description": "the reqional state of the library" >+ }, >+ "branchcountry": { >+ "type": ["string", "null"], >+ "description": "the county of the library" >+ }, >+ "branchphone": { >+ "type": ["string", "null"], >+ "description": "the primary phone of the library" >+ }, >+ "branchfax": { >+ "type": ["string", "null"], >+ "description": "the fax number of the library" >+ }, >+ "branchemail": { >+ "type": ["string", "null"], >+ "description": "the primary email address of the library" >+ }, >+ "branchreplyto": { >+ "type": ["string", "null"], >+ "description": "the email to be used as a Reply-To" >+ }, >+ "branchreturnpath": { >+ "type": ["string", "null"], >+ "description": "the email to be used as Return-Path" >+ }, >+ "branchurl": { >+ "type": ["string", "null"], >+ "description": "the URL for your library or branch's website" >+ }, >+ "issuing": { >+ "type": ["integer", "null"], >+ "description": "unused in Koha" >+ }, >+ "branchip": { >+ "type": ["string", "null"], >+ "description": "the IP address for your library or branch" >+ }, >+ "branchprinter": { >+ "type": ["string", "null"], >+ "description": "unused in Koha" >+ }, >+ "branchnotes": { >+ "type": ["string", "null"], >+ "description": "notes related to your library or branch" >+ }, >+ "opac_info": { >+ "type": ["string", "null"], >+ "description": "HTML that displays in OPAC" >+ } >+ }, >+ "additionalProperties": false, >+ "required": ["branchcode", "branchname"] >+} >diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json >index b8835d2..0a756a0 100644 >--- a/api/v1/swagger/parameters.json >+++ b/api/v1/swagger/parameters.json >@@ -5,6 +5,9 @@ > "borrowernumberQueryParam": { > "$ref": "parameters/patron.json#/borrowernumberQueryParam" > }, >+ "branchcodePathParam": { >+ "$ref": "parameters/library.json#/branchcodePathParam" >+ }, > "cityidPathParam": { > "$ref": "parameters/city.json#/cityidPathParam" > }, >diff --git a/api/v1/swagger/parameters/library.json b/api/v1/swagger/parameters/library.json >new file mode 100644 >index 0000000..366581e >--- /dev/null >+++ b/api/v1/swagger/parameters/library.json >@@ -0,0 +1,9 @@ >+{ >+ "branchcodePathParam": { >+ "name": "branchcode", >+ "in": "path", >+ "description": "Branch identifier code", >+ "required": true, >+ "type": "string" >+ } >+} >diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json >index 147e985..b19d960 100644 >--- a/api/v1/swagger/paths.json >+++ b/api/v1/swagger/paths.json >@@ -17,6 +17,12 @@ > "/holds/{reserve_id}": { > "$ref": "paths/holds.json#/~1holds~1{reserve_id}" > }, >+ "/libraries": { >+ "$ref": "paths/libraries.json#/~1libraries" >+ }, >+ "/libraries/{branchcode}": { >+ "$ref": "paths/libraries.json#/~1libraries~1{branchcode}" >+ }, > "/patrons": { > "$ref": "paths/patrons.json#/~1patrons" > }, >diff --git a/api/v1/swagger/paths/libraries.json b/api/v1/swagger/paths/libraries.json >new file mode 100644 >index 0000000..1457788 >--- /dev/null >+++ b/api/v1/swagger/paths/libraries.json >@@ -0,0 +1,362 @@ >+{ >+ "/libraries": { >+ "get": { >+ "x-mojo-to": "Library#list", >+ "operationId": "listLibrary", >+ "tags": ["library"], >+ "parameters": [{ >+ "name": "branchname", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on name", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchaddress1", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on address1", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchaddress2", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on address2", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchaddress3", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on address3", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchzip", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on zipcode", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchcity", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on city", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchstate", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on state", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchcountry", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on country", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchphone", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on phone number", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchfax", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on fax number", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchemail", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on email address", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchreplyto", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on Reply-To email address", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchreturnpath", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on Return-Path email address", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchurl", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on website URL", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "issuing", >+ "in": "query", >+ "description": "Unused in Koha", >+ "required": false, >+ "type": "integer" >+ }, { >+ "name": "branchip", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on IP address", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchprinter", >+ "in": "query", >+ "description": "Unused in Koha", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "branchnotes", >+ "in": "query", >+ "description": "Case insensitive 'starts_with' search on notes", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "opac_info", >+ "in": "query", >+ "description": "Case insensitive 'starts-with' search on OPAC info", >+ "required": false, >+ "type": "string" >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A list of libraries", >+ "schema": { >+ "type": "array", >+ "items": { >+ "$ref": "../definitions.json#/library" >+ } >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ } >+ }, >+ "post": { >+ "x-mojo-to": "Library#add", >+ "operationId": "addLibrary", >+ "tags": ["library"], >+ "parameters": [{ >+ "name": "body", >+ "in": "body", >+ "description": "A JSON object containing informations about the new library", >+ "required": true, >+ "schema": { >+ "$ref": "../definitions.json#/library" >+ } >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "201": { >+ "description": "Library added", >+ "schema": { >+ "$ref": "../definitions.json#/library" >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "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": { >+ "permissions": { >+ "parameters": "parameters_remaining_permissions" >+ } >+ } >+ } >+ }, >+ "/libraries/{branchcode}": { >+ "get": { >+ "x-mojo-to": "Library#get", >+ "operationId": "getLibrary", >+ "tags": ["library"], >+ "parameters": [ >+ { >+ "$ref": "../parameters.json#/branchcodePathParam" >+ } >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A library", >+ "schema": { >+ "$ref": "../definitions.json#/library" >+ } >+ }, >+ "404": { >+ "description": "Library not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ } >+ }, >+ "put": { >+ "x-mojo-to": "Library#update", >+ "operationId": "updateLibrary", >+ "tags": ["library"], >+ "parameters": [{ >+ "$ref": "../parameters.json#/branchcodePathParam" >+ }, { >+ "name": "body", >+ "in": "body", >+ "description": "A JSON object containing information on the library", >+ "required": true, >+ "schema": { >+ "$ref": "../definitions.json#/library" >+ } >+ }], >+ "consumes": [ >+ "application/json" >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A library", >+ "schema": { >+ "$ref": "../definitions.json#/library" >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "Library 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": { >+ "permissions": { >+ "parameters": "parameters_remaining_permissions" >+ } >+ } >+ }, >+ "delete": { >+ "x-mojo-to": "Library#delete", >+ "operationId": "deleteLibrary", >+ "tags": ["library"], >+ "parameters": [{ >+ "$ref": "../parameters.json#/branchcodePathParam" >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "204": { >+ "description": "Library deleted", >+ "schema": { "type": "string" } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "Library 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": { >+ "permissions": { >+ "parameters": "parameters_remaining_permissions" >+ } >+ } >+ } >+ } >+} >diff --git a/api/v1/swagger/x-primitives.json b/api/v1/swagger/x-primitives.json >index 12e5e9d..9b06a5c 100644 >--- a/api/v1/swagger/x-primitives.json >+++ b/api/v1/swagger/x-primitives.json >@@ -7,6 +7,12 @@ > "type": "integer", > "description": "internally assigned user identifier" > }, >+ "branchcode": { >+ "type": "string", >+ "description": "internally assigned library identifier", >+ "maxLength": 10, >+ "minLength": 1 >+ }, > "cardnumber": { > "type": ["string", "null"], > "description": "library assigned user identifier" >diff --git a/t/db_dependent/api/v1/libraries.t b/t/db_dependent/api/v1/libraries.t >new file mode 100644 >index 0000000..7b59610 >--- /dev/null >+++ b/t/db_dependent/api/v1/libraries.t >@@ -0,0 +1,413 @@ >+#!/usr/bin/env perl >+ >+# 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 Modern::Perl; >+ >+use Test::More tests => 5; >+use Test::Mojo; >+use Test::Warn; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use C4::Auth; >+use Koha::Libraries; >+use Koha::Database; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+ >+# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling >+# this affects the other REST api tests >+t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); >+ >+my $remote_address = '127.0.0.1'; >+my $t = Test::Mojo->new('Koha::REST::V1'); >+ >+subtest 'list() tests' => sub { >+ plan tests => 8; >+ >+ $schema->storage->txn_begin; >+ >+ # Create test context >+ my $library = $builder->build( { source => 'Branch' } ); >+ my $another_library = { %$library }; # create a copy of $library but make >+ delete $another_library->{branchcode}; # sure branchcode will be regenerated >+ $another_library = $builder->build( >+ { source => 'Branch', value => $another_library } ); >+ my ( $borrowernumber, $session_id ) = >+ create_user_and_session( { authorized => 0 } ); >+ >+ ## Authorized user tests >+ my $count_of_libraries = Koha::Libraries->search->count; >+ # Make sure we are returned with the correct amount of libraries >+ my $tx = $t->ua->build_tx( GET => '/api/v1/libraries' ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_has('/'.($count_of_libraries-1).'/branchcode') >+ ->json_hasnt('/'.($count_of_libraries).'/branchcode'); >+ >+ subtest 'query parameters' => sub { >+ my @fields = qw( >+ branchname branchaddress1 branchaddress2 branchaddress3 >+ branchzip branchcity branchstate branchcountry >+ branchphone branchfax branchemail branchreplyto >+ branchreturnpath branchurl issuing branchip >+ branchprinter branchnotes opac_info >+ ); >+ plan tests => scalar(@fields)*3; >+ >+ foreach my $field (@fields) { >+ $tx = $t->ua->build_tx( GET => >+ "/api/v1/libraries?$field=$library->{$field}" ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ my $result = >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_has( [ $library, $another_library ] ); >+ } >+ }; >+ >+ # Warn on unsupported query parameter >+ $tx = $t->ua->build_tx( GET => '/api/v1/libraries?library_blah=blah' ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(400) >+ ->json_is( [{ path => '/query/library_blah', message => 'Malformed query string'}] ); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'get() tests' => sub { >+ >+ plan tests => 6; >+ >+ $schema->storage->txn_begin; >+ >+ my $library = $builder->build( { source => 'Branch' } ); >+ my ( $borrowernumber, $session_id ) = >+ create_user_and_session( { authorized => 0 } ); >+ >+ my $tx = $t->ua->build_tx( GET => "/api/v1/libraries/" . $library->{branchcode} ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is($library); >+ >+ my $non_existent_code = 'non_existent'.int(rand(10000)); >+ $tx = $t->ua->build_tx( GET => "/api/v1/libraries/" . $non_existent_code ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(404) >+ ->json_is( '/error' => 'Library not found' ); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'add() tests' => sub { >+ plan tests => 31; >+ >+ $schema->storage->txn_begin; >+ >+ my ( $unauthorized_borrowernumber, $unauthorized_session_id ) = >+ create_user_and_session( { authorized => 0 } ); >+ my ( $authorized_borrowernumber, $authorized_session_id ) = >+ create_user_and_session( { authorized => 1 } ); >+ my $library = { >+ branchcode => "LIBRARYBR1", >+ branchname => "Library Name", >+ branchaddress1 => "Library Address1", >+ branchaddress2 => "Library Address2", >+ branchaddress3 => "Library Address3", >+ branchzip => "Library Zipcode", >+ branchcity => "Library City", >+ branchstate => "Library State", >+ branchcountry => "Library Country", >+ branchphone => "Library Phone", >+ branchfax => "Library Fax", >+ branchemail => "Library Email", >+ branchreplyto => "Library Reply-To", >+ branchreturnpath => "Library Return-Path", >+ branchurl => "http://library.url", >+ issuing => undef, # unused in Koha >+ branchip => "127.0.0.1", >+ branchprinter => "Library Printer", # unused in Koha >+ branchnotes => "Library Notes", >+ opac_info => "<p>Library OPAC info</p>", >+ }; >+ >+ # Unauthorized attempt to write >+ my $tx = $t->ua->build_tx( POST => "/api/v1/libraries" => json => $library ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $unauthorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(403); >+ >+ # Authorized attempt to write invalid data >+ my $library_with_invalid_field = { %$library }; >+ $library_with_invalid_field->{'branchinvalid'} = 'Library invalid'; >+ >+ $tx = $t->ua->build_tx( >+ POST => "/api/v1/libraries" => json => $library_with_invalid_field ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Properties not allowed: branchinvalid.", >+ path => "/body" >+ } >+ ] >+ ); >+ >+ # Authorized attempt to write >+ $tx = $t->ua->build_tx( POST => "/api/v1/libraries" => json => $library ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ my $branchcode = $t->request_ok($tx) >+ ->status_is(201) >+ ->json_is( '/branchname' => $library->{branchname} ) >+ ->json_is( '/branchaddress1' => $library->{branchaddress1} ) >+ ->json_is( '/branchaddress2' => $library->{branchaddress2} ) >+ ->json_is( '/branchaddress3' => $library->{branchaddress3} ) >+ ->json_is( '/branchzip' => $library->{branchzip} ) >+ ->json_is( '/branchcity' => $library->{branchcity} ) >+ ->json_is( '/branchstate' => $library->{branchstate} ) >+ ->json_is( '/branchcountry' => $library->{branchcountry} ) >+ ->json_is( '/branchphone' => $library->{branchphone} ) >+ ->json_is( '/branchfax' => $library->{branchfax} ) >+ ->json_is( '/branchemail' => $library->{branchemail} ) >+ ->json_is( '/branchreplyto' => $library->{branchreplyto} ) >+ ->json_is( '/branchreturnpath' => $library->{branchreturnpath} ) >+ ->json_is( '/branchurl' => $library->{branchurl} ) >+ ->json_is( '/branchip' => $library->{branchip} ) >+ ->json_is( '/branchnotes' => $library->{branchnotes} ) >+ ->json_is( '/opac_info' => $library->{opac_info} ) >+ ->header_is(Location => "/api/v1/libraries/$library->{branchcode}") >+ ->tx->res->json->{branchcode}; >+ >+ # Authorized attempt to create with null id >+ $library->{branchcode} = undef; >+ $tx = $t->ua->build_tx( >+ POST => "/api/v1/libraries" => json => $library ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(400) >+ ->json_has('/errors'); >+ >+ # Authorized attempt to create with existing id >+ $library->{branchcode} = $branchcode; >+ $tx = $t->ua->build_tx( >+ POST => "/api/v1/libraries" => json => $library ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(400) >+ ->json_is('/error' => 'Library already exists'); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'update() tests' => sub { >+ plan tests => 13; >+ >+ $schema->storage->txn_begin; >+ >+ my ( $unauthorized_borrowernumber, $unauthorized_session_id ) = >+ create_user_and_session( { authorized => 0 } ); >+ my ( $authorized_borrowernumber, $authorized_session_id ) = >+ create_user_and_session( { authorized => 1 } ); >+ >+ my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode}; >+ >+ # Unauthorized attempt to update >+ my $tx = $t->ua->build_tx( PUT => "/api/v1/libraries/$branchcode" >+ => json => { branchname => 'New unauthorized name change' } ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $unauthorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(403); >+ >+ # Attempt partial update on a PUT >+ my $library_with_missing_field = { >+ branchaddress1 => "New library address", >+ }; >+ >+ $tx = $t->ua->build_tx( PUT => "/api/v1/libraries/$branchcode" => >+ json => $library_with_missing_field ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(400) >+ ->json_has( "/errors" => >+ [ { message => "Missing property.", path => "/body/branchaddress2" } ] >+ ); >+ >+ # Full object update on PUT >+ my $library_with_updated_field = { >+ branchcode => "LIBRARYBR2", >+ branchname => "Library Name", >+ branchaddress1 => "Library Address1", >+ branchaddress2 => "Library Address2", >+ branchaddress3 => "Library Address3", >+ branchzip => "Library Zipcode", >+ branchcity => "Library City", >+ branchstate => "Library State", >+ branchcountry => "Library Country", >+ branchphone => "Library Phone", >+ branchfax => "Library Fax", >+ branchemail => "Library Email", >+ branchreplyto => "Library Reply-To", >+ branchreturnpath => "Library Return-Path", >+ branchurl => "http://library.url", >+ issuing => undef, # unused in Koha >+ branchip => "127.0.0.1", >+ branchprinter => "Library Printer", # unused in Koha >+ branchnotes => "Library Notes", >+ opac_info => "<p>Library OPAC info</p>", >+ }; >+ >+ $tx = $t->ua->build_tx( >+ PUT => "/api/v1/libraries/$branchcode" => json => $library_with_updated_field ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is( '/branchname' => 'Library Name' ); >+ >+ # Authorized attempt to write invalid data >+ my $library_with_invalid_field = { %$library_with_updated_field }; >+ $library_with_invalid_field->{'branchinvalid'} = 'Library invalid'; >+ >+ $tx = $t->ua->build_tx( >+ PUT => "/api/v1/libraries/$branchcode" => json => $library_with_invalid_field ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Properties not allowed: branchinvalid.", >+ path => "/body" >+ } >+ ] >+ ); >+ >+ my $non_existent_code = 'nope'.int(rand(10000)); >+ $tx = >+ $t->ua->build_tx( PUT => "/api/v1/libraries/$non_existent_code" => json => >+ $library_with_updated_field ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(404); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'delete() tests' => sub { >+ plan tests => 7; >+ >+ $schema->storage->txn_begin; >+ >+ my ( $unauthorized_borrowernumber, $unauthorized_session_id ) = >+ create_user_and_session( { authorized => 0 } ); >+ my ( $authorized_borrowernumber, $authorized_session_id ) = >+ create_user_and_session( { authorized => 1 } ); >+ >+ my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode}; >+ >+ # Unauthorized attempt to delete >+ my $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $unauthorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(403); >+ >+ $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(204) >+ ->content_is(''); >+ >+ $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" ); >+ $tx->req->cookies( >+ { name => 'CGISESSID', value => $authorized_session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(404); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+sub create_user_and_session { >+ >+ my $args = shift; >+ my $flags = ( $args->{authorized} ) ? $args->{authorized} : 0; >+ my $dbh = C4::Context->dbh; >+ >+ my $user = $builder->build( >+ { >+ source => 'Borrower', >+ value => { >+ flags => $flags >+ } >+ } >+ ); >+ >+ # Create a session for the authorized user >+ my $session = C4::Auth::get_session(''); >+ $session->param( 'number', $user->{borrowernumber} ); >+ $session->param( 'id', $user->{userid} ); >+ $session->param( 'ip', '127.0.0.1' ); >+ $session->param( 'lasttime', time() ); >+ $session->flush; >+ >+ if ( $args->{authorized} ) { >+ $dbh->do( " >+ INSERT INTO user_permissions (borrowernumber,module_bit,code) >+ VALUES (?,3,'parameters_remaining_permissions')", undef, >+ $user->{borrowernumber} ); >+ } >+ >+ return ( $user->{borrowernumber}, $session->id ); >+} >+ >+1; >-- >2.7.4
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 16497
:
51454
|
52905
|
53818
|
53819
|
54943
|
60801
|
60802
|
61164
|
61165
|
63160
|
63161
|
66837
|
66838
|
68746
|
68747
|
68748
|
68838
|
68839
|
68840
|
68841
|
69508
|
83913
|
83914
|
83915
|
83916
|
83917
|
83943
|
83945
|
83946
|
83947
|
83948
|
83949
|
84198
|
84588
|
84589
|
84590
|
84591
|
84592
|
84593
|
84734
|
84769