From 95ac878376fce692e8999b5a801a2b58a8ce68d0 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 7 Mar 2023 20:51:35 -0300 Subject: [PATCH] Bug 33161: Add +strings support to GET /items and /items/:item_id This patch introduces the `api_strings_mapping` method to the *Koha::Item* class, and makes the API spec for the following routes: * GET /items * GET /items/:item_id * GET /acquisitions/orders accept the new `+strings` parameter that can be passed through the `x-koha-embed` header and was introduced by bug 26635. In the case of /acquisitions/orders, you will need to use x-koha-embed: items+strings I introduce it here to highlight the flebility we introduced with bug 26635. The `api_strings_mapping` method has its roots on the cool `columns_to_str` method already present. The main differences: * It is aware of the `public_read_list` for attributes so no hidden information is exposed. * Attribute names get mapped for consistency with the API (e.g. `homebranch` is converted into `home_library_id`, etc). * The data structure it returns includes information about the source for the descriptions (e.g. it it is an authorised value, then `type` will be `av`, and the related category information is returned so dropdowns and such can be built. The same goes for other types as `library`, `item_type` and `call_number_source`. To test: 1. Apply this patch 2. Reload everything 3. Play with your favourite REST tool (e.g. Postman) 4. Try: GET http://localhost:8081/api/v1/items x-koha-embed: +strings => SUCCESS: You get a list of items, they include the new _strings structure, and the contents make sense! 5. Repeat with a specific item: GET http://localhost:8081/api/v1/items/14 x-koha-embed: +strings => SUCCESS: It all makes sense! 6. Sign off :-D Sponsored-by: Virginia Polytechnic Institute and State University Signed-off-by: Pedro Amorim Signed-off-by: Tomas Cohen Arazi Signed-off-by: Martin Renvoize Signed-off-by: Tomas Cohen Arazi (cherry picked from commit dab02607028fadc0e8864102a9a59c7e8fb6c775) Signed-off-by: Martin Renvoize --- Koha/Item.pm | 70 +++++++++++++++++++ Koha/REST/V1/Items.pm | 5 +- api/v1/swagger/definitions/item.yaml | 4 ++ api/v1/swagger/paths/acquisitions_orders.yaml | 1 + api/v1/swagger/paths/items.yaml | 20 ++++++ 5 files changed, 98 insertions(+), 2 deletions(-) diff --git a/Koha/Item.pm b/Koha/Item.pm index 17075e4b10..4c7cec845c 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -2059,6 +2059,76 @@ sub is_denied_renewal { return 0; } +=head3 api_strings_mapping + +Retrieves for each column name the unblessed authorised value. + +=cut + +sub api_strings_mapping { + my ( $self, $params ) = @_; + + my $columns_info = $self->_result->result_source->columns_info; + my $frameworkcode = $self->biblio->frameworkcode; + my $tagslib = C4::Biblio::GetMarcStructure( 1, $frameworkcode ); + my $mss = C4::Biblio::GetMarcSubfieldStructure( $frameworkcode, { unsafe => 1 } ); + + my ( $itemtagfield, $itemtagsubfield ) = C4::Biblio::GetMarcFromKohaField("items.itemnumber"); + + my $public_read_list = $params->{public} ? $self->public_read_list : []; + my $to_api_mapping = $self->to_api_mapping; + + # Hardcoded known 'authorised_value' values mapped to API codes + my $code_to_type = { + branches => 'library', + cn_source => 'call_number_source', + itemtypes => 'item_type', + }; + + # Handle not null and default values for integers and dates + my $strings = {}; + + foreach my $col ( keys %{$columns_info} ) { + + # Skip columns not in public read list + next + unless !$params->{public} + || any { $col eq $_ } $public_read_list; + + # Skip columns that are not exposed on the API by to_api_mapping + # i.e. mapping exists but points to undef + next + if $col eq 'more_subfields_xml' # not dealt with as a regular field + || ( exists $to_api_mapping->{$col} && !defined $to_api_mapping->{$col} ); + + # By now, we are done with known columns, now check the framework for mappings + my $field = $self->_result->result_source->name . '.' . $col; + + # Check there's an entry in the MARC subfield structure for the field + if ( exists $mss->{$field} + && scalar @{ $mss->{$field} } > 0 + && $mss->{$field}[0]->{authorised_value} ) + { + my $subfield = $mss->{$field}[0]; + my $code = $subfield->{authorised_value}; + + my $str = C4::Biblio::GetAuthorisedValueDesc( $itemtagfield, $subfield->{tagsubfield}, $self->$col, '', $tagslib, undef, $params->{public} ); + my $type = exists $code_to_type->{$code} ? $code_to_type->{$code} : 'av'; + + # The _strings entry should match the API attribute name + my $mapped_attr = exists $to_api_mapping->{$col} ? $to_api_mapping->{$col} : $col; + + $strings->{$mapped_attr} = { + str => $str, + type => $type, + ( $type eq 'av' ? ( category => $code ) : () ), + }; + } + } + + return $strings; +} + =head3 _type =cut diff --git a/Koha/REST/V1/Items.pm b/Koha/REST/V1/Items.pm index 515fcd91bf..4332c0ba87 100644 --- a/Koha/REST/V1/Items.pm +++ b/Koha/REST/V1/Items.pm @@ -69,14 +69,15 @@ sub get { my $c = shift->openapi->valid_input or return; try { - my $item = Koha::Items->find($c->validation->param('item_id')); + my $items_rs = Koha::Items->new; + my $item = $c->objects->find($items_rs, $c->validation->param('item_id')); unless ( $item ) { return $c->render( status => 404, openapi => { error => 'Item not found'} ); } - return $c->render( status => 200, openapi => $item->to_api ); + return $c->render( status => 200, openapi => $item ); } catch { $c->unhandled_exception($_); diff --git a/api/v1/swagger/definitions/item.yaml b/api/v1/swagger/definitions/item.yaml index 069c0faebc..21963d1ca4 100644 --- a/api/v1/swagger/definitions/item.yaml +++ b/api/v1/swagger/definitions/item.yaml @@ -227,6 +227,10 @@ properties: type: - object - "null" + _strings: + type: + - object + - "null" description: A return claims object if one exists that's unresolved additionalProperties: false required: diff --git a/api/v1/swagger/paths/acquisitions_orders.yaml b/api/v1/swagger/paths/acquisitions_orders.yaml index 70668af8d7..3f3d5e4a93 100644 --- a/api/v1/swagger/paths/acquisitions_orders.yaml +++ b/api/v1/swagger/paths/acquisitions_orders.yaml @@ -63,6 +63,7 @@ - current_item_level_holds+count - invoice - items + - items+strings - subscription collectionFormat: csv responses: diff --git a/api/v1/swagger/paths/items.yaml b/api/v1/swagger/paths/items.yaml index 4ca6117d5f..9e20b7eb8a 100644 --- a/api/v1/swagger/paths/items.yaml +++ b/api/v1/swagger/paths/items.yaml @@ -12,6 +12,16 @@ description: Search on the item's barcode required: false type: string + - 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 - $ref: "../swagger.yaml#/parameters/match" - $ref: "../swagger.yaml#/parameters/order_by" - $ref: "../swagger.yaml#/parameters/page" @@ -62,6 +72,16 @@ summary: Get item parameters: - $ref: "../swagger.yaml#/parameters/item_id_pp" + - 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: -- 2.39.5