From da7cc659be6440ce2e21a5bd4c7ddd3dda2ab1f6 Mon Sep 17 00:00:00 2001 From: Arthur Suzuki Date: Wed, 18 Feb 2026 00:53:27 +0000 Subject: [PATCH] Bug 41768: create and use public pickup_locations endpoints Sponsored-by: BibLibre --- Koha/REST/V1/Biblios.pm | 11 +++- Koha/REST/V1/Holds.pm | 14 ++++ Koha/REST/V1/Items.pm | 12 +++- api/v1/swagger/paths/biblios.yaml | 56 ++++++++++++++++ api/v1/swagger/paths/holds.yaml | 65 +++++++++++++++++++ api/v1/swagger/paths/items.yaml | 57 ++++++++++++++++ api/v1/swagger/swagger.yaml | 6 ++ .../bootstrap/js/pickup-locations.js | 12 +--- 8 files changed, 221 insertions(+), 12 deletions(-) diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index a4d50e38005..7aff1fb17ca 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -474,7 +474,16 @@ sub pickup_locations { return $c->render_resource_not_found("Bibliographic record") unless $biblio; - my $patron = Koha::Patrons->find( $c->param('patron_id') ); + my $patron; + $patron = Koha::Patrons->find( $c->param('patron_id') ); + + if ( $c->stash('is_public') || !$patron ) { + my $userenv = C4::Context->userenv; + if ( $userenv and $userenv->{number} ) { + $patron = Koha::Patrons->find( $userenv->{number} ); + } + } + $c->req->params->remove('patron_id'); unless ($patron) { diff --git a/Koha/REST/V1/Holds.pm b/Koha/REST/V1/Holds.pm index ad5b4c4d647..b25107dbca5 100644 --- a/Koha/REST/V1/Holds.pm +++ b/Koha/REST/V1/Holds.pm @@ -21,6 +21,7 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON; +use C4::Context; use C4::Reserves; use Koha::Items; @@ -543,6 +544,19 @@ sub pickup_locations { return $c->render_resource_not_found("Hold") unless $hold; + if ( $c->stash('is_public') ) { + my $userenv = C4::Context->userenv; + return $c->render( + status => 401, + openapi => { error => 'Cannot find connected user' } + ) unless ( $userenv and $userenv->{number} ); + + return $c->render( + status => 403, + openapi => { error => 'Hold do not belong to the connected user' } + ) unless ( $hold->patron->id eq $userenv->{number} ); + } + return try { my $ps_set; diff --git a/Koha/REST/V1/Items.pm b/Koha/REST/V1/Items.pm index 07a8a4f03e5..9b989177007 100644 --- a/Koha/REST/V1/Items.pm +++ b/Koha/REST/V1/Items.pm @@ -19,6 +19,7 @@ use Modern::Perl; use Mojo::Base 'Mojolicious::Controller'; +use C4::Context; use C4::Circulation qw( barcodedecode ); use Koha::Items; @@ -210,8 +211,15 @@ sub pickup_locations { return $c->render_resource_not_found("Item") unless $item; - my $patron_id = $c->param('patron_id'); - my $patron = Koha::Patrons->find($patron_id); + my $patron; + $patron = Koha::Patrons->find( $c->param('patron_id') ); + + if ( $c->stash('is_public') || !$patron ) { + my $userenv = C4::Context->userenv; + if ( $userenv and $userenv->{number} ) { + $patron = Koha::Patrons->find( $userenv->{number} ); + } + } $c->req->params->remove('patron_id'); diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index 18120c5dd98..3e2c7ed81e5 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -920,3 +920,59 @@ description: Under maintenance schema: $ref: "../swagger.yaml#/definitions/error" +"/public/biblios/{biblio_id}/pickup_locations": + get: + x-mojo-to: Biblios#pickup_locations + operationId: getBiblioPickupLocationsPublic + tags: + - biblios + summary: Get valid pickup locations for a biblio for the connected user + parameters: + - $ref: "../swagger.yaml#/parameters/biblio_id_pp" + - $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" + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: Biblio pickup locations + schema: + type: array + items: + $ref: "../swagger.yaml#/definitions/library" + "400": + description: | + Bad request. Possible `error_code` attribute values: + + * `invalid_query` + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Bibliographic record not found + 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" diff --git a/api/v1/swagger/paths/holds.yaml b/api/v1/swagger/paths/holds.yaml index dcd6413c03a..444ae7ed68b 100644 --- a/api/v1/swagger/paths/holds.yaml +++ b/api/v1/swagger/paths/holds.yaml @@ -957,3 +957,68 @@ x-koha-authorization: permissions: reserveforothers: modify_holds_priority +"/public/holds/{hold_id}/pickup_locations": + get: + x-mojo-to: Holds#pickup_locations + operationId: getHoldPickupLocationsPublic + tags: + - holds + summary: Get valid pickup locations for hold + parameters: + - name: x-koha-override + in: header + required: false + description: Overrides list sent as a request header + type: array + items: + type: string + enum: + - any + collectionFormat: csv + - $ref: "../swagger.yaml#/parameters/hold_id_pp" + - $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/request_id_header" + produces: + - application/json + responses: + "200": + description: Hold pickup location + schema: + type: array + items: + $ref: "../swagger.yaml#/definitions/library" + "400": + description: | + Bad request. Possible `error_code` attribute values: + + * `invalid_query` + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Hold pickup location list not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Hold not found + 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" diff --git a/api/v1/swagger/paths/items.yaml b/api/v1/swagger/paths/items.yaml index e99a6e0e55f..3c6b246e397 100644 --- a/api/v1/swagger/paths/items.yaml +++ b/api/v1/swagger/paths/items.yaml @@ -542,3 +542,60 @@ description: Under maintenance schema: $ref: "../swagger.yaml#/definitions/error" +"/public/items/{item_id}/pickup_locations": + get: + x-mojo-to: Items#pickup_locations + operationId: getItemPickupLocationsPublic + summary: Get valid pickup locations for an item for the connected user + tags: + - items + parameters: + - $ref: "../swagger.yaml#/parameters/item_id_pp" + - $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/request_id_header" + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: Item pickup locations + schema: + type: array + items: + $ref: "../swagger.yaml#/definitions/library" + "400": + description: | + Bad request. Possible `error_code` attribute values: + + * `invalid_query` + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Bibliographic record not found + 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" diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 9a9b7af7565..9cd44e96885 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -555,6 +555,12 @@ paths: $ref: ./paths/checkouts.yaml#/~1public~1checkouts~1availability "/public/items": $ref: "./paths/items.yaml#/~1public~1items" + "/public/items/{item_id}/pickup_locations": + $ref: "./paths/items.yaml#/~1public~1items~1{item_id}~1pickup_locations" + "/public/holds/{hold_id}/pickup_locations": + $ref: "./paths/holds.yaml#/~1public~1holds~1{hold_id}~1pickup_locations" + "/public/biblios/{biblio_id}/pickup_locations": + $ref: "./paths/biblios.yaml#/~1public~1biblios~1{biblio_id}~1pickup_locations" "/public/biblios/{biblio_id}/items": $ref: "./paths/biblios.yaml#/~1public~1biblios~1{biblio_id}~1items" "/public/biblios/{biblio_id}/ratings": diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/pickup-locations.js b/koha-tmpl/opac-tmpl/bootstrap/js/pickup-locations.js index cb25fcdc70f..6aadd2dd50b 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/js/pickup-locations.js +++ b/koha-tmpl/opac-tmpl/bootstrap/js/pickup-locations.js @@ -44,7 +44,6 @@ * * It expects the select object to contain several data-* attributes * - data-pickup-location-source: 'biblio', 'item' or 'hold' (default) - * - data-patron-id: required for 'biblio' and 'item' * - data-biblio-id: required for 'biblio' only * - data-item-id: required for 'item' only * @@ -54,7 +53,6 @@ $.fn.pickup_locations_dropdown = function () { var select = $(this); var pickup_location_source = $(this).data("pickup-location-source"); - var patron_id = $(this).data("patron-id"); var biblio_id = $(this).data("biblio-id"); var item_id = $(this).data("item-id"); var hold_id = $(this).data("hold-id"); @@ -63,18 +61,18 @@ if (pickup_location_source === "biblio") { url = - "/api/v1/biblios/" + + "/api/v1/public/biblios/" + encodeURIComponent(biblio_id) + "/pickup_locations"; } else if (pickup_location_source === "item") { url = - "/api/v1/items/" + + "/api/v1/public/items/" + encodeURIComponent(item_id) + "/pickup_locations"; } else { // hold url = - "/api/v1/holds/" + + "/api/v1/public/holds/" + encodeURIComponent(hold_id) + "/pickup_locations"; } @@ -98,10 +96,6 @@ _page: params.page, }; - if (pickup_location_source !== "hold") { - query["patron_id"] = patron_id; - } - return query; }, processResults: function (data) { -- 2.39.5