Bug 26635: Move expand syntax to x-koha-embed
[koha.git] / t / db_dependent / Koha / REST / Plugin / Objects.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
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.
9 #
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.
14 #
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>.
17
18 use Modern::Perl;
19
20 use Koha::Acquisition::Orders;
21 use Koha::AuthorisedValueCategories;
22 use Koha::AuthorisedValues;
23 use Koha::Cities;
24 use Koha::Biblios;
25 use Koha::Patrons;
26
27 use Mojo::JSON qw(encode_json);
28
29 # Dummy app for testing the plugin
30 use Mojolicious::Lite;
31
32 app->log->level('error');
33
34 plugin 'Koha::REST::Plugin::Objects';
35 plugin 'Koha::REST::Plugin::Query';
36 plugin 'Koha::REST::Plugin::Pagination';
37
38 get '/cities' => sub {
39     my $c = shift;
40     $c->validation->output($c->req->params->to_hash);
41     $c->stash_embed;
42     my $cities = $c->objects->search(Koha::Cities->new);
43     $c->render( status => 200, json => $cities );
44 };
45
46 get '/cities/:city_id' => sub {
47     my $c = shift;
48     my $id = $c->stash("city_id");
49     $c->stash_embed;
50     my $city = $c->objects->find(Koha::Cities->new, $id);
51     $c->render( status => 200, json => $city );
52 };
53
54 get '/orders' => sub {
55     my $c = shift;
56     $c->stash('koha.embed', ( { fund => {} } ) );
57     $c->validation->output($c->req->params->to_hash);
58     my $orders = $c->objects->search(Koha::Acquisition::Orders->new);
59     $c->render( status => 200, json => $orders );
60 };
61
62 get '/orders/:order_id' => sub {
63     my $c = shift;
64     $c->stash('koha.embed', ( { fund => {} } ) );
65     my $id = $c->stash("order_id");
66     my $order = $c->objects->find(Koha::Acquisition::Orders->new, $id);
67     $c->render( status => 200, json => $order );
68 };
69
70 get '/biblios' => sub {
71     my $c = shift;
72     my $output = $c->req->params->to_hash;
73     $output->{query} = $c->req->json if defined $c->req->json;
74     my $headers = $c->req->headers->to_hash;
75     $output->{'x-koha-query'} = $headers->{'x-koha-query'} if defined $headers->{'x-koha-query'};
76     $c->validation->output($output);
77     my $biblios_set = Koha::Biblios->new;
78     $c->stash("koha.embed", {
79         "suggestions" => {
80             children => {
81                 "suggester" => {}
82             }
83         }
84     });
85     my $biblios = $c->objects->search($biblios_set);
86     $c->render( status => 200, json => {count => scalar(@$biblios), biblios => $biblios} );
87 };
88
89 get '/libraries/:library_id_1/:library_id_2' => sub {
90
91     my $c = shift;
92
93     # Emulate a public route by stashing the is_public value
94     $c->stash( 'is_public' => 1 );
95
96     my $library_id_1 = $c->param('library_id_1');
97     my $library_id_2 = $c->param('library_id_2');
98
99     my $libraries_rs = Koha::Libraries->search(
100         { branchcode => [ $library_id_1, $library_id_2 ] },
101         { order_by   => 'branchname' }
102     );
103     my $libraries    = $c->objects->search( $libraries_rs );
104
105     $c->render(
106         status => 200,
107         json   => $libraries
108     );
109 };
110
111 get '/my_patrons' => sub {
112
113     my $c = shift;
114
115     my $patrons = $c->objects->search( scalar Koha::Patrons->search( {}, { order_by   => 'borrowernumber' }) );
116
117     $c->render(
118         status => 200,
119         json   => $patrons
120     );
121 };
122
123 # The tests
124 use Test::More tests => 16;
125 use Test::Mojo;
126
127 use t::lib::Mocks;
128 use t::lib::TestBuilder;
129 use Koha::Database;
130
131 my $schema  = Koha::Database->new()->schema();
132 my $builder = t::lib::TestBuilder->new;
133
134 subtest 'objects.search helper' => sub {
135
136     plan tests => 50;
137
138     $schema->storage->txn_begin;
139
140     # Remove existing cities to have more control on the search results
141     Koha::Cities->delete;
142
143     # Create three sample cities that match the query. This makes sure we
144     # always have a "next" link regardless of Mojolicious::Plugin::OpenAPI version.
145     $builder->build_object({
146         class => 'Koha::Cities',
147         value => {
148             city_name => 'Manuel'
149         }
150     });
151     $builder->build_object({
152         class => 'Koha::Cities',
153         value => {
154             city_name => 'Manuela'
155         }
156     });
157     $builder->build_object({
158         class => 'Koha::Cities',
159         value => {
160             city_name => 'Manuelab'
161         }
162     });
163
164     my $t = Test::Mojo->new;
165     $t->get_ok('/cities?name=manuel&_per_page=1&_page=1')
166         ->status_is(200)
167         ->header_like( 'Link' => qr/<http:\/\/.*[\?&]_page=2.*>; rel="next",/ )
168         ->json_has('/0')
169         ->json_hasnt('/1')
170         ->json_is('/0/name' => 'Manuel');
171
172     $builder->build_object({
173         class => 'Koha::Cities',
174         value => {
175             city_name => 'Emanuel'
176         }
177     });
178
179     # _match=starts_with
180     $t->get_ok('/cities?name=manuel&_per_page=4&_page=1&_match=starts_with')
181         ->status_is(200)
182         ->json_has('/0')
183         ->json_has('/1')
184         ->json_has('/2')
185         ->json_hasnt('/3')
186         ->json_is('/0/name' => 'Manuel')
187         ->json_is('/1/name' => 'Manuela')
188         ->json_is('/2/name' => 'Manuelab');
189
190     # _match=ends_with
191     $t->get_ok('/cities?name=manuel&_per_page=4&_page=1&_match=ends_with')
192         ->status_is(200)
193         ->json_has('/0')
194         ->json_has('/1')
195         ->json_hasnt('/2')
196         ->json_is('/0/name' => 'Manuel')
197         ->json_is('/1/name' => 'Emanuel');
198
199     # _match=exact
200     $t->get_ok('/cities?name=manuel&_per_page=4&_page=1&_match=exact')
201         ->status_is(200)
202         ->json_has('/0')
203         ->json_hasnt('/1')
204         ->json_is('/0/name' => 'Manuel');
205
206     # _match=contains
207     $t->get_ok('/cities?name=manuel&_per_page=4&_page=1&_match=contains')
208         ->status_is(200)
209         ->json_has('/0')
210         ->json_has('/1')
211         ->json_has('/2')
212         ->json_has('/3')
213         ->json_hasnt('/4')
214         ->json_is('/0/name' => 'Manuel')
215         ->json_is('/1/name' => 'Manuela')
216         ->json_is('/2/name' => 'Manuelab')
217         ->json_is('/3/name' => 'Emanuel');
218
219     # Add 20 more cities
220     for ( 1..20 ) {
221         $builder->build_object({ class => 'Koha::Cities' });
222     }
223
224     t::lib::Mocks::mock_preference('RESTdefaultPageSize', 20 );
225     $t->get_ok('/cities')
226       ->status_is(200);
227
228     my $response_count = scalar @{ $t->tx->res->json };
229     is( $response_count, 20, 'RESTdefaultPageSize is honoured by default (20)' );
230
231     t::lib::Mocks::mock_preference('RESTdefaultPageSize', 5 );
232     $t->get_ok('/cities')
233       ->status_is(200);
234
235     $response_count = scalar @{ $t->tx->res->json };
236     is( $response_count, 5, 'RESTdefaultPageSize is honoured by default (5)' );
237
238     $t->get_ok('/cities?_page=1&_per_page=-1')
239       ->status_is(200);
240
241     $response_count = scalar @{ $t->tx->res->json };
242     is( $response_count, 24, '_per_page=-1 means all resources' );
243
244     $t->get_ok('/cities?_page=100&_per_page=-1')
245       ->status_is(200);
246
247     $response_count = scalar @{ $t->tx->res->json };
248     is( $response_count, 24, 'When _per_page=-1 the page param is not considered' );
249
250     $schema->storage->txn_rollback;
251 };
252
253 subtest 'objects.search helper, sorting on mapped column' => sub {
254
255     plan tests => 42;
256
257     $schema->storage->txn_begin;
258
259     # Have complete control over the existing cities to ease testing
260     Koha::Cities->delete;
261
262     $builder->build_object({ class => 'Koha::Cities', value => { city_name => 'A', city_country => 'Argentina' } });
263     $builder->build_object({ class => 'Koha::Cities', value => { city_name => 'B', city_country => 'Argentina' } });
264     $builder->build_object({ class => 'Koha::Cities', value => { city_name => 'C', city_country => 'Argentina' } });
265     $builder->build_object({ class => 'Koha::Cities', value => { city_name => 'C', city_country => 'Belarus' } });
266
267     my $t = Test::Mojo->new;
268     # CSV-param
269     $t->get_ok('/cities?_order_by=%2Bname,-country')
270       ->status_is(200)
271       ->json_has('/0')
272       ->json_has('/1')
273       ->json_is('/0/name' => 'A')
274       ->json_is('/1/name' => 'B')
275       ->json_is('/2/name' => 'C')
276       ->json_is('/2/country' => 'Belarus')
277       ->json_is('/3/name' => 'C')
278       ->json_is('/3/country' => 'Argentina')
279       ->json_hasnt('/4');
280
281     # Multi-param: traditional
282     $t->get_ok('/cities?_order_by=%2Bname&_order_by=-country')
283       ->status_is(200)
284       ->json_has('/0')
285       ->json_has('/1')
286       ->json_is('/0/name' => 'A')
287       ->json_is('/1/name' => 'B')
288       ->json_is('/2/name' => 'C')
289       ->json_is('/2/country' => 'Belarus')
290       ->json_is('/3/name' => 'C')
291       ->json_is('/3/country' => 'Argentina')
292       ->json_hasnt('/4');
293
294     # Multi-param: PHP Style, Passes validation as above, subsequntly explodes
295     $t->get_ok('/cities?_order_by[]=%2Bname&_order_by[]=-country')
296       ->status_is(200)
297       ->json_has('/0')
298       ->json_has('/1')
299       ->json_is('/0/name' => 'A')
300       ->json_is('/1/name' => 'B')
301       ->json_is('/2/name' => 'C')
302       ->json_is('/2/country' => 'Belarus')
303       ->json_is('/3/name' => 'C')
304       ->json_is('/3/country' => 'Argentina')
305       ->json_hasnt('/4');
306
307     # Single-param
308     $t->get_ok('/cities?_order_by=-name')
309       ->status_is(200)
310       ->json_has('/0')
311       ->json_has('/1')
312       ->json_is('/0/name' => 'C')
313       ->json_is('/1/name' => 'C')
314       ->json_is('/2/name' => 'B')
315       ->json_is('/3/name' => 'A')
316       ->json_hasnt('/4');
317
318     $schema->storage->txn_rollback;
319 };
320
321 subtest 'objects.search helper, encoding' => sub {
322
323     plan tests => 5;
324
325     $schema->storage->txn_begin;
326
327     Koha::Cities->delete;
328
329     $builder->build_object({ class => 'Koha::Cities', value => { city_name => 'A', city_country => 'Argentina' } });
330     $builder->build_object({ class => 'Koha::Cities', value => { city_name => 'B', city_country => '❤Argentina❤' } });
331
332     my $t = Test::Mojo->new;
333     $t->get_ok('/cities?q={"country": "❤Argentina❤"}')
334       ->status_is(200)
335       ->json_has('/0')
336       ->json_hasnt('/1')
337       ->json_is('/0/name' => 'B');
338
339     $schema->storage->txn_rollback;
340 };
341
342 subtest 'objects.search helper, X-Total-Count and X-Base-Total-Count' => sub {
343
344     plan tests => 8;
345
346     $schema->storage->txn_begin;
347
348     Koha::Cities->delete;
349
350     my $long_city_name = 'Llanfairpwllgwyngyll';
351     for my $i ( 1 .. length($long_city_name) ) {
352         $builder->build_object(
353             {
354                 class => 'Koha::Cities',
355                 value => {
356                     city_name    => substr( $long_city_name, 0, $i ),
357                     city_country => 'Wales'
358                 }
359             }
360         );
361     }
362
363     my $t = Test::Mojo->new;
364     $t->get_ok('/cities?name=L&_per_page=10&_page=1&_match=starts_with')
365       ->status_is(200)
366       ->header_is( 'X-Total-Count' => 20, 'X-Total-Count header present' )
367       ->header_is( 'X-Base-Total-Count' => 20, 'X-Base-Total-Count header present' );
368
369     $t->get_ok('/cities?name=Llan&_per_page=10&_page=1&_match=starts_with')
370       ->status_is(200)
371       ->header_is( 'X-Total-Count' => 17, 'X-Total-Count header present' )
372       ->header_is('X-Base-Total-Count' => 20, 'X-Base-Total-Count header present' );
373
374     $schema->storage->txn_rollback;
375 };
376
377 subtest 'objects.search helper, embed' => sub {
378
379     plan tests => 2;
380
381     $schema->storage->txn_begin;
382
383     my $order = $builder->build_object({ class => 'Koha::Acquisition::Orders' });
384
385     my $t = Test::Mojo->new;
386     $t->get_ok('/orders?order_id=' . $order->ordernumber)
387       ->json_is('/0',$order->to_api({ embed => ( { fund => {} } ) }));
388
389     $schema->storage->txn_rollback;
390 };
391
392 subtest 'objects.search helper with query parameter' => sub {
393     plan tests => 4;
394
395     $schema->storage->txn_begin;
396
397     my $patron1 = $builder->build_object( { class => "Koha::Patrons" } );
398     my $patron2 = $builder->build_object( { class => "Koha::Patrons" } );
399     my $biblio1 = $builder->build_sample_biblio;
400     my $biblio2 = $builder->build_sample_biblio;
401     my $biblio3 = $builder->build_sample_biblio;
402     my $suggestion1 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron1->borrowernumber, biblionumber => $biblio1->biblionumber} } );
403     my $suggestion2 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio2->biblionumber} } );
404     my $suggestion3 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio3->biblionumber} } );
405
406     my $t = Test::Mojo->new;
407     $t->get_ok('/biblios' => json => {"suggestions.suggester.patron_id" => $patron1->borrowernumber })
408       ->json_is('/count' => 1, 'there should be 1 biblio with suggestions of patron 1');
409
410     $t->get_ok('/biblios' => json => {"suggestions.suggester.patron_id" => $patron2->borrowernumber })
411       ->json_is('/count' => 2, 'there should be 2 biblios with suggestions of patron 2');
412
413     $schema->storage->txn_rollback;
414 };
415
416 subtest 'objects.search helper with q parameter' => sub {
417     plan tests => 4;
418
419     $schema->storage->txn_begin;
420
421     my $patron1 = $builder->build_object( { class => "Koha::Patrons" } );
422     my $patron2 = $builder->build_object( { class => "Koha::Patrons" } );
423     my $biblio1 = $builder->build_sample_biblio;
424     my $biblio2 = $builder->build_sample_biblio;
425     my $biblio3 = $builder->build_sample_biblio;
426     my $suggestion1 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron1->borrowernumber, biblionumber => $biblio1->biblionumber} } );
427     my $suggestion2 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio2->biblionumber} } );
428     my $suggestion3 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio3->biblionumber} } );
429
430     my $t = Test::Mojo->new;
431     $t->get_ok('/biblios?q={"suggestions.suggester.patron_id": "'.$patron1->borrowernumber.'"}')
432       ->json_is('/count' => 1, 'there should be 1 biblio with suggestions of patron 1');
433
434     $t->get_ok('/biblios?q={"suggestions.suggester.patron_id": "'.$patron2->borrowernumber.'"}')
435       ->json_is('/count' => 2, 'there should be 2 biblios with suggestions of patron 2');
436
437     $schema->storage->txn_rollback;
438 };
439
440 subtest 'objects.search helper with x-koha-query header' => sub {
441     plan tests => 4;
442
443     $schema->storage->txn_begin;
444
445     my $patron1 = $builder->build_object( { class => "Koha::Patrons" } );
446     my $patron2 = $builder->build_object( { class => "Koha::Patrons" } );
447     my $biblio1 = $builder->build_sample_biblio;
448     my $biblio2 = $builder->build_sample_biblio;
449     my $biblio3 = $builder->build_sample_biblio;
450     my $suggestion1 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron1->borrowernumber, biblionumber => $biblio1->biblionumber} } );
451     my $suggestion2 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio2->biblionumber} } );
452     my $suggestion3 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio3->biblionumber} } );
453
454     my $t = Test::Mojo->new;
455     $t->get_ok('/biblios' => {'x-koha-query' => '{"suggestions.suggester.patron_id": "'.$patron1->borrowernumber.'"}'})
456       ->json_is('/count' => 1, 'there should be 1 biblio with suggestions of patron 1');
457
458     $t->get_ok('/biblios' => {'x-koha-query' => '{"suggestions.suggester.patron_id": "'.$patron2->borrowernumber.'"}'})
459       ->json_is('/count' => 2, 'there should be 2 biblios with suggestions of patron 2');
460
461     $schema->storage->txn_rollback;
462 };
463
464 subtest 'objects.search helper with all query methods' => sub {
465     plan tests => 6;
466
467     $schema->storage->txn_begin;
468
469     my $patron1 = $builder->build_object( { class => "Koha::Patrons" , value => {firstname=>'patron1'} } );
470     my $patron2 = $builder->build_object( { class => "Koha::Patrons" , value => {firstname=>'patron2'} } );
471     my $biblio1 = $builder->build_sample_biblio;
472     my $biblio2 = $builder->build_sample_biblio;
473     my $biblio3 = $builder->build_sample_biblio;
474     my $suggestion1 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron1->borrowernumber, biblionumber => $biblio1->biblionumber} } );
475     my $suggestion2 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio2->biblionumber} } );
476     my $suggestion3 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio3->biblionumber} } );
477
478     my $t = Test::Mojo->new;
479     $t->get_ok('/biblios?q={"suggestions.suggester.firstname": "'.$patron1->firstname.'"}' => {'x-koha-query' => '{"suggestions.suggester.patron_id": "'.$patron1->borrowernumber.'"}'} => json => {"suggestions.suggester.cardnumber" => $patron1->cardnumber})
480       ->json_is('/count' => 1, 'there should be 1 biblio with suggestions of patron 1');
481
482     $t->get_ok('/biblios?q={"suggestions.suggester.firstname": "'.$patron2->firstname.'"}' => {'x-koha-query' => '{"suggestions.suggester.patron_id": "'.$patron2->borrowernumber.'"}'} => json => {"suggestions.suggester.cardnumber" => $patron2->cardnumber})
483       ->json_is('/count' => 2, 'there should be 2 biblios with suggestions of patron 2');
484
485     $t->get_ok('/biblios?q={"suggestions.suggester.firstname": "'.$patron1->firstname.'"}' => {'x-koha-query' => '{"suggestions.suggester.patron_id": "'.$patron2->borrowernumber.'"}'} => json => {"suggestions.suggester.cardnumber" => $patron2->cardnumber})
486       ->json_is('/count' => 0, 'there shouldn\'t be biblios where suggester has patron1 fistname and patron2 id');
487
488     $schema->storage->txn_rollback;
489 };
490
491 subtest 'objects.search helper order by embedded columns' => sub {
492     plan tests => 3;
493
494     $schema->storage->txn_begin;
495
496     my $patron1 = $builder->build_object( { class => "Koha::Patrons" , value => {firstname=>'patron1'} } );
497     my $patron2 = $builder->build_object( { class => "Koha::Patrons" , value => {firstname=>'patron2'} } );
498     my $biblio1 = $builder->build_sample_biblio;
499     my $biblio2 = $builder->build_sample_biblio;
500     my $suggestion1 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron1->borrowernumber, biblionumber => $biblio1->biblionumber} } );
501     my $suggestion2 = $builder->build_object( { class => "Koha::Suggestions", value => { suggestedby => $patron2->borrowernumber, biblionumber => $biblio2->biblionumber} } );
502
503     my $t = Test::Mojo->new;
504     $t->get_ok('/biblios?_order_by=-suggestions.suggester.firstname' => json => [{"me.biblio_id" => $biblio1->biblionumber}, {"me.biblio_id" => $biblio2->biblionumber}])
505       ->json_is('/biblios/0/biblio_id' => $biblio2->biblionumber, 'Biblio 2 should be first')
506       ->json_is('/biblios/1/biblio_id' => $biblio1->biblionumber, 'Biblio 1 should be second');
507
508     $schema->storage->txn_rollback;
509 };
510
511 subtest 'objects.find helper' => sub {
512
513     plan tests => 9;
514
515     my $t = Test::Mojo->new;
516
517     $schema->storage->txn_begin;
518
519     my $city_1 = $builder->build_object( { class => 'Koha::Cities' } );
520     my $city_2 = $builder->build_object( { class => 'Koha::Cities' } );
521
522     $t->get_ok( '/cities/' . $city_1->id )
523       ->status_is(200)
524       ->json_is( $city_1->to_api );
525
526     $t->get_ok( '/cities/' . $city_2->id )
527       ->status_is(200)
528       ->json_is( $city_2->to_api );
529
530     # Remove the city
531     my $city_2_id = $city_2->id;
532     $city_2->delete;
533     $t->get_ok( '/cities/' . $city_2_id )
534       ->status_is(200)
535       ->json_is( undef );
536
537     $schema->storage->txn_rollback;
538 };
539
540 subtest 'objects.find helper, embed' => sub {
541
542     plan tests => 2;
543
544     my $t = Test::Mojo->new;
545
546     $schema->storage->txn_begin;
547
548     my $order = $builder->build_object({ class => 'Koha::Acquisition::Orders' });
549
550     $t->get_ok( '/orders/' . $order->ordernumber )
551       ->json_is( $order->to_api( { embed => ( { fund => {} } ) } ) );
552
553     $schema->storage->txn_rollback;
554 };
555
556 subtest 'objects.search helper, public requests' => sub {
557
558     plan tests => 3;
559
560     $schema->storage->txn_begin;
561
562     my $library_1 = $builder->build_object({ class => 'Koha::Libraries', value => { branchname => 'A' } });
563     my $library_2 = $builder->build_object({ class => 'Koha::Libraries', value => { branchname => 'B' } });
564
565     my $t = Test::Mojo->new;
566
567     $t->get_ok( '/libraries/'.$library_1->id.'/'.$library_2->id )
568       ->json_is('/0' => $library_1->to_api({ public => 1 }), 'Public representation of $library_1 is retrieved')
569       ->json_is('/1' => $library_2->to_api({ public => 1 }), 'Public representation of $library_2 is retrieved');
570
571     $schema->storage->txn_rollback;
572 };
573
574 subtest 'objects.search helper, search_limited() tests' => sub {
575
576     plan tests => 9;
577
578     $schema->storage->txn_begin;
579
580     my $library_1 = $builder->build_object({ class => 'Koha::Libraries' });
581     my $library_2 = $builder->build_object({ class => 'Koha::Libraries' });
582
583     my $patron_1 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $library_1->id } });
584     my $patron_2 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $library_1->id } });
585     my $patron_3 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $library_2->id } });
586
587     my @libraries_where_can_see_patrons = ( $library_1->id, $library_2->id );
588
589     my $t = Test::Mojo->new;
590
591     my $mocked_patron = Test::MockModule->new('Koha::Patron');
592     $mocked_patron->mock( 'libraries_where_can_see_patrons', sub
593         {
594             return @libraries_where_can_see_patrons;
595         }
596     );
597
598     my $patron = $builder->build_object(
599         {
600             class => 'Koha::Patrons',
601             value => { flags => 2**4 }    # borrowers flag = 4
602         }
603     );
604
605     t::lib::Mocks::mock_userenv({ patron => $patron });
606
607     $t->get_ok( "/my_patrons?q=" . encode_json( { library_id => [ $library_1->id, $library_2->id ] } ) )
608       ->status_is(200)
609       ->json_is( '/0/patron_id' => $patron_1->id )
610       ->json_is( '/1/patron_id' => $patron_2->id )
611       ->json_is( '/2/patron_id' => $patron_3->id );
612
613     @libraries_where_can_see_patrons = ( $library_2->id );
614
615     my $res = $t->get_ok( "/my_patrons?q=" . encode_json( { library_id => [ $library_1->id, $library_2->id ] } ) )
616       ->status_is(200)
617       ->json_is( '/0/patron_id' => $patron_3->id, 'Returns the only allowed patron' )
618       ->tx->res->json;
619
620     is( scalar @{$res}, 1, 'Only one patron returned' );
621
622     $schema->storage->txn_rollback;
623 };
624
625 subtest 'objects.find helper with expanded authorised values' => sub {
626
627     plan tests => 18;
628
629     $schema->storage->txn_begin;
630
631     my $t = Test::Mojo->new;
632
633     Koha::AuthorisedValues->search( { category => 'Countries' } )->delete;
634     Koha::AuthorisedValueCategories->search( { category_name => 'Countries' } )
635       ->delete;
636
637     my $cat = $builder->build_object(
638         {
639             class => 'Koha::AuthorisedValueCategories',
640             value => { category_name => 'Countries' }
641         }
642     );
643     my $fr = $builder->build_object(
644         {
645             class => 'Koha::AuthorisedValues',
646             value => {
647                 authorised_value => 'FR',
648                 lib              => 'France',
649                 category         => $cat->category_name
650             }
651         }
652     );
653     my $us = $builder->build_object(
654         {
655             class => 'Koha::AuthorisedValues',
656             value => {
657                 authorised_value => 'US',
658                 lib              => 'United States of America',
659                 category         => $cat->category_name
660             }
661         }
662     );
663     my $ar = $builder->build_object(
664         {
665             class => 'Koha::AuthorisedValues',
666             value => {
667                 authorised_value => 'AR',
668                 lib              => 'Argentina',
669                 category         => $cat->category_name
670             }
671         }
672     );
673
674     my $city_class = Test::MockModule->new('Koha::City');
675     $city_class->mock(
676         'api_av_mapping',
677         sub {
678             my ($self, $params) = @_;
679             use Koha::AuthorisedValues;
680
681             my $av = Koha::AuthorisedValues->find(
682                 {
683                     authorised_value => $self->city_country,
684                     category         => 'Countries'
685                 }
686             );
687
688             return {
689                 city_country => {
690                     category => $av->category,
691                     str      => ( $params->{public} ) ? $av->lib_opac : $av->lib,
692                     type     => 'av',
693                 }
694             };
695         }
696     );
697
698     my $manuel = $builder->build_object(
699         {
700             class => 'Koha::Cities',
701             value => {
702                 city_name    => 'Manuel',
703                 city_country => 'AR'
704             }
705         }
706     );
707     my $manuela = $builder->build_object(
708         {
709             class => 'Koha::Cities',
710             value => {
711                 city_name    => 'Manuela',
712                 city_country => 'US'
713             }
714         }
715     );
716
717     $t->get_ok( '/cities/' . $manuel->id => { 'x-koha-embed' => '+av_expand' } )
718       ->status_is(200)->json_is( '/name' => 'Manuel' )
719       ->json_has('/_str')
720       ->json_is( '/_str/country/type'     => 'av' )
721       ->json_is( '/_str/country/category' => $cat->category_name )
722       ->json_is( '/_str/country/str'      => $ar->lib );
723
724     $t->get_ok( '/cities/' . $manuel->id => { 'x-koha-av-expand' => 0 } )
725       ->status_is(200)->json_is( '/name' => 'Manuel' )
726       ->json_hasnt('/_str');
727
728     $t->get_ok( '/cities/' . $manuela->id => { 'x-koha-embed' => '+av_expand' } )
729       ->status_is(200)->json_is( '/name' => 'Manuela' )
730       ->json_has('/_str')
731       ->json_is( '/_str/country/type'     => 'av' )
732       ->json_is( '/_str/country/category' => $cat->category_name )
733       ->json_is( '/_str/country/str'      => $us->lib );
734
735     $schema->storage->txn_rollback;
736 };
737
738 subtest 'objects.search helper with expanded authorised values' => sub {
739
740     plan tests => 24;
741
742     my $t = Test::Mojo->new;
743
744     $schema->storage->txn_begin;
745
746     Koha::AuthorisedValues->search( { category => 'Countries' } )->delete;
747     Koha::AuthorisedValueCategories->search( { category_name => 'Countries' } )
748       ->delete;
749
750     my $cat = $builder->build_object(
751         {
752             class => 'Koha::AuthorisedValueCategories',
753             value => { category_name => 'Countries' }
754         }
755     );
756     my $fr = $builder->build_object(
757         {
758             class => 'Koha::AuthorisedValues',
759             value => {
760                 authorised_value => 'FR',
761                 lib              => 'France',
762                 category         => $cat->category_name
763             }
764         }
765     );
766     my $us = $builder->build_object(
767         {
768             class => 'Koha::AuthorisedValues',
769             value => {
770                 authorised_value => 'US',
771                 lib              => 'United States of America',
772                 category         => $cat->category_name
773             }
774         }
775     );
776     my $ar = $builder->build_object(
777         {
778             class => 'Koha::AuthorisedValues',
779             value => {
780                 authorised_value => 'AR',
781                 lib              => 'Argentina',
782                 category         => $cat->category_name
783             }
784         }
785     );
786
787     my $city_class = Test::MockModule->new('Koha::City');
788     $city_class->mock(
789         'api_av_mapping',
790         sub {
791             my ($self, $params) = @_;
792             use Koha::AuthorisedValues;
793
794             my $av = Koha::AuthorisedValues->find(
795                 {
796                     authorised_value => $self->city_country,
797                     category         => 'Countries'
798                 }
799             );
800
801             return {
802                 city_country => {
803                     category => $av->category,
804                     str      => ( $params->{public} ) ? $av->lib_opac : $av->lib,
805                     type     => 'av',
806                 }
807             };
808         }
809     );
810
811
812     $builder->build_object(
813         {
814             class => 'Koha::Cities',
815             value => {
816                 city_name    => 'Manuel',
817                 city_country => 'AR'
818             }
819         }
820     );
821     $builder->build_object(
822         {
823             class => 'Koha::Cities',
824             value => {
825                 city_name    => 'Manuela',
826                 city_country => 'US'
827             }
828         }
829     );
830
831     $t->get_ok( '/cities?name=manuel&_per_page=4&_page=1&_match=starts_with' =>
832           { 'x-koha-embed' => '+av_expand' } )->status_is(200)
833       ->json_has('/0')->json_has('/1')->json_hasnt('/2')
834       ->json_is( '/0/name' => 'Manuel' )
835       ->json_has('/0/_str')
836       ->json_is( '/0/_str/country/str'      => $ar->lib )
837       ->json_is( '/0/_str/country/type'     => 'av' )
838       ->json_is( '/0/_str/country/category' => $cat->category_name )
839       ->json_is( '/1/name' => 'Manuela' )
840       ->json_has('/1/_str')
841       ->json_is( '/1/_str/country/str' => $us->lib )
842       ->json_is( '/1/_str/country/type'     => 'av' )
843       ->json_is( '/1/_str/country/category' => $cat->category_name );
844
845     $t->get_ok( '/cities?name=manuel&_per_page=4&_page=1&_match=starts_with' )->status_is(200)
846       ->json_has('/0')->json_has('/1')->json_hasnt('/2')
847       ->json_is( '/0/name' => 'Manuel' )->json_hasnt('/0/_str')
848       ->json_is( '/1/name' => 'Manuela' )->json_hasnt('/1/_str');
849
850
851     $schema->storage->txn_rollback;
852 };