View | Details | Raw Unified | Return to bug 23517
Collapse All | Expand All

(-)a/t/db_dependent/api/v1/holds.t (-141 / +54 lines)
Lines 40-72 my $builder = t::lib::TestBuilder->new(); Link Here
40
40
41
$schema->storage->txn_begin;
41
$schema->storage->txn_begin;
42
42
43
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
43
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
44
# this affects the other REST api tests
45
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
46
44
47
$ENV{REMOTE_ADDR} = '127.0.0.1';
48
my $t = Test::Mojo->new('Koha::REST::V1');
45
my $t = Test::Mojo->new('Koha::REST::V1');
49
my $tx;
50
46
51
my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
47
my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
52
my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
48
my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
53
my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
49
my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
54
50
51
# Generic password for everyone
52
my $password = 'thePassword123';
53
55
# User without any permissions
54
# User without any permissions
56
my $nopermission = $builder->build({
55
my $nopermission = $builder->build_object({
57
    source => 'Borrower',
56
    class => 'Koha::Patrons',
58
    value => {
57
    value => {
59
        branchcode   => $branchcode,
58
        branchcode   => $branchcode,
60
        categorycode => $categorycode,
59
        categorycode => $categorycode,
61
        flags        => 0
60
        flags        => 0
62
    }
61
    }
63
});
62
});
64
my $session_nopermission = C4::Auth::get_session('');
63
$nopermission->set_password( { password => $password, skip_validation => 1 } );
65
$session_nopermission->param('number', $nopermission->{ borrowernumber });
64
my $nopermission_userid = $nopermission->userid;
66
$session_nopermission->param('id', $nopermission->{ userid });
67
$session_nopermission->param('ip', '127.0.0.1');
68
$session_nopermission->param('lasttime', time());
69
$session_nopermission->flush;
70
65
71
my $patron_1 = $builder->build_object(
66
my $patron_1 = $builder->build_object(
72
    {
67
    {
Lines 79-84 my $patron_1 = $builder->build_object( Link Here
79
        }
74
        }
80
    }
75
    }
81
);
76
);
77
$patron_1->set_password( { password => $password, skip_validation => 1 } );
78
my $userid_1 = $patron_1->userid;
82
79
83
my $patron_2 = $builder->build_object(
80
my $patron_2 = $builder->build_object(
84
    {
81
    {
Lines 91-96 my $patron_2 = $builder->build_object( Link Here
91
        }
88
        }
92
    }
89
    }
93
);
90
);
91
$patron_2->set_password( { password => $password, skip_validation => 1 } );
92
my $userid_2 = $patron_2->userid;
94
93
95
my $patron_3 = $builder->build_object(
94
my $patron_3 = $builder->build_object(
96
    {
95
    {
Lines 103-138 my $patron_3 = $builder->build_object( Link Here
103
        }
102
        }
104
    }
103
    }
105
);
104
);
105
$patron_3->set_password( { password => $password, skip_validation => 1 } );
106
my $userid_3 = $patron_3->userid;
107
108
my $biblio_1 = $builder->build_sample_biblio;
109
my $item_1   = $builder->build_sample_item({ biblionumber => $biblio_1->biblionumber, itype => $itemtype });
106
110
107
# Get sessions
111
my $biblio_2 = $builder->build_sample_biblio;
108
my $session = C4::Auth::get_session('');
112
my $item_2   = $builder->build_sample_item({ biblionumber => $biblio_2->biblionumber, itype => $itemtype });
109
$session->param('number', $patron_1->borrowernumber);
110
$session->param('id', $patron_1->userid);
111
$session->param('ip', '127.0.0.1');
112
$session->param('lasttime', time());
113
$session->flush;
114
my $session2 = C4::Auth::get_session('');
115
$session2->param('number', $patron_2->borrowernumber);
116
$session2->param('id', $patron_2->userid);
117
$session2->param('ip', '127.0.0.1');
118
$session2->param('lasttime', time());
119
$session2->flush;
120
my $session3 = C4::Auth::get_session('');
121
$session3->param('number', $patron_3->borrowernumber);
122
$session3->param('id', $patron_3->userid);
123
$session3->param('ip', '127.0.0.1');
124
$session3->param('lasttime', time());
125
$session3->flush;
126
127
my $biblionumber = create_biblio('RESTful Web APIs');
128
my $item = create_item($biblionumber, 'TEST000001');
129
my $itemnumber = $item->{itemnumber};
130
$item->{itype} = $itemtype;
131
C4::Items::ModItem($item, $biblionumber, $itemnumber);
132
133
my $biblionumber2 = create_biblio('RESTful Web APIs');
134
my $item2 = create_item($biblionumber2, 'TEST000002');
135
my $itemnumber2 = $item2->{itemnumber};
136
113
137
my $dbh = C4::Context->dbh;
114
my $dbh = C4::Context->dbh;
138
$dbh->do('DELETE FROM reserves');
115
$dbh->do('DELETE FROM reserves');
Lines 143-161 $dbh->do('DELETE FROM issuingrules'); Link Here
143
    }, {}, '*', '*', '*', 1);
