]> git.koha-community.org Git - koha.git/blob - t/db_dependent/api/v1/libraries.t
Bug 16497: Add /api/v1/libraries
[koha.git] / t / db_dependent / api / v1 / libraries.t
1 #!/usr/bin/env perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
8 # version.
9 #
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 use Modern::Perl;
19
20 use Test::More tests => 5;
21 use Test::Mojo;
22 use Test::Warn;
23
24 use t::lib::TestBuilder;
25 use t::lib::Mocks;
26
27 use C4::Auth;
28 use Koha::Libraries;
29 use Koha::Database;
30
31 my $schema  = Koha::Database->new->schema;
32 my $builder = t::lib::TestBuilder->new;
33
34 # FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
35 # this affects the other REST api tests
36 t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
37
38 my $remote_address = '127.0.0.1';
39 my $t              = Test::Mojo->new('Koha::REST::V1');
40
41 subtest 'list() tests' => sub {
42     plan tests => 8;
43
44     $schema->storage->txn_begin;
45
46     # Create test context
47     my $library = $builder->build( { source => 'Branch' } );
48     my $another_library = { %$library };   # create a copy of $library but make
49     delete $another_library->{branchcode}; # sure branchcode will be regenerated
50     $another_library = $builder->build(
51         { source => 'Branch', value => $another_library } );
52     my ( $borrowernumber, $session_id ) =
53       create_user_and_session( { authorized => 0 } );
54
55     ## Authorized user tests
56     my $count_of_libraries = Koha::Libraries->search->count;
57     # Make sure we are returned with the correct amount of libraries
58     my $tx = $t->ua->build_tx( GET => '/api/v1/libraries' );
59     $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
60     $tx->req->env( { REMOTE_ADDR => $remote_address } );
61     $t->request_ok($tx)
62       ->status_is(200)
63       ->json_has('/'.($count_of_libraries-1).'/branchcode')
64       ->json_hasnt('/'.($count_of_libraries).'/branchcode');
65
66     subtest 'query parameters' => sub {
67         my @fields = qw(
68         branchname       branchaddress1 branchaddress2 branchaddress3
69         branchzip        branchcity     branchstate    branchcountry
70         branchphone      branchfax      branchemail    branchreplyto
71         branchreturnpath branchurl      issuing        branchip
72         branchprinter    branchnotes    opac_info
73         );
74         plan tests => scalar(@fields)*3;
75
76         foreach my $field (@fields) {
77             $tx = $t->ua->build_tx( GET =>
78                          "/api/v1/libraries?$field=$library->{$field}" );
79             $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
80             $tx->req->env( { REMOTE_ADDR => $remote_address } );
81             my $result =
82             $t->request_ok($tx)
83               ->status_is(200)
84               ->json_has( [ $library, $another_library ] );
85         }
86     };
87
88     # Warn on unsupported query parameter
89     $tx = $t->ua->build_tx( GET => '/api/v1/libraries?library_blah=blah' );
90     $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
91     $tx->req->env( { REMOTE_ADDR => $remote_address } );
92     $t->request_ok($tx)
93       ->status_is(400)
94       ->json_is( [{ path => '/query/library_blah', message => 'Malformed query string'}] );
95
96     $schema->storage->txn_rollback;
97 };
98
99 subtest 'get() tests' => sub {
100
101     plan tests => 6;
102
103     $schema->storage->txn_begin;
104
105     my $library = $builder->build( { source => 'Branch' } );
106     my ( $borrowernumber, $session_id ) =
107       create_user_and_session( { authorized => 0 } );
108
109     my $tx = $t->ua->build_tx( GET => "/api/v1/libraries/" . $library->{branchcode} );
110     $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
111     $tx->req->env( { REMOTE_ADDR => $remote_address } );
112     $t->request_ok($tx)
113       ->status_is(200)
114       ->json_is($library);
115
116     my $non_existent_code = 'non_existent'.int(rand(10000));
117     $tx = $t->ua->build_tx( GET => "/api/v1/libraries/" . $non_existent_code );
118     $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
119     $tx->req->env( { REMOTE_ADDR => $remote_address } );
120     $t->request_ok($tx)
121       ->status_is(404)
122       ->json_is( '/error' => 'Library not found' );
123
124     $schema->storage->txn_rollback;
125 };
126
127 subtest 'add() tests' => sub {
128     plan tests => 31;
129
130     $schema->storage->txn_begin;
131
132     my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
133       create_user_and_session( { authorized => 0 } );
134     my ( $authorized_borrowernumber, $authorized_session_id ) =
135       create_user_and_session( { authorized => 1 } );
136     my $library = {
137         branchcode       => "LIBRARYBR1",
138         branchname       => "Library Name",
139         branchaddress1   => "Library Address1",
140         branchaddress2   => "Library Address2",
141         branchaddress3   => "Library Address3",
142         branchzip        => "Library Zipcode",
143         branchcity       => "Library City",
144         branchstate      => "Library State",
145         branchcountry    => "Library Country",
146         branchphone      => "Library Phone",
147         branchfax        => "Library Fax",
148         branchemail      => "Library Email",
149         branchreplyto    => "Library Reply-To",
150         branchreturnpath => "Library Return-Path",
151         branchurl        => "http://library.url",
152         issuing          => undef,                  # unused in Koha
153         branchip         => "127.0.0.1",
154         branchprinter    => "Library Printer",      # unused in Koha
155         branchnotes      => "Library Notes",
156         opac_info        => "<p>Library OPAC info</p>",
157     };
158
159     # Unauthorized attempt to write
160     my $tx = $t->ua->build_tx( POST => "/api/v1/libraries" => json => $library );
161     $tx->req->cookies(
162         { name => 'CGISESSID', value => $unauthorized_session_id } );
163     $tx->req->env( { REMOTE_ADDR => $remote_address } );
164     $t->request_ok($tx)
165       ->status_is(403);
166
167     # Authorized attempt to write invalid data
168     my $library_with_invalid_field = { %$library };
169     $library_with_invalid_field->{'branchinvalid'} = 'Library invalid';
170
171     $tx = $t->ua->build_tx(
172         POST => "/api/v1/libraries" => json => $library_with_invalid_field );
173     $tx->req->cookies(
174         { name => 'CGISESSID', value => $authorized_session_id } );
175     $tx->req->env( { REMOTE_ADDR => $remote_address } );
176     $t->request_ok($tx)
177       ->status_is(400)
178       ->json_is(
179         "/errors" => [
180             {
181                 message => "Properties not allowed: branchinvalid.",
182                 path    => "/body"
183             }
184         ]
185     );
186
187     # Authorized attempt to write
188     $tx = $t->ua->build_tx( POST => "/api/v1/libraries" => json => $library );
189     $tx->req->cookies(
190         { name => 'CGISESSID', value => $authorized_session_id } );
191     $tx->req->env( { REMOTE_ADDR => $remote_address } );
192     my $branchcode = $t->request_ok($tx)
193       ->status_is(201)
194       ->json_is( '/branchname'       => $library->{branchname} )
195       ->json_is( '/branchaddress1'   => $library->{branchaddress1} )
196       ->json_is( '/branchaddress2'   => $library->{branchaddress2} )
197       ->json_is( '/branchaddress3'   => $library->{branchaddress3} )
198       ->json_is( '/branchzip'        => $library->{branchzip} )
199       ->json_is( '/branchcity'       => $library->{branchcity} )
200       ->json_is( '/branchstate'      => $library->{branchstate} )
201       ->json_is( '/branchcountry'    => $library->{branchcountry} )
202       ->json_is( '/branchphone'      => $library->{branchphone} )
203       ->json_is( '/branchfax'        => $library->{branchfax} )
204       ->json_is( '/branchemail'      => $library->{branchemail} )
205       ->json_is( '/branchreplyto'    => $library->{branchreplyto} )
206       ->json_is( '/branchreturnpath' => $library->{branchreturnpath} )
207       ->json_is( '/branchurl'        => $library->{branchurl} )
208       ->json_is( '/branchip'        => $library->{branchip} )
209       ->json_is( '/branchnotes'      => $library->{branchnotes} )
210       ->json_is( '/opac_info'        => $library->{opac_info} )
211       ->header_is(Location => "/api/v1/libraries/$library->{branchcode}")
212       ->tx->res->json->{branchcode};
213
214     # Authorized attempt to create with null id
215     $library->{branchcode} = undef;
216     $tx = $t->ua->build_tx(
217         POST => "/api/v1/libraries" => json => $library );
218     $tx->req->cookies(
219         { name => 'CGISESSID', value => $authorized_session_id } );
220     $tx->req->env( { REMOTE_ADDR => $remote_address } );
221     $t->request_ok($tx)
222       ->status_is(400)
223       ->json_has('/errors');
224
225     # Authorized attempt to create with existing id
226     $library->{branchcode} = $branchcode;
227     $tx = $t->ua->build_tx(
228         POST => "/api/v1/libraries" => json => $library );
229     $tx->req->cookies(
230         { name => 'CGISESSID', value => $authorized_session_id } );
231     $tx->req->env( { REMOTE_ADDR => $remote_address } );
232     $t->request_ok($tx)
233       ->status_is(400)
234       ->json_is('/error' => 'Library already exists');
235
236     $schema->storage->txn_rollback;
237 };
238
239 subtest 'update() tests' => sub {
240     plan tests => 13;
241
242     $schema->storage->txn_begin;
243
244     my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
245       create_user_and_session( { authorized => 0 } );
246     my ( $authorized_borrowernumber, $authorized_session_id ) =
247       create_user_and_session( { authorized => 1 } );
248
249     my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
250
251     # Unauthorized attempt to update
252     my $tx = $t->ua->build_tx( PUT => "/api/v1/libraries/$branchcode"
253         => json => { branchname => 'New unauthorized name change' } );
254     $tx->req->cookies(
255         { name => 'CGISESSID', value => $unauthorized_session_id } );
256     $tx->req->env( { REMOTE_ADDR => $remote_address } );
257     $t->request_ok($tx)
258       ->status_is(403);
259
260     # Attempt partial update on a PUT
261     my $library_with_missing_field = {
262         branchaddress1 => "New library address",
263     };
264
265     $tx = $t->ua->build_tx( PUT => "/api/v1/libraries/$branchcode" =>
266                             json => $library_with_missing_field );
267     $tx->req->cookies(
268         { name => 'CGISESSID', value => $authorized_session_id } );
269     $tx->req->env( { REMOTE_ADDR => $remote_address } );
270     $t->request_ok($tx)
271       ->status_is(400)
272       ->json_has( "/errors" =>
273           [ { message => "Missing property.", path => "/body/branchaddress2" } ]
274       );
275
276     # Full object update on PUT
277     my $library_with_updated_field = {
278         branchcode       => "LIBRARYBR2",
279         branchname       => "Library Name",
280         branchaddress1   => "Library Address1",
281         branchaddress2   => "Library Address2",
282         branchaddress3   => "Library Address3",
283         branchzip        => "Library Zipcode",
284         branchcity       => "Library City",
285         branchstate      => "Library State",
286         branchcountry    => "Library Country",
287         branchphone      => "Library Phone",
288         branchfax        => "Library Fax",
289         branchemail      => "Library Email",
290         branchreplyto    => "Library Reply-To",
291         branchreturnpath => "Library Return-Path",
292         branchurl        => "http://library.url",
293         issuing          => undef,                  # unused in Koha
294         branchip         => "127.0.0.1",
295         branchprinter    => "Library Printer",      # unused in Koha
296         branchnotes      => "Library Notes",
297         opac_info        => "<p>Library OPAC info</p>",
298     };
299
300     $tx = $t->ua->build_tx(
301         PUT => "/api/v1/libraries/$branchcode" => json => $library_with_updated_field );
302     $tx->req->cookies(
303         { name => 'CGISESSID', value => $authorized_session_id } );
304     $tx->req->env( { REMOTE_ADDR => $remote_address } );
305     $t->request_ok($tx)
306       ->status_is(200)
307       ->json_is( '/branchname' => 'Library Name' );
308
309     # Authorized attempt to write invalid data
310     my $library_with_invalid_field = { %$library_with_updated_field };
311     $library_with_invalid_field->{'branchinvalid'} = 'Library invalid';
312
313     $tx = $t->ua->build_tx(
314         PUT => "/api/v1/libraries/$branchcode" => json => $library_with_invalid_field );
315     $tx->req->cookies(
316         { name => 'CGISESSID', value => $authorized_session_id } );
317     $tx->req->env( { REMOTE_ADDR => $remote_address } );
318     $t->request_ok($tx)
319       ->status_is(400)
320       ->json_is(
321         "/errors" => [
322             {
323                 message => "Properties not allowed: branchinvalid.",
324                 path    => "/body"
325             }
326         ]
327     );
328
329     my $non_existent_code = 'nope'.int(rand(10000));
330     $tx =
331       $t->ua->build_tx( PUT => "/api/v1/libraries/$non_existent_code" => json =>
332           $library_with_updated_field );
333     $tx->req->cookies(
334         { name => 'CGISESSID', value => $authorized_session_id } );
335     $tx->req->env( { REMOTE_ADDR => $remote_address } );
336     $t->request_ok($tx)
337       ->status_is(404);
338
339     $schema->storage->txn_rollback;
340 };
341
342 subtest 'delete() tests' => sub {
343     plan tests => 7;
344
345     $schema->storage->txn_begin;
346
347     my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
348       create_user_and_session( { authorized => 0 } );
349     my ( $authorized_borrowernumber, $authorized_session_id ) =
350       create_user_and_session( { authorized => 1 } );
351
352     my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
353
354     # Unauthorized attempt to delete
355     my $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" );
356     $tx->req->cookies(
357         { name => 'CGISESSID', value => $unauthorized_session_id } );
358     $tx->req->env( { REMOTE_ADDR => $remote_address } );
359     $t->request_ok($tx)
360       ->status_is(403);
361
362     $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" );
363     $tx->req->cookies(
364         { name => 'CGISESSID', value => $authorized_session_id } );
365     $tx->req->env( { REMOTE_ADDR => $remote_address } );
366     $t->request_ok($tx)
367       ->status_is(204)
368       ->content_is('');
369
370     $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" );
371     $tx->req->cookies(
372         { name => 'CGISESSID', value => $authorized_session_id } );
373     $tx->req->env( { REMOTE_ADDR => $remote_address } );
374     $t->request_ok($tx)
375       ->status_is(404);
376
377     $schema->storage->txn_rollback;
378 };
379
380 sub create_user_and_session {
381
382     my $args  = shift;
383     my $flags = ( $args->{authorized} ) ? $args->{authorized} : 0;
384     my $dbh   = C4::Context->dbh;
385
386     my $user = $builder->build(
387         {
388             source => 'Borrower',
389             value  => {
390                 flags => $flags
391             }
392         }
393     );
394
395     # Create a session for the authorized user
396     my $session = C4::Auth::get_session('');
397     $session->param( 'number',   $user->{borrowernumber} );
398     $session->param( 'id',       $user->{userid} );
399     $session->param( 'ip',       '127.0.0.1' );
400     $session->param( 'lasttime', time() );
401     $session->flush;
402
403     if ( $args->{authorized} ) {
404         $dbh->do( "
405             INSERT INTO user_permissions (borrowernumber,module_bit,code)
406             VALUES (?,3,'parameters_remaining_permissions')", undef,
407             $user->{borrowernumber} );
408     }
409
410     return ( $user->{borrowernumber}, $session->id );
411 }
412
413 1;