3 # This file is part of Koha.
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
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.
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.
20 use Test::More tests => 5;
23 use t::lib::TestBuilder;
29 my $schema = Koha::Database->new->schema;
30 my $builder = t::lib::TestBuilder->new;
32 # FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
33 # this affects the other REST api tests
34 t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
36 my $remote_address = '127.0.0.1';
37 my $t = Test::Mojo->new('Koha::REST::V1');
39 subtest 'list() tests' => sub {
42 $schema->storage->txn_begin;
44 unauthorized_access_tests('GET', undef, undef);
46 subtest 'librarian access tests' => sub {
49 my ($borrowernumber, $sessionid) = create_user_and_session({
51 my $patron = Koha::Patrons->find($borrowernumber);
52 Koha::Patrons->search({
53 borrowernumber => { '!=' => $borrowernumber},
54 cardnumber => { LIKE => $patron->cardnumber . "%" }
56 Koha::Patrons->search({
57 borrowernumber => { '!=' => $borrowernumber},
58 address2 => { LIKE => $patron->address2 . "%" }
61 my $tx = $t->ua->build_tx(GET => '/api/v1/patrons');
62 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
63 $tx->req->env({REMOTE_ADDR => '127.0.0.1'});
67 $tx = $t->ua->build_tx(GET => '/api/v1/patrons?cardnumber='.
69 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
70 $tx->req->env({REMOTE_ADDR => '127.0.0.1'});
73 ->json_is('/0/cardnumber' => $patron->cardnumber);
75 $tx = $t->ua->build_tx(GET => '/api/v1/patrons?address2='.
77 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
78 $tx->req->env({REMOTE_ADDR => '127.0.0.1'});
81 ->json_is('/0/address2' => $patron->address2);
84 $schema->storage->txn_rollback;
87 subtest 'get() tests' => sub {
90 $schema->storage->txn_begin;
92 unauthorized_access_tests('GET', -1, undef);
94 subtest 'access own object tests' => sub {
97 my ($patronid, $patronsessionid) = create_user_and_session({
100 # Access patron's own data even though they have no borrowers flag
101 my $tx = $t->ua->build_tx(GET => "/api/v1/patrons/$patronid");
102 $tx->req->cookies({name => 'CGISESSID', value => $patronsessionid});
103 $tx->req->env({REMOTE_ADDR => '127.0.0.1'});
107 my $guarantee = $builder->build({
108 source => 'Borrower',
110 guarantorid => $patronid,
114 # Access guarantee's data even though guarantor has no borrowers flag
115 my $guaranteenumber = $guarantee->{borrowernumber};
116 $tx = $t->ua->build_tx(GET => "/api/v1/patrons/$guaranteenumber");
117 $tx->req->cookies({name => 'CGISESSID', value => $patronsessionid});
118 $tx->req->env({REMOTE_ADDR => '127.0.0.1'});
123 subtest 'librarian access tests' => sub {
126 my ($patron_id) = create_user_and_session({
128 my $patron = Koha::Patrons->find($patron_id);
129 my ($borrowernumber, $sessionid) = create_user_and_session({
131 my $tx = $t->ua->build_tx(GET => "/api/v1/patrons/$patron_id");
132 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
135 ->json_is('/borrowernumber' => $patron_id)
136 ->json_is('/surname' => $patron->surname)
137 ->json_is('/lost' => Mojo::JSON->false );
140 $schema->storage->txn_rollback;
143 subtest 'add() tests' => sub {
146 $schema->storage->txn_begin;
148 my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
149 my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
152 branchcode => $branchcode,
153 cardnumber => $branchcode.$categorycode,
154 categorycode => $categorycode,
156 surname => "TestUser",
157 userid => $branchcode.$categorycode,
160 unauthorized_access_tests('POST', undef, $newpatron);
162 subtest 'librarian access tests' => sub {
165 my ($borrowernumber, $sessionid) = create_user_and_session({
168 $newpatron->{branchcode} = "nonexistent"; # Test invalid branchcode
169 my $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron );
170 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
173 ->json_is('/error' => "Given branchcode does not exist");
174 $newpatron->{branchcode} = $branchcode;
176 $newpatron->{categorycode} = "nonexistent"; # Test invalid patron category
177 $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
178 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
181 ->json_is('/error' => "Given categorycode does not exist");
182 $newpatron->{categorycode} = $categorycode;
184 $newpatron->{falseproperty} = "Non existent property";
185 $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
186 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
189 delete $newpatron->{falseproperty};
191 $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
192 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
194 ->status_is(201, 'Patron created successfully')
195 ->json_has('/borrowernumber', 'got a borrowernumber')
196 ->json_is('/cardnumber', $newpatron->{ cardnumber })
197 ->json_is('/surname' => $newpatron->{ surname })
198 ->json_is('/firstname' => $newpatron->{ firstname });
199 $newpatron->{borrowernumber} = $tx->res->json->{borrowernumber};
201 $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
202 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
205 ->json_has('/error', 'Fails when trying to POST duplicate'.
206 ' cardnumber or userid')
207 ->json_has('/conflict', {
208 userid => $newpatron->{ userid },
209 cardnumber => $newpatron->{ cardnumber }
214 $schema->storage->txn_rollback;
217 subtest 'update() tests' => sub {
220 $schema->storage->txn_begin;
222 unauthorized_access_tests('PUT', 123, {email => 'nobody@example.com'});
224 subtest 'librarian access tests' => sub {
227 t::lib::Mocks::mock_preference('minPasswordLength', 1);
228 my ($borrowernumber, $sessionid) = create_user_and_session({ authorized => 1 });
229 my ($borrowernumber2, undef) = create_user_and_session({ authorized => 0 });
231 my $patron_1 = Koha::Patrons->find($borrowernumber);
232 my $patron_2 = Koha::Patrons->find($borrowernumber2);
233 my $newpatron = $patron_2->TO_JSON;
235 my $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/-1" => json => $newpatron );
236 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
239 ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
241 $newpatron->{categorycode} = 'nonexistent';
242 $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
243 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
246 ->json_is('/error' => "Given categorycode does not exist");
247 $newpatron->{categorycode} = $patron_2->categorycode;
249 $newpatron->{branchcode} = 'nonexistent';
250 $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
251 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
254 ->json_is('/error' => "Given branchcode does not exist");
255 $newpatron->{branchcode} = $patron_2->branchcode;
257 $newpatron->{falseproperty} = "Non existent property";
258 $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
259 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
262 ->json_is('/errors/0/message' =>
263 'Properties not allowed: falseproperty.');
264 delete $newpatron->{falseproperty};
266 # Set both cardnumber and userid to already existing values
267 $newpatron->{cardnumber} = $patron_1->cardnumber;
268 $newpatron->{userid} = $patron_1->userid;
270 $tx = $t->ua->build_tx( PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
271 $tx->req->cookies({ name => 'CGISESSID', value => $sessionid });
272 $t->request_ok($tx)->status_is(409)
273 ->json_has( '/error' => "Fails when trying to update to an existing cardnumber or userid")
274 ->json_is( '/conflict',
276 cardnumber => $newpatron->{cardnumber},
277 userid => $newpatron->{userid}
281 $newpatron->{ cardnumber } = $borrowernumber.$borrowernumber2;
282 $newpatron->{ userid } = "user".$borrowernumber.$borrowernumber2;
283 $newpatron->{ surname } = "user".$borrowernumber.$borrowernumber2;
285 $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
286 $newpatron->{borrowernumber} => json => $newpatron);
287 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
289 ->status_is(200, 'Patron updated successfully')
290 ->json_has($newpatron);
291 is(Koha::Patrons->find($newpatron->{borrowernumber})->cardnumber,
292 $newpatron->{ cardnumber }, 'Patron is really updated!');
295 $schema->storage->txn_rollback;
298 subtest 'delete() tests' => sub {
301 $schema->storage->txn_begin;
303 unauthorized_access_tests('DELETE', 123, undef);
305 subtest 'librarian access test' => sub {
308 my ($borrowernumber, $sessionid) = create_user_and_session({
310 my ($borrowernumber2, $sessionid2) = create_user_and_session({
313 my $tx = $t->ua->build_tx(DELETE => "/api/v1/patrons/-1");
314 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
316 ->status_is(404, 'Patron not found');
318 $tx = $t->ua->build_tx(DELETE => "/api/v1/patrons/$borrowernumber2");
319 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
321 ->status_is(200, 'Patron deleted successfully');
324 $schema->storage->txn_rollback;
327 # Centralized tests for 401s and 403s assuming the endpoint requires
328 # borrowers flag for access
329 sub unauthorized_access_tests {
330 my ($verb, $patronid, $json) = @_;
332 my $endpoint = '/api/v1/patrons';
333 $endpoint .= ($patronid) ? "/$patronid" : '';
335 subtest 'unauthorized access tests' => sub {
338 my $tx = $t->ua->build_tx($verb => $endpoint => json => $json);
342 my ($borrowernumber, $sessionid) = create_user_and_session({
345 $tx = $t->ua->build_tx($verb => $endpoint => json => $json);
346 $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
349 ->json_has('/required_permissions');
353 sub create_user_and_session {
356 my $flags = ( $args->{authorized} ) ? 16 : 0;
358 my $user = $builder->build(
360 source => 'Borrower',
365 email => 'nobody@example.com',
366 emailpro => 'nobody@example.com',
367 B_email => 'nobody@example.com'
372 # Create a session for the authorized user
373 my $session = C4::Auth::get_session('');
374 $session->param( 'number', $user->{borrowernumber} );
375 $session->param( 'id', $user->{userid} );
376 $session->param( 'ip', '127.0.0.1' );
377 $session->param( 'lasttime', time() );
380 return ( $user->{borrowernumber}, $session->id );