120
    }, {}, '*', '*', '*', 1);
144
121
145
my $reserve_id = C4::Reserves::AddReserve($branchcode, $patron_1->borrowernumber,
122
my $reserve_id = C4::Reserves::AddReserve($branchcode, $patron_1->borrowernumber,
146
    $biblionumber, undef, 1, undef, undef, undef, '', $itemnumber);
123
    $biblio_1->biblionumber, undef, 1, undef, undef, undef, '', $item_1->itemnumber);
147
124
148
# Add another reserve to be able to change first reserve's rank
125
# Add another reserve to be able to change first reserve's rank
149
my $reserve_id2 = C4::Reserves::AddReserve($branchcode, $patron_2->borrowernumber,
126
my $reserve_id2 = C4::Reserves::AddReserve($branchcode, $patron_2->borrowernumber,
150
    $biblionumber, undef, 2, undef, undef, undef, '', $itemnumber);
127
    $biblio_1->biblionumber, undef, 2, undef, undef, undef, '', $item_1->itemnumber);
151
128
152
my $suspended_until = DateTime->now->add(days => 10)->truncate( to => 'day' );
129
my $suspended_until = DateTime->now->add(days => 10)->truncate( to => 'day' );
153
my $expiration_date = DateTime->now->add(days => 10)->truncate( to => 'day' );
130
my $expiration_date = DateTime->now->add(days => 10)->truncate( to => 'day' );
154
131
155
my $post_data = {
132
my $post_data = {
156
    patron_id => int($patron_1->borrowernumber),
133
    patron_id => int($patron_1->borrowernumber),
157
    biblio_id => int($biblionumber),
134
    biblio_id => int($biblio_1->biblionumber),
158
    item_id => int($itemnumber),
135
    item_id => int($item_1->itemnumber),
159
    pickup_library_id => $branchcode,
136
    pickup_library_id => $branchcode,
160
    expiration_date => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
137
    expiration_date => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
161
    priority => 2,
138
    priority => 2,
Lines 177-205 subtest "Test endpoints without authentication" => sub { Link Here
177
      ->status_is(401);
154
      ->status_is(401);
178
};
155
};
179
156
180
181
subtest "Test endpoints without permission" => sub {
157
subtest "Test endpoints without permission" => sub {
158
182
    plan tests => 10;
159
    plan tests => 10;
183
160
184
    $tx = $t->ua->build_tx(GET => "/api/v1/holds?patron_id=" . $patron_1->borrowernumber);
161
    $t->get_ok( "//$nopermission_userid:$password@/api/v1/holds?patron_id=" . $patron_1->borrowernumber ) # no permission
185
    $tx->req->cookies({name => 'CGISESSID', value => $session_nopermission->id});
186
    $t->request_ok($tx) # no permission
187
      ->status_is(403);
162
      ->status_is(403);
188
    $tx = $t->ua->build_tx(GET => "/api/v1/holds?patron_id=" . $patron_1->borrowernumber);
163
189
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
164
    $t->get_ok( "//$userid_3:$password@/api/v1/holds?patron_id=" . $patron_1->borrowernumber )    # no permission
190
    $t->request_ok($tx) # reserveforothers permission
191
      ->status_is(403);
165
      ->status_is(403);
192
    $tx = $t->ua->build_tx(POST => "/api/v1/holds" => json => $post_data );
166
193
    $tx->req->cookies({name => 'CGISESSID', value => $session_nopermission->id});
167
    $t->post_ok( "//$nopermission_userid:$password@/api/v1/holds" => json => $post_data )
194
    $t->request_ok($tx) # no permission
195
      ->status_is(403);
168
      ->status_is(403);
196
    $tx = $t->ua->build_tx(PUT => "/api/v1/holds/0" => json => $put_data );
169
197
    $tx->req->cookies({name => 'CGISESSID', value => $session_nopermission->id});
170
    $t->put_ok( "//$nopermission_userid:$password@/api/v1/holds/0" => json => $put_data )
198
    $t->request_ok($tx) # no permission
199
      ->status_is(403);
171
      ->status_is(403);
200
    $tx = $t->ua->build_tx(DELETE => "/api/v1/holds/0");
172
201
    $tx->req->cookies({name => 'CGISESSID', value => $session_nopermission->id});
173
    $t->delete_ok( "//$nopermission_userid:$password@/api/v1/holds/0" )
202
    $t->request_ok($tx) # no permission
203
      ->status_is(403);
174
      ->status_is(403);
204
};
175
};
205
176
Lines 207-296 subtest "Test endpoints with permission" => sub { Link Here
207
178
208
    plan tests => 44;
179
    plan tests => 44;
209
180
210
    $tx = $t->ua->build_tx(GET => '/api/v1/holds');
181
    $t->get_ok( "//$userid_1:$password@/api/v1/holds" )
211
    $tx->req->cookies({name => 'CGISESSID', value => $session->id});
212
    $t->request_ok($tx)
213
      ->status_is(200)
182
      ->status_is(200)
214
      ->json_has('/0')
183
      ->json_has('/0')
215
      ->json_has('/1')
184
      ->json_has('/1')
216
      ->json_hasnt('/2');
185
      ->json_hasnt('/2');
217
186
218
    $tx = $t->ua->build_tx(GET => '/api/v1/holds?priority=2');
187
    $t->get_ok( "//$userid_1:$password@/api/v1/holds?priority=2" )
219
    $tx->req->cookies({name => 'CGISESSID', value => $session->id});
220
    $t->request_ok($tx)
221
      ->status_is(200)
188
      ->status_is(200)
222
      ->json_is('/0/patron_id', $patron_2->borrowernumber)
189
      ->json_is('/0/patron_id', $patron_2->borrowernumber)
223
      ->json_hasnt('/1');
190
      ->json_hasnt('/1');
224
191
225
    $tx = $t->ua->build_tx(PUT => "/api/v1/holds/$reserve_id" => json => $put_data);
192
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => $put_data )
226
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
227
    $t->request_ok($tx)
228
      ->status_is(200)
193
      ->status_is(200)
229
      ->json_is( '/hold_id', $reserve_id )
194
      ->json_is( '/hold_id', $reserve_id )
230
      ->json_is( '/suspended_until', output_pref({ dt => $suspended_until, dateformat => 'rfc3339' }) )
195
      ->json_is( '/suspended_until', output_pref({ dt => $suspended_until, dateformat => 'rfc3339' }) )
231
      ->json_is( '/priority', 2 );
196
      ->json_is( '/priority', 2 );
232
197
233
    $tx = $t->ua->build_tx(DELETE => "/api/v1/holds/$reserve_id");
198
    $t->delete_ok( "//$userid_3:$password@/api/v1/holds/$reserve_id" )
234
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
235
    $t->request_ok($tx)
236
      ->status_is(200);
199
      ->status_is(200);
237
200
238
    $tx = $t->ua->build_tx(PUT => "/api/v1/holds/$reserve_id" => json => $put_data);
201
    $t->put_ok( "//$userid_3:$password@/api/v1/holds/$reserve_id" => json => $put_data )
239
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
240
    $t->request_ok($tx)
241
      ->status_is(404)
202
      ->status_is(404)
242
      ->json_has('/error');
203
      ->json_has('/error');
243
204
244
    $tx = $t->ua->build_tx(DELETE => "/api/v1/holds/$reserve_id");
205
    $t->delete_ok( "//$userid_3:$password@/api/v1/holds/$reserve_id" )
245
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
246
    $t->request_ok($tx)
247
      ->status_is(404)
206
      ->status_is(404)
248
      ->json_has('/error');
207
      ->json_has('/error');
249
208
250
    $tx = $t->ua->build_tx(GET => "/api/v1/holds?patron_id=" . $patron_1->borrowernumber);
209
    $t->get_ok( "//$userid_2:$password@/api/v1/holds?patron_id=" . $patron_1->borrowernumber )
251
    $tx->req->cookies({name => 'CGISESSID', value => $session2->id}); # get with borrowers flag
252
    $t->request_ok($tx)
253
      ->status_is(200)
210
      ->status_is(200)
254
      ->json_is([]);
211
      ->json_is([]);
255
212
256
    my $inexisting_borrowernumber = $patron_2->borrowernumber * 2;
213
    my $inexisting_borrowernumber = $patron_2->borrowernumber * 2;
257
    $tx = $t->ua->build_tx(GET => "/api/v1/holds?patron_id=$inexisting_borrowernumber");
214
    $t->get_ok( "//$userid_1:$password@/api/v1/holds?patron_id=$inexisting_borrowernumber")
258
    $tx->req->cookies({name => 'CGISESSID', value => $session->id});
259
    $t->request_ok($tx)
260
      ->status_is(200)
215
      ->status_is(200)
261
      ->json_is([]);
216
      ->json_is([]);
262
217
263
    $tx = $t->ua->build_tx(DELETE => "/api/v1/holds/$reserve_id2");
218
    $t->delete_ok( "//$userid_3:$password@/api/v1/holds/$reserve_id2" )
264
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
265
    $t->request_ok($tx)
266
      ->status_is(200);
219
      ->status_is(200);
267
220
268
    $tx = $t->ua->build_tx(POST => "/api/v1/holds" => json => $post_data);
221
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
269
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
270
    $t->request_ok($tx)
271
      ->status_is(201)
222
      ->status_is(201)
272
      ->json_has('/hold_id');
223
      ->json_has('/hold_id');
224
    # Get id from response
273
    $reserve_id = $t->tx->res->json->{hold_id};
225
    $reserve_id = $t->tx->res->json->{hold_id};
274
226
275
    $tx = $t->ua->build_tx(GET => "/api/v1/holds?patron_id=" . $patron_1->borrowernumber);
227
    $t->get_ok( "//$userid_1:$password@/api/v1/holds?patron_id=" . $patron_1->borrowernumber )
276
    $tx->req->cookies({name => 'CGISESSID', value => $session->id});
277
    $t->request_ok($tx)
278
      ->status_is(200)
228
      ->status_is(200)
279
      ->json_is('/0/hold_id', $reserve_id)
229
      ->json_is('/0/hold_id', $reserve_id)
280
      ->json_is('/0/expiration_date', output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }))
