Bug 24302: Add a way to specify nested objects to embed in OpenAPI
[koha.git] / t / Koha / REST / Plugin / Query.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 # Dummy app for testing the plugin
21 use Mojolicious::Lite;
22 use Try::Tiny;
23
24 use Koha::Cities;
25
26 app->log->level('error');
27
28 plugin 'Koha::REST::Plugin::Query';
29
30 get '/empty' => sub {
31     my $c = shift;
32     $c->render( json => undef, status => 200 );
33 };
34
35 get '/query' => sub {
36     my $c     = shift;
37     my $input = {
38         _page     => 2,
39         _per_page => 3,
40         firstname => 'Manuel',
41         surname   => 'Cohen Arazi'
42     };
43     my ( $filtered_params, $reserved_params ) = $c->extract_reserved_params($input);
44     $c->render(
45         json => {
46             filtered_params => $filtered_params,
47             reserved_params => $reserved_params
48         },
49         status => 200
50     );
51 };
52
53 get '/query_full' => sub {
54     my $c     = shift;
55     my $input = {
56         _match    => 'exact',
57         _order_by => 'blah',
58         _page     => 2,
59         _per_page => 3,
60         firstname => 'Manuel',
61         surname   => 'Cohen Arazi'
62     };
63     my ( $filtered_params, $reserved_params ) = $c->extract_reserved_params($input);
64     $c->render(
65         json => {
66             filtered_params => $filtered_params,
67             reserved_params => $reserved_params
68         },
69         status => 200
70     );
71 };
72
73 get '/dbic_merge_sorting' => sub {
74     my $c = shift;
75     my $attributes = { a => 'a', b => 'b' };
76     $attributes = $c->dbic_merge_sorting(
77         {
78             attributes => $attributes,
79             params     => { _match => 'exact', _order_by => [ 'uno', '-dos', '+tres', ' cuatro' ] }
80         }
81     );
82     $c->render( json => $attributes, status => 200 );
83 };
84
85 get '/dbic_merge_sorting_single' => sub {
86     my $c = shift;
87     my $attributes = { a => 'a', b => 'b' };
88     $attributes = $c->dbic_merge_sorting(
89         {
90             attributes => $attributes,
91             params     => { _match => 'exact', _order_by => '-uno' }
92         }
93     );
94     $c->render( json => $attributes, status => 200 );
95 };
96
97 get '/dbic_merge_sorting_result_set' => sub {
98     my $c = shift;
99     my $attributes = { a => 'a', b => 'b' };
100     my $result_set = Koha::Cities->new;
101     $attributes = $c->dbic_merge_sorting(
102         {
103             attributes => $attributes,
104             params     => { _match => 'exact', _order_by => [ 'name', '-postal_code', '+country', ' state' ] },
105             result_set => $result_set
106         }
107     );
108     $c->render( json => $attributes, status => 200 );
109 };
110
111 get '/build_query' => sub {
112     my $c = shift;
113     my ( $filtered_params, $reserved_params ) =
114       $c->extract_reserved_params( $c->req->params->to_hash );
115     my $query;
116     try {
117         $query = $c->build_query_params( $filtered_params, $reserved_params );
118         $c->render( json => { query => $query }, status => 200 );
119     }
120     catch {
121         $c->render(
122             json => { exception_msg => $_->message, exception_type => ref($_) },
123             status => 400
124         );
125     };
126 };
127
128 get '/stash_embed' => sub {
129     my $c = shift;
130
131     try {
132         $c->stash_embed(
133             {
134                 spec => {
135                     'x-koha-embed' => [
136                         'checkouts',
137                         'checkouts.item',
138                         'library'
139                     ]
140                 }
141             }
142         );
143
144         $c->render(
145             status => 200,
146             json   => $c->stash( 'koha.embed' )
147         );
148     }
149     catch {
150         $c->render(
151             status => 400,
152             json   => { error => "$_" }
153         );
154     };
155 };
156
157 get '/stash_embed_no_spec' => sub {
158     my $c = shift;
159
160     try {
161         $c->stash_embed({ spec => {} });
162
163         $c->render(
164             status => 200,
165             json   => $c->stash( 'koha.embed' )
166         );
167     }
168     catch {
169         $c->render(
170             status => 400,
171             json   => { error => "$_" }
172         );
173     };
174 };
175
176 sub to_model {
177     my ($args) = @_;
178     $args->{three} = delete $args->{tres}
179         if exists $args->{tres};
180     return $args;
181 }
182
183 # The tests
184
185 use Test::More tests => 4;
186 use Test::Mojo;
187
188 subtest 'extract_reserved_params() tests' => sub {
189
190     plan tests => 8;
191
192     my $t = Test::Mojo->new;
193
194     $t->get_ok('/query')->status_is(200)
195       ->json_is( '/filtered_params' =>
196           { firstname => 'Manuel', surname => 'Cohen Arazi' } )
197       ->json_is( '/reserved_params' => { _page => 2, _per_page => 3 } );
198
199     $t->get_ok('/query_full')->status_is(200)
200       ->json_is(
201         '/filtered_params' => {
202             firstname => 'Manuel',
203             surname   => 'Cohen Arazi'
204         } )
205       ->json_is(
206         '/reserved_params' => {
207             _page     => 2,
208             _per_page => 3,
209             _match    => 'exact',
210             _order_by => 'blah'
211         } );
212
213 };
214
215 subtest 'dbic_merge_sorting() tests' => sub {
216
217     plan tests => 15;
218
219     my $t = Test::Mojo->new;
220
221     $t->get_ok('/dbic_merge_sorting')->status_is(200)
222       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
223       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
224         '/order_by' => [
225             'uno',
226             { -desc => 'dos' },
227             { -asc  => 'tres' },
228             { -asc  => 'cuatro' }
229         ]
230       );
231
232     $t->get_ok('/dbic_merge_sorting_result_set')->status_is(200)
233       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
234       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
235         '/order_by' => [
236             'city_name',
237             { -desc => 'city_zipcode' },
238             { -asc  => 'city_country' },
239             { -asc  => 'city_state' }
240         ]
241       );
242
243     $t->get_ok('/dbic_merge_sorting_single')->status_is(200)
244       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
245       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
246         '/order_by' => { '-desc' => 'uno' }
247       );
248 };
249
250 subtest '_build_query_params_from_api' => sub {
251
252     plan tests => 16;
253
254     my $t = Test::Mojo->new;
255
256     # _match => contains
257     $t->get_ok('/build_query?_match=contains&title=Ender&author=Orson')
258       ->status_is(200)
259       ->json_is( '/query' =>
260           { author => { like => '%Orson%' }, title => { like => '%Ender%' } } );
261
262     # _match => starts_with
263     $t->get_ok('/build_query?_match=starts_with&title=Ender&author=Orson')
264       ->status_is(200)
265       ->json_is( '/query' =>
266           { author => { like => 'Orson%' }, title => { like => 'Ender%' } } );
267
268     # _match => ends_with
269     $t->get_ok('/build_query?_match=ends_with&title=Ender&author=Orson')
270       ->status_is(200)
271       ->json_is( '/query' =>
272           { author => { like => '%Orson' }, title => { like => '%Ender' } } );
273
274     # _match => exact
275     $t->get_ok('/build_query?_match=exact&title=Ender&author=Orson')
276       ->status_is(200)
277       ->json_is( '/query' => { author => 'Orson', title => 'Ender' } );
278
279     # _match => blah
280     $t->get_ok('/build_query?_match=blah&title=Ender&author=Orson')
281       ->status_is(400)
282       ->json_is( '/exception_msg'  => 'Invalid value for _match param (blah)' )
283       ->json_is( '/exception_type' => 'Koha::Exceptions::WrongParameter' );
284
285 };
286
287 subtest 'stash_embed() tests' => sub {
288
289     plan tests => 12;
290
291     my $t = Test::Mojo->new;
292
293     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item' } )
294       ->status_is(200)
295       ->json_is( { checkouts => { children => { item => {} } } } );
296
297     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item,library' } )
298       ->status_is(200)
299       ->json_is( { checkouts => { children => { item => {} } }, library => {} } );
300
301     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item,patron' } )
302       ->status_is(400)
303       ->json_is(
304         {
305             error => 'Embeding patron is not authorised. Check your x-koha-embed headers or remove it.'
306         }
307       );
308
309     $t->get_ok( '/stash_embed_no_spec' => { 'x-koha-embed' => 'checkouts,checkouts.item,patron' } )
310       ->status_is(400)
311       ->json_is(
312         {
313             error => 'Embedding objects is not allowed on this endpoint.'
314         }
315       );
316
317 };