Bug 33146: Add public items lookup route
authorMartin Renvoize <martin.renvoize@ptfs-europe.com>
Tue, 19 Jul 2022 10:56:56 +0000 (11:56 +0100)
committerTomas Cohen Arazi <tomascohen@theke.io>
Fri, 31 Mar 2023 10:26:57 +0000 (12:26 +0200)
This patch adds a /public equivilent to the item listing endpoint.

This allows us to search for an item by it's external_id (barcode).

Test plan
1. Apply patch
2. Perform a GET on /api/v1/public/items?external_id=some_barcode
3. Confirm that the above endpoint correctly returns items that should
   be visible in the OPAC

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Bug 33146: (QA follow-up) Do not delete all items in test

Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Bug 33146: Allow embedding expanded coded values

Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Bug 33146: (QA follow-up) Consistency with /biblios/:biblio_id/items

Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Bug 33146: (QA follow-up) Make sure public API enabled for tests

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Koha/REST/V1/Items.pm
api/v1/swagger/paths/biblios.yaml
api/v1/swagger/paths/items.yaml
api/v1/swagger/swagger.yaml
t/db_dependent/api/v1/items.t

index 3f20e3a..938ffcd 100644 (file)
@@ -58,6 +58,32 @@ sub list {
     };
 }
 
+=head3 list_public
+
+Controller function that handles listing Koha::Item objects available to the opac
+
+=cut
+
+sub list_public {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+        my $patron = $c->stash('koha.user');
+
+        my $items_set =
+          Koha::Items->filter_by_visible_in_opac( { patron => $patron } );
+        my $items = $c->objects->search($items_set);
+
+        return $c->render(
+            status  => 200,
+            openapi => $items
+        );
+    }
+    catch {
+        $c->unhandled_exception($_);
+    };
+}
+
 =head3 get
 
 Controller function that handles retrieving a single Koha::Item
index 8b7da78..559e5a4 100644 (file)
       - $ref: "../swagger.yaml#/parameters/q_param"
       - $ref: "../swagger.yaml#/parameters/q_body"
       - $ref: "../swagger.yaml#/parameters/q_header"
+      - name: x-koha-embed
+        in: header
+        required: false
+        description: Embed list sent as a request header
+        type: array
+        items:
+          type: string
+          enum:
+            - +strings
+        collectionFormat: csv
     consumes:
       - application/json
     produces:
index a9c7ca4..ac8c313 100644 (file)
     x-koha-authorization:
       permissions:
         reserveforothers: place_holds
+"/public/items":
+  get:
+    x-mojo-to: Items#list_public
+    operationId: listItemsPublic
+    tags:
+      - items
+    summary: List items publically visible
+    parameters:
+      - name: external_id
+        in: query
+        description: Search on the item's barcode
+        required: false
+        type: string
+      - $ref: "../swagger.yaml#/parameters/match"
+      - $ref: "../swagger.yaml#/parameters/order_by"
+      - $ref: "../swagger.yaml#/parameters/page"
+      - $ref: "../swagger.yaml#/parameters/per_page"
+      - $ref: "../swagger.yaml#/parameters/q_param"
+      - $ref: "../swagger.yaml#/parameters/q_body"
+      - $ref: "../swagger.yaml#/parameters/q_header"
+      - $ref: "../swagger.yaml#/parameters/request_id_header"
+      - name: x-koha-embed
+        in: header
+        required: false
+        description: Embed list sent as a request header
+        type: array
+        items:
+          type: string
+          enum:
+            - +strings
+        collectionFormat: csv
+    consumes:
+      - application/json
+    produces:
+      - application/json
+    responses:
+      "200":
+        description: A list of item
+        schema:
+          type: array
+          items:
+            $ref: "../swagger.yaml#/definitions/item"
+      "401":
+        description: Authentication required
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+      "403":
+        description: Access forbidden
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+      "500":
+        description: |
+          Internal server error. Possible `error_code` attribute values:
+
+          * `internal_server_error`
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+      "503":
+        description: Under maintenance
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
index 6f7d697..7d5e04f 100644 (file)
@@ -291,6 +291,8 @@ paths:
     $ref: "./paths/patrons_password.yaml#/~1patrons~1{patron_id}~1password~1expiration_date"
   "/public/biblios/{biblio_id}":
     $ref: "./paths/biblios.yaml#/~1public~1biblios~1{biblio_id}"
+  "/public/items":
+    $ref: "./paths/items.yaml#/~1public~1items"
   "/public/biblios/{biblio_id}/items":
     $ref: "./paths/biblios.yaml#/~1public~1biblios~1{biblio_id}~1items"
   "/public/biblios/{biblio_id}/ratings":
index 27a8566..a4a6300 100755 (executable)
@@ -27,6 +27,8 @@ use Test::Warn;
 use t::lib::TestBuilder;
 use t::lib::Mocks;
 
+use Mojo::JSON qw(encode_json);
+
 use C4::Auth;
 use Koha::Items;
 use Koha::Database;
@@ -105,15 +107,17 @@ subtest 'list_public() tests' => sub {
 
     $schema->storage->txn_begin;
 
-    # Clean out all demo items
-    Koha::Items->delete();
+    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
 
-    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
-    my $mocked_category = Test::MockModule->new('Koha::Patron::Category');
     my $exception = 1;
-    $mocked_category->mock( 'override_hidden_items', sub {
-        return $exception;
-    });
+
+    my $mocked_category = Test::MockModule->new('Koha::Patron::Category');
+    $mocked_category->mock(
+        'override_hidden_items',
+        sub {
+            return $exception;
+        }
+    );
 
     my $password = 'thePassword123';
     $patron->set_password( { password => $password, skip_validation => 1 } );
@@ -186,28 +190,33 @@ subtest 'list_public() tests' => sub {
         return $rules;
     });
 
+    my $query = encode_json({ item_id => [ $item_1->id, $item_2->id, $item_3->id, $item_4->id, $item_5->id, $item_6->id ] });
+
+    t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
     subtest 'anonymous access' => sub {
         plan tests => 21;
 
+        t::lib::Mocks::mock_preference( 'RESTPublicAnonymousRequests', 1 );
+
         t::lib::Mocks::mock_preference( 'hidelostitems', 0 );
-        my $res = $t->get_ok( "/api/v1/public/items" )->status_is(200)->tx->res->json;
+        my $res = $t->get_ok( "/api/v1/public/items?q=" . $query )->status_is(200)->tx->res->json;
         is( scalar @{ $res }, 6, 'No rules set, hidelostitems unset, all items returned');
 
         t::lib::Mocks::mock_preference( 'hidelostitems', 1 );
-        $res = $t->get_ok( "/api/v1/public/items" )->status_is(200)->tx->res->json;
+        $res = $t->get_ok( "/api/v1/public/items?q=" . $query )->status_is(200)->tx->res->json;
         is( scalar @{ $res }, 3, 'No rules set, hidelostitems set, 3 items hidden');
 
         t::lib::Mocks::mock_preference( 'hidelostitems', 0 );
         $rules = { biblionumber => [ $biblio->biblionumber ] };
-        $res = $t->get_ok( "/api/v1/public/items" )->status_is(200)->tx->res->json;
+        $res = $t->get_ok( "/api/v1/public/items?q=" . $query )->status_is(200)->tx->res->json;
         is( scalar @{ $res }, 0, 'Biblionumber rule set, hidelostitems unset, all items hidden');
 
         $rules = { withdrawn => [ 1, 2 ] };
-        $res = $t->get_ok( "/api/v1/public/items" )->status_is(200)->tx->res->json;
+        $res = $t->get_ok( "/api/v1/public/items?q=" . $query )->status_is(200)->tx->res->json;
         is( scalar @{ $res }, 4, 'Withdrawn rule set, hidelostitems unset, 2 items hidden');
 
         $rules = { itype => [ $itype_1->itemtype ] };
-        $res = $t->get_ok( "/api/v1/public/items" )->status_is(200)->tx->res->json;
+        $res = $t->get_ok( "/api/v1/public/items?q=" . $query )->status_is(200)->tx->res->json;
         is( scalar @{ $res }, 2, 'Itype rule set, hidelostitems unset, 4 items hidden');
 
         $rules = { withdrawn => [ 1 ] };
@@ -228,7 +237,7 @@ subtest 'list_public() tests' => sub {
 
         t::lib::Mocks::mock_preference( 'hidelostitems', 1 );
         $rules = { withdrawn => [ 1, 2 ] };
-        my $res = $t->get_ok("//$userid:$password@/api/v1/public/items")
+        my $res = $t->get_ok("//$userid:$password@/api/v1/public/items?q=" . $query)
           ->status_is(200)->tx->res->json;
         is(
             scalar @{$res},