230
      ->json_is('/0/expiration_date', output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }))
281
      ->json_is('/0/pickup_library_id', $branchcode);
231
      ->json_is('/0/pickup_library_id', $branchcode);
282
232
283
    $tx = $t->ua->build_tx(POST => "/api/v1/holds" => json => $post_data);
233
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
284
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
285
    $t->request_ok($tx)
286
      ->status_is(403)
234
      ->status_is(403)
287
      ->json_like('/error', qr/itemAlreadyOnHold/);
235
      ->json_like('/error', qr/itemAlreadyOnHold/);
288
236
289
    $post_data->{biblionumber} = int($biblionumber2);
237
    $post_data->{biblionumber} = int($biblio_2->biblionumber);
290
    $post_data->{itemnumber} = int($itemnumber2);
238
    $post_data->{itemnumber}   = int($item_2->itemnumber);
291
    $tx = $t->ua->build_tx(POST => "/api/v1/holds" => json => $post_data);
239
292
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
240
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
293
    $t->request_ok($tx)
294
      ->status_is(403)
241
      ->status_is(403)
295
      ->json_like('/error', qr/itemAlreadyOnHold/);
242
      ->json_like('/error', qr/itemAlreadyOnHold/);
296
};
243
};
Lines 300-326 subtest 'Reserves with itemtype' => sub { Link Here
300
247
301
    my $post_data = {
248
    my $post_data = {
302
        patron_id => int($patron_1->borrowernumber),
249
        patron_id => int($patron_1->borrowernumber),
303
        biblio_id => int($biblionumber),
250
        biblio_id => int($biblio_1->biblionumber),
304
        pickup_library_id => $branchcode,
251
        pickup_library_id => $branchcode,
305
        item_type => $itemtype,
252
        item_type => $itemtype,
306
    };
253
    };
307
254
308
    $tx = $t->ua->build_tx(DELETE => "/api/v1/holds/$reserve_id");
255
    $t->delete_ok( "//$userid_3:$password@/api/v1/holds/$reserve_id" )
309
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
310
    $t->request_ok($tx)
311
      ->status_is(200);
256
      ->status_is(200);
312
257
313
    $tx = $t->ua->build_tx(POST => "/api/v1/holds" => json => $post_data);
258
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
314
    $tx->req->cookies({name => 'CGISESSID', value => $session3->id});
315
    $t->request_ok($tx)
316
      ->status_is(201)
259
      ->status_is(201)
317
      ->json_has('/hold_id');
260
      ->json_has('/hold_id');
318
261
319
    $reserve_id = $t->tx->res->json->{hold_id};
262
    $reserve_id = $t->tx->res->json->{hold_id};
320
263
321
    $tx = $t->ua->build_tx(GET => "/api/v1/holds?patron_id=" . $patron_1->borrowernumber);
264
    $t->get_ok( "//$userid_1:$password@/api/v1/holds?patron_id=" . $patron_1->borrowernumber )
322
    $tx->req->cookies({name => 'CGISESSID', value => $session->id});
323
    $t->request_ok($tx)
324
      ->status_is(200)
265
      ->status_is(200)
325
      ->json_is('/0/hold_id', $reserve_id)
266
      ->json_is('/0/hold_id', $reserve_id)
326
      ->json_is('/0/item_type', $itemtype);
267
      ->json_is('/0/item_type', $itemtype);
Lines 490-519 subtest 'PUT /holds/{hold_id}/priority tests' => sub { Link Here
490
431
491
    $schema->storage->txn_rollback;
432
    $schema->storage->txn_rollback;
492
};
433
};
493
494
sub create_biblio {
495
    my ($title) = @_;
496
497
    my $biblio = Koha::Biblio->new( { title => $title } )->store;
498
    my $biblioitem = Koha::Biblioitem->new({biblionumber => $biblio->biblionumber})->store;
499
500
    return $biblio->biblionumber;
501
}
502
503
sub create_item {
504
    my ( $biblionumber, $barcode ) = @_;
505
506
    Koha::Items->search( { barcode => $barcode } )->delete;
507
    my $builder = t::lib::TestBuilder->new;
508
    my $item    = $builder->build(
509
        {
510
            source => 'Item',
511
            value  => {
512
                biblionumber     => $biblionumber,
513
                barcode          => $barcode,
514
            }
515
        }
516
    );
517
518
    return $item;
519
}
520
- 

Return to bug 23517