Bug 25898: Prohibit indirect object notation
[koha.git] / t / db_dependent / api / v1 / cities.t
blob720e6434a15f50d865297667dd1d18a0b0403b81
1 #!/usr/bin/env perl
3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
18 use Modern::Perl;
20 use Test::More tests => 5;
21 use Test::Mojo;
23 use t::lib::TestBuilder;
24 use t::lib::Mocks;
26 use Koha::Cities;
27 use Koha::Database;
29 my $schema = Koha::Database->new->schema;
30 my $builder = t::lib::TestBuilder->new;
32 my $t = Test::Mojo->new('Koha::REST::V1');
33 t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
35 subtest 'list() tests' => sub {
37 plan tests => 20;
39 $schema->storage->txn_begin;
41 Koha::Cities->search->delete;
43 my $librarian = $builder->build_object(
45 class => 'Koha::Patrons',
46 value => { flags => 2 ** 2 } # catalogue flag = 2
49 my $password = 'thePassword123';
50 $librarian->set_password( { password => $password, skip_validation => 1 } );
51 my $userid = $librarian->userid;
53 my $patron = $builder->build_object(
55 class => 'Koha::Patrons',
56 value => { flags => 0 }
60 $patron->set_password( { password => $password, skip_validation => 1 } );
61 my $unauth_userid = $patron->userid;
63 ## Authorized user tests
64 # No cities, so empty array should be returned
65 $t->get_ok("//$userid:$password@/api/v1/cities")
66 ->status_is(200)
67 ->json_is( [] );
69 my $city = $builder->build_object({ class => 'Koha::Cities' });
71 # One city created, should get returned
72 $t->get_ok("//$userid:$password@/api/v1/cities")
73 ->status_is(200)
74 ->json_is( [$city->to_api] );
76 my $another_city = $builder->build_object(
77 { class => 'Koha::Cities', value => { city_country => $city->city_country } } );
78 my $city_with_another_country = $builder->build_object({ class => 'Koha::Cities' });
80 # Two cities created, they should both be returned
81 $t->get_ok("//$userid:$password@/api/v1/cities")
82 ->status_is(200)
83 ->json_is([$city->to_api,
84 $another_city->to_api,
85 $city_with_another_country->to_api
86 ] );
88 # Filtering works, two cities sharing city_country
89 $t->get_ok("//$userid:$password@/api/v1/cities?country=" . $city->city_country )
90 ->status_is(200)
91 ->json_is([ $city->to_api,
92 $another_city->to_api
93 ]);
95 $t->get_ok("//$userid:$password@/api/v1/cities?name=" . $city->city_name )
96 ->status_is(200)
97 ->json_is( [$city->to_api] );
99 # Warn on unsupported query parameter
100 $t->get_ok("//$userid:$password@/api/v1/cities?city_blah=blah" )
101 ->status_is(400)
102 ->json_is( [{ path => '/query/city_blah', message => 'Malformed query string'}] );
104 # Unauthorized access
105 $t->get_ok("//$unauth_userid:$password@/api/v1/cities")
106 ->status_is(403);
108 $schema->storage->txn_rollback;
111 subtest 'get() tests' => sub {
113 plan tests => 8;
115 $schema->storage->txn_begin;
117 my $city = $builder->build_object({ class => 'Koha::Cities' });
118 my $librarian = $builder->build_object(
120 class => 'Koha::Patrons',
121 value => { flags => 2**2 } # catalogue flag = 2
124 my $password = 'thePassword123';
125 $librarian->set_password( { password => $password, skip_validation => 1 } );
126 my $userid = $librarian->userid;
128 my $patron = $builder->build_object(
130 class => 'Koha::Patrons',
131 value => { flags => 0 }
135 $patron->set_password( { password => $password, skip_validation => 1 } );
136 my $unauth_userid = $patron->userid;
138 $t->get_ok( "//$userid:$password@/api/v1/cities/" . $city->cityid )
139 ->status_is(200)
140 ->json_is($city->to_api);
142 $t->get_ok( "//$unauth_userid:$password@/api/v1/cities/" . $city->cityid )
143 ->status_is(403);
145 my $city_to_delete = $builder->build_object({ class => 'Koha::Cities' });
146 my $non_existent_id = $city_to_delete->id;
147 $city_to_delete->delete;
149 $t->get_ok( "//$userid:$password@/api/v1/cities/$non_existent_id" )
150 ->status_is(404)
151 ->json_is( '/error' => 'City not found' );
153 $schema->storage->txn_rollback;
156 subtest 'add() tests' => sub {
158 plan tests => 18;
160 $schema->storage->txn_begin;
162 my $librarian = $builder->build_object(
164 class => 'Koha::Patrons',
165 value => { flags => 2**3 } # parameters flag = 2
168 my $password = 'thePassword123';
169 $librarian->set_password( { password => $password, skip_validation => 1 } );
170 my $userid = $librarian->userid;
172 my $patron = $builder->build_object(
174 class => 'Koha::Patrons',
175 value => { flags => 0 }
179 $patron->set_password( { password => $password, skip_validation => 1 } );
180 my $unauth_userid = $patron->userid;
182 my $city = {
183 name => "City Name",
184 state => "City State",
185 postal_code => "City Zipcode",
186 country => "City Country"
189 # Unauthorized attempt to write
190 $t->post_ok("//$unauth_userid:$password@/api/v1/cities" => json => $city)
191 ->status_is(403);
193 # Authorized attempt to write invalid data
194 my $city_with_invalid_field = {
195 blah => "City Blah",
196 state => "City State",
197 postal_code => "City Zipcode",
198 country => "City Country"
201 $t->post_ok( "//$userid:$password@/api/v1/cities" => json => $city_with_invalid_field )
202 ->status_is(400)
203 ->json_is(
204 "/errors" => [
206 message => "Properties not allowed: blah.",
207 path => "/body"
212 # Authorized attempt to write
213 my $city_id =
214 $t->post_ok( "//$userid:$password@/api/v1/cities" => json => $city )
215 ->status_is( 201, 'SWAGGER3.2.1' )
216 ->header_like(
217 Location => qr|^\/api\/v1\/cities/\d*|,
218 'SWAGGER3.4.1'
220 ->json_is( '/name' => $city->{name} )
221 ->json_is( '/state' => $city->{state} )
222 ->json_is( '/postal_code' => $city->{postal_code} )
223 ->json_is( '/country' => $city->{country} )
224 ->tx->res->json->{city_id};
226 # Authorized attempt to create with null id
227 $city->{city_id} = undef;
228 $t->post_ok( "//$userid:$password@/api/v1/cities" => json => $city )
229 ->status_is(400)
230 ->json_has('/errors');
232 # Authorized attempt to create with existing id
233 $city->{city_id} = $city_id;
234 $t->post_ok( "//$userid:$password@/api/v1/cities" => json => $city )
235 ->status_is(400)
236 ->json_is(
237 "/errors" => [
239 message => "Read-only.",
240 path => "/body/city_id"
245 $schema->storage->txn_rollback;
248 subtest 'update() tests' => sub {
250 plan tests => 15;
252 $schema->storage->txn_begin;
254 my $librarian = $builder->build_object(
256 class => 'Koha::Patrons',
257 value => { flags => 2**3 } # parameters flag = 2
260 my $password = 'thePassword123';
261 $librarian->set_password( { password => $password, skip_validation => 1 } );
262 my $userid = $librarian->userid;
264 my $patron = $builder->build_object(
266 class => 'Koha::Patrons',
267 value => { flags => 0 }
271 $patron->set_password( { password => $password, skip_validation => 1 } );
272 my $unauth_userid = $patron->userid;
274 my $city_id = $builder->build_object({ class => 'Koha::Cities' } )->id;
276 # Unauthorized attempt to update
277 $t->put_ok( "//$unauth_userid:$password@/api/v1/cities/$city_id" => json => { name => 'New unauthorized name change' } )
278 ->status_is(403);
280 # Attempt partial update on a PUT
281 my $city_with_missing_field = {
282 name => 'New name',
283 state => 'New state',
284 country => 'New country'
287 $t->put_ok( "//$userid:$password@/api/v1/cities/$city_id" => json => $city_with_missing_field )
288 ->status_is(400)
289 ->json_is( "/errors" =>
290 [ { message => "Missing property.", path => "/body/postal_code" } ]
293 # Full object update on PUT
294 my $city_with_updated_field = {
295 name => "London",
296 state => "City State",
297 postal_code => "City Zipcode",
298 country => "City Country"
301 $t->put_ok( "//$userid:$password@/api/v1/cities/$city_id" => json => $city_with_updated_field )
302 ->status_is(200)
303 ->json_is( '/name' => 'London' );
305 # Authorized attempt to write invalid data
306 my $city_with_invalid_field = {
307 blah => "City Blah",
308 state => "City State",
309 postal_code => "City Zipcode",
310 country => "City Country"
313 $t->put_ok( "//$userid:$password@/api/v1/cities/$city_id" => json => $city_with_invalid_field )
314 ->status_is(400)
315 ->json_is(
316 "/errors" => [
318 message => "Properties not allowed: blah.",
319 path => "/body"
324 my $city_to_delete = $builder->build_object({ class => 'Koha::Cities' });
325 my $non_existent_id = $city_to_delete->id;
326 $city_to_delete->delete;
328 $t->put_ok( "//$userid:$password@/api/v1/cities/$non_existent_id" => json => $city_with_updated_field )
329 ->status_is(404);
331 # Wrong method (POST)
332 $city_with_updated_field->{city_id} = 2;
334 $t->post_ok( "//$userid:$password@/api/v1/cities/$city_id" => json => $city_with_updated_field )
335 ->status_is(404);
337 $schema->storage->txn_rollback;
340 subtest 'delete() tests' => sub {
342 plan tests => 7;
344 $schema->storage->txn_begin;
346 my $librarian = $builder->build_object(
348 class => 'Koha::Patrons',
349 value => { flags => 2**3 } # parameters flag = 2
352 my $password = 'thePassword123';
353 $librarian->set_password( { password => $password, skip_validation => 1 } );
354 my $userid = $librarian->userid;
356 my $patron = $builder->build_object(
358 class => 'Koha::Patrons',
359 value => { flags => 0 }
363 $patron->set_password( { password => $password, skip_validation => 1 } );
364 my $unauth_userid = $patron->userid;
366 my $city_id = $builder->build_object({ class => 'Koha::Cities' })->id;
368 # Unauthorized attempt to delete
369 $t->delete_ok( "//$unauth_userid:$password@/api/v1/cities/$city_id" )
370 ->status_is(403);
372 $t->delete_ok("//$userid:$password@/api/v1/cities/$city_id")
373 ->status_is(204, 'SWAGGER3.2.4')
374 ->content_is('', 'SWAGGER3.3.4');
376 $t->delete_ok("//$userid:$password@/api/v1/cities/$city_id")
377 ->status_is(404);
379 $schema->storage->txn_rollback;