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

(-)a/Koha/REST/V1/ILL/Requests.pm (-14 / +30 lines)
Lines 60-91 sub list { Link Here
60
60
61
=head3 patron_list
61
=head3 patron_list
62
62
63
Controller function that handles listing Koha::ILL::Request objects for a given patron.
63
Controller function that returns a patron's list of ILL requests.
64
65
The patron must match the requesting user unless the requesting user is a superlibrarian.
66
67
This is a public route, so some request details are omitted.
68
64
69
=cut
65
=cut
70
66
71
sub patron_list {
67
sub patron_list {
72
    my $c    = shift->openapi->valid_input or return;
68
    my $c = shift->openapi->valid_input or return;
73
    my $user = $c->stash('koha.user');
69
74
    $c->stash( is_public => 1 );
70
    my $patron = Koha::Patrons->find( $c->param('patron_id') );
71
72
    return $c->render_resource_not_found('Patron')
73
        unless $patron;
74
75
    return try {
75
76
76
    if ( $user->borrowernumber != $c->param('patron_id') and !$user->is_superlibrarian ) {
77
        return $c->render(
77
        return $c->render(
78
            status  => 403,
78
            status  => 200,
79
            openapi => { error => "Cannot lookup ILL requests for other users" }
79
            openapi => $c->objects->search( $patron->ill_requests ),
80
        );
80
        );
81
    }
81
    } catch {
82
        $c->unhandled_exception($_);
83
    };
84
}
85
86
=head3 public_patron_list
87
88
Controller function that returns a patron's list of ILL requests for unprivileged
89
access.
90
91
=cut
92
93
sub public_patron_list {
94
    my $c = shift->openapi->valid_input or return;
82
95
83
    return try {
96
    return try {
84
        my $reqs = $c->objects->search( Koha::ILL::Requests->search( { borrowernumber => $c->param('patron_id') } ) );
97
98
        $c->auth->public( $c->param('patron_id') );
99
100
        my $patron = $c->stash('koha.user');
85
101
86
        return $c->render(
102
        return $c->render(
87
            status  => 200,
103
            status  => 200,
88
            openapi => $reqs,
104
            openapi => $c->objects->search( $patron->ill_requests() ),
89
        );
105
        );
90
    } catch {
106
    } catch {
91
        $c->unhandled_exception($_);
107
        $c->unhandled_exception($_);
(-)a/api/v1/swagger/paths/patrons.yaml (-2 / +2 lines)
Lines 667-673 Link Here
667
    x-mojo-to: ILL::Requests#patron_list
667
    x-mojo-to: ILL::Requests#patron_list
668
    operationId: getPatronIllRequests
668
    operationId: getPatronIllRequests
669
    tags:
669
    tags:
670
      - patrons
671
      - ill_requests
670
      - ill_requests
672
    summary: Get patron's ILL requests
671
    summary: Get patron's ILL requests
673
    parameters:
672
    parameters:
Lines 727-730 Link Here
727
        schema:
726
        schema:
728
          $ref: "../swagger.yaml#/definitions/error"
727
          $ref: "../swagger.yaml#/definitions/error"
729
    x-koha-authorization:
728
    x-koha-authorization:
730
      permissions: {}
729
      permissions:
730
        ill: "1"
(-)a/api/v1/swagger/paths/public_patrons.yaml (-1 / +64 lines)
Lines 277-280 Link Here
277
      "503":
277
      "503":
278
        description: Under maintenance
278
        description: Under maintenance
279
        schema:
279
        schema:
280
          $ref: "../swagger.yaml#/definitions/error"
280
          $ref: "../swagger.yaml#/definitions/error"
281
"/public/patrons/{patron_id}/ill/requests":
282
  get:
283
    x-mojo-to: ILL::Requests#public_patron_list
284
    operationId: getPublicPatronIllRequests
285
    tags:
286
      - ill_requests
287
    summary: Get patron's ILL requests
288
    parameters:
289
      - $ref: "../swagger.yaml#/parameters/patron_id_pp"
290
      - $ref: "../swagger.yaml#/parameters/page"
291
      - $ref: "../swagger.yaml#/parameters/per_page"
292
      - $ref: "../swagger.yaml#/parameters/match"
293
      - $ref: "../swagger.yaml#/parameters/order_by"
294
      - $ref: "../swagger.yaml#/parameters/q_param"
295
      - $ref: "../swagger.yaml#/parameters/q_body"
296
      - $ref: "../swagger.yaml#/parameters/request_id_header"
297
      - name: x-koha-embed
298
        in: header
299
        required: false
300
        description: Embed list sent as a request header
301
        type: array
302
        items:
303
          type: string
304
          enum:
305
            - +strings
306
            - extended_attributes
307
        collectionFormat: csv
308
    produces:
309
      - application/json
310
    responses:
311
      "200":
312
        description: A list of parton's ILL requests
313
        schema:
314
          type: array
315
          items:
316
            $ref: "../swagger.yaml#/definitions/ill_request"
317
      "400":
318
        description: Bad request
319
        schema:
320
          $ref: "../swagger.yaml#/definitions/error"
321
      "401":
322
        description: Authentication required
323
        schema:
324
          $ref: "../swagger.yaml#/definitions/error"
325
      "403":
326
        description: Access forbidden
327
        schema:
328
          $ref: "../swagger.yaml#/definitions/error"
329
      "404":
330
        description: Patron not found
331
        schema:
332
          $ref: "../swagger.yaml#/definitions/error"
333
      "500":
334
        description: |
335
          Internal server error. Possible `error_code` attribute values:
336
337
          * `internal_server_error`
338
        schema:
339
          $ref: "../swagger.yaml#/definitions/error"
340
      "503":
341
        description: Under maintenance
342
        schema:
343
          $ref: "../swagger.yaml#/definitions/error"
(-)a/api/v1/swagger/swagger.yaml (-1 / +3 lines)
Lines 531-536 paths: Link Here
531
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
531
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
532
  "/public/patrons/{patron_id}/holds/{hold_id}":
532
  "/public/patrons/{patron_id}/holds/{hold_id}":
533
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1holds~1{hold_id}"
533
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1holds~1{hold_id}"
534
  "/public/patrons/{patron_id}/ill/requests":
535
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1ill~1requests"
534
  "/public/patrons/{patron_id}/password":
536
  "/public/patrons/{patron_id}/password":
535
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1password"
537
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1password"
536
  "/public/tickets":
538
  "/public/tickets":
Lines 1295-1298 tags: Link Here
1295
    x-displayName: Two factor authentication
1297
    x-displayName: Two factor authentication
1296
  - description: "Manage vendors for the acquisitions module\n"
1298
  - description: "Manage vendors for the acquisitions module\n"
1297
    name: vendors
1299
    name: vendors
1298
    x-displayName: Vendors
1300
    x-displayName: Vendors
(-)a/t/db_dependent/api/v1/ill_requests.t (-26 / +90 lines)
Lines 18-24 Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::NoWarnings;
20
use Test::NoWarnings;
21
use Test::More tests => 4;
21
use Test::More tests => 5;
22
22
23
use Test::MockModule;
23
use Test::MockModule;
24
use Test::MockObject;
24
use Test::MockObject;
Lines 264-272 subtest 'list() tests' => sub { Link Here
264
    $schema->storage->txn_rollback;
264
    $schema->storage->txn_rollback;
265
};
265
};
266
266
267
subtest 'patron_list() tests' => sub {
267
subtest 'public_patron_list() tests' => sub {
268
269
    plan tests => 13;
268
270
269
    plan tests => 15;
271
    $schema->storage->txn_begin;
270
272
271
    # Mock ILLBackend (as object)
273
    # Mock ILLBackend (as object)
272
    my $backend = Test::MockObject->new;
274
    my $backend = Test::MockObject->new;
Lines 283-318 subtest 'patron_list() tests' => sub { Link Here
283
        sub { my $self = shift; $self->{_my_backend} = $backend; return $self }
285
        sub { my $self = shift; $self->{_my_backend} = $backend; return $self }
284
    );
286
    );
285
287
286
    $schema->storage->txn_begin;
288
    my $password = 'thePassword123';
287
288
    Koha::ILL::Requests->search->delete;
289
289
290
    my $requester = $builder->build_object(
290
    my $patron_1 = $builder->build_object(
291
        {
291
        {
292
            class => 'Koha::Patrons',
292
            class => 'Koha::Patrons',
293
            value => { flags => 0 }
293
            value => { flags => 0 }
294
        }
294
        }
295
    );
295
    );
296
    my $password = 'thePassword123';
296
    my $patron_1_userid = $patron_1->userid;
297
    $requester->set_password( { password => $password, skip_validation => 1 } );
297
    my $patron_1_id     = $patron_1->id;
298
    my $requester_userid = $requester->userid;
298
299
    my $requester_number = $requester->borrowernumber;
299
    $patron_1->set_password( { password => $password, skip_validation => 1 } );
300
300
301
    my $observer = $builder->build_object(
301
    my $patron_2 = $builder->build_object(
302
        {
302
        {
303
            class => 'Koha::Patrons',
303
            class => 'Koha::Patrons',
304
            value => { flags => 0 }
304
            value => { flags => 0 }
305
        }
305
        }
306
    );
306
    );
307
307
308
    $observer->set_password( { password => $password, skip_validation => 1 } );
308
    $patron_2->set_password( { password => $password, skip_validation => 1 } );
309
    my $observer_userid = $observer->userid;
309
310
    my $observer_number = $observer->borrowernumber;
310
    my $patron_2_userid = $patron_2->userid;
311
    my $patron_2_id     = $patron_2->id;
311
312
312
    # No requests yet, expect empty for both
313
    # No requests yet, expect empty for both
313
    $t->get_ok("//$requester_userid:$password@/api/v1/patrons/$requester_number/ill/requests")->status_is(200)
314
    $t->get_ok("//$patron_1_userid:$password@/api/v1/public/patrons/$patron_1_id/ill/requests")->status_is(200)
314
        ->json_is( [] );
315
        ->json_is( [] );
315
    $t->get_ok("//$observer_userid:$password@/api/v1/patrons/$observer_number/ill/requests")->status_is(200)
316
317
    $t->get_ok("//$patron_2_userid:$password@/api/v1/public/patrons/$patron_2_id/ill/requests")->status_is(200)
316
        ->json_is( [] );
318
        ->json_is( [] );
317
319
318
    for ( 0 .. 25 ) {
320
    for ( 0 .. 25 ) {
Lines 320-326 subtest 'patron_list() tests' => sub { Link Here
320
            {
322
            {
321
                class => 'Koha::ILL::Requests',
323
                class => 'Koha::ILL::Requests',
322
                value => {
324
                value => {
323
                    borrowernumber => $requester_number,
325
                    borrowernumber => $patron_1_id,
324
                    batch_id       => undef,
326
                    batch_id       => undef,
325
                    status         => 'NEW',
327
                    status         => 'NEW',
326
                    backend        => $backend->name,
328
                    backend        => $backend->name,
Lines 331-350 subtest 'patron_list() tests' => sub { Link Here
331
    }
333
    }
332
334
333
    # Other user should not see anything
335
    # Other user should not see anything
334
    $t->get_ok("//$observer_userid:$password@/api/v1/patrons/$observer_number/ill/requests")->status_is(200)
336
    $t->get_ok("//$patron_2_userid:$password@/api/v1/public/patrons/$patron_2_id/ill/requests")->status_is(200)
335
        ->json_is( [] );
337
        ->json_is( [] );
336
338
337
    # Staff notes hidden in the public API
339
    # Staff notes hidden in the public API
338
    $t->get_ok("//$requester_userid:$password@/api/v1/patrons/$requester_number/ill/requests")->status_is(200)
340
    $t->get_ok("//$patron_1_userid:$password@/api/v1/public/patrons/$patron_1_id/ill/requests?_per_page=-1")
339
        ->json_is(
341
        ->status_is(200)->json_is(
340
        '/0/staff_notes' => undef,
342
        '/0/staff_notes' => undef,
341
        );
343
        );
342
344
343
    # Not all requests get returned, pagination works
345
    my $reqs = $t->tx->res->json;
344
    $t->get_ok("//$requester_userid:$password@/api/v1/patrons/$requester_number/ill/requests")->status_is(200)
346
    is( scalar @{$reqs}, 26, 'All ILL requests returned for the patron' );
345
        ->json_is(
347
346
        '/21' => undef,
348
    $schema->storage->txn_rollback;
349
};
350
351
subtest 'patron_list() tests' => sub {
352
353
    plan tests => 7;
354
355
    $schema->storage->txn_begin;
356
357
    # Mock ILLBackend (as object)
358
    my $backend = Test::MockObject->new;
359
    $backend->set_isa('Koha::Illbackends::Mock');
360
    $backend->set_always( 'name', 'Mock' );
361
    $backend->mock(
362
        'status_graph', sub { },
363
    );
364
365
    # Mock Koha::ILL::Request::load_backend (to load Mocked Backend)
366
    my $illreqmodule = Test::MockModule->new('Koha::ILL::Request');
367
    $illreqmodule->mock(
368
        'load_backend',
369
        sub { my $self = shift; $self->{_my_backend} = $backend; return $self }
370
    );
371
372
    my $password = 'thePassword123';
373
374
    my $patron = $builder->build_object(
375
        {
376
            class => 'Koha::Patrons',
377
            value => { flags => 2**22 }    # 22 => ill
378
        }
379
    );
380
381
    my $user_id   = $patron->userid;
382
    my $patron_id = $patron->id;
383
384
    $patron->set_password( { password => $password, skip_validation => 1 } );
385
386
    # No requests yet, expect empty for both
387
    $t->get_ok("//$user_id:$password@/api/v1/patrons/$patron_id/ill/requests")->status_is(200)->json_is( [] );
388
389
    my $secret_notes = 'secret staff notes';
390
391
    for ( 0 .. 25 ) {
392
        $builder->build_object(
393
            {
394
                class => 'Koha::ILL::Requests',
395
                value => {
396
                    borrowernumber => $patron_id,
397
                    batch_id       => undef,
398
                    status         => 'NEW',
399
                    backend        => $backend->name,
400
                    notesstaff     => $secret_notes,
401
                }
402
            }
347
        );
403
        );
404
    }
405
406
    # Staff notes available in the staff endpoint
407
    $t->get_ok("//$user_id:$password@/api/v1/patrons/$patron_id/ill/requests?_per_page=-1")->status_is(200)->json_is(
408
        '/0/staff_notes' => $secret_notes,
409
    );
410
411
    my $reqs = $t->tx->res->json;
412
    is( scalar @{$reqs}, 26, 'All ILL requests returned for the patron' );
348
413
349
    $schema->storage->txn_rollback;
414
    $schema->storage->txn_rollback;
350
};
415
};
351
- 

Return to bug 38340