Browse Source

Bug 16497: 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>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>

Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
19.05.x
Jiří Kozlovský 6 years ago
committed by root
parent
commit
96456cadc2
  1. 141
      Koha/REST/V1/Library.pm
  2. 3
      api/v1/swagger/definitions.json
  3. 86
      api/v1/swagger/definitions/library.json
  4. 3
      api/v1/swagger/parameters.json
  5. 9
      api/v1/swagger/parameters/library.json
  6. 6
      api/v1/swagger/paths.json
  7. 362
      api/v1/swagger/paths/libraries.json
  8. 6
      api/v1/swagger/x-primitives.json
  9. 413
      t/db_dependent/api/v1/libraries.t

141
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;

3
api/v1/swagger/definitions.json

@ -14,6 +14,9 @@
"holds": {
"$ref": "definitions/holds.json"
},
"library": {
"$ref": "definitions/library.json"
},
"patron": {
"$ref": "definitions/patron.json"
},

86
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"]
}

3
api/v1/swagger/parameters.json

@ -8,6 +8,9 @@
"city_id_pp": {
"$ref": "parameters/city.json#/city_id_pp"
},
"branchcodePathParam": {
"$ref": "parameters/library.json#/branchcodePathParam"
},
"holdIdPathParam": {
"$ref": "parameters/hold.json#/holdIdPathParam"
},

9
api/v1/swagger/parameters/library.json

@ -0,0 +1,9 @@
{
"branchcodePathParam": {
"name": "branchcode",
"in": "path",
"description": "Branch identifier code",
"required": true,
"type": "string"
}
}

6
api/v1/swagger/paths.json

@ -20,6 +20,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"
},

362
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"
}
}
}
}
}

6
api/v1/swagger/x-primitives.json

@ -7,6 +7,12 @@
"type": "integer",
"description": "Internal patron identifier"
},
"branchcode": {
"type": "string",
"description": "internally assigned library identifier",
"maxLength": 10,
"minLength": 1
},
"cardnumber": {
"type": ["string", "null"],
"description": "library assigned user identifier"

413
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;
Loading…
Cancel
Save