Bugzilla – Attachment 158082 Details for
Bug 34008
REST API: Add a list (GET) endpoint for itemtypes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 34008: Add REST endpoint for list of itemtypes
Bug-34008-Add-REST-endpoint-for-list-of-itemtypes.patch (text/plain), 19.43 KB, created by
Tomás Cohen Arazi (tcohen)
on 2023-10-30 16:18:16 UTC
(
hide
)
Description:
Bug 34008: Add REST endpoint for list of itemtypes
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2023-10-30 16:18:16 UTC
Size:
19.43 KB
patch
obsolete
>From 08fc92d71d87d9e1d69d560bec769f64c8c97abc Mon Sep 17 00:00:00 2001 >From: Andreas Jonsson <andreas.jonsson@kreablo.se> >Date: Sat, 16 Sep 2023 10:13:15 +0000 >Subject: [PATCH] Bug 34008: Add REST endpoint for list of itemtypes > >Test plan: >* Enable the system preference RESTBasicAuth >* curl -s --request GET http://kohadev-intra.mydnsname.org:8081/api/v1/itemtypes > should give 401 Unauthorized >* curl -s -u koha:koha --request GET http://kohadev-intra.mydnsname.org:8081/api/v1/itemtypes > should produce JSON-list of itemtypes >* curl -s -u koha:koha --header "x-koha-embed: translated_descriptions" --request GET http://kohadev-intra.mydnsname.org:8081/api/v1/itemtypes > should include the field translated_descriptions containing the translated descriptions, if any > >Signed-off-by: David Nind <david@davidnind.com> > >Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl> >[EDIT] perltidy -b t/db_dependent/api/v1/itemtypes.t # Resolve bad score of 44 >[EDIT] chmod 755 t/db_dependent/api/v1/itemtypes.t >[EDIT] perltidy -b Koha/REST/V1/ItemTypes.pm >Lesson: Please run qa tools yourself and adjust accordingly? >Edit (tcohen): I restored the item_type_translated_description.yaml file >as the entire API was broken because of the lack of it. >Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> >--- > Koha/ItemType.pm | 85 +++++++---- > Koha/REST/V1/ItemTypes.pm | 48 ++++++ > api/v1/swagger/definitions/item_type.yaml | 96 ++++++++++++ > .../item_type_translated_description.yaml | 13 ++ > api/v1/swagger/paths/item_types.yaml | 59 ++++++++ > api/v1/swagger/swagger.yaml | 7 + > t/db_dependent/api/v1/item_types.t | 142 ++++++++++++++++++ > 7 files changed, 418 insertions(+), 32 deletions(-) > create mode 100644 Koha/REST/V1/ItemTypes.pm > create mode 100644 api/v1/swagger/definitions/item_type.yaml > create mode 100644 api/v1/swagger/definitions/item_type_translated_description.yaml > create mode 100644 api/v1/swagger/paths/item_types.yaml > create mode 100755 t/db_dependent/api/v1/item_types.t > >diff --git a/Koha/ItemType.pm b/Koha/ItemType.pm >index 18f25446043..200ac166ea6 100644 >--- a/Koha/ItemType.pm >+++ b/Koha/ItemType.pm >@@ -17,7 +17,6 @@ package Koha::ItemType; > > use Modern::Perl; > >- > use C4::Koha qw( getitemtypeimagelocation ); > use C4::Languages; > use Koha::Caches; >@@ -52,8 +51,7 @@ sub store { > > if ( !$self->in_storage ) { > $flush = 1; >- } >- else { >+ } else { > my $self_from_storage = $self->get_from_storage; > $flush = 1 if ( $self_from_storage->description ne $self->description ); > } >@@ -96,22 +94,25 @@ sub image_location { > sub translated_description { > my ( $self, $lang ) = @_; > if ( my $translated_description = eval { $self->get_column('translated_description') } ) { >+ > # If the value has already been fetched (eg. from sarch_with_localization), > # do not search for it again > # Note: This is a bit hacky but should be fast > return $translated_description >- ? $translated_description >- : $self->description; >+ ? $translated_description >+ : $self->description; > } > $lang ||= C4::Languages::getlanguage; >- my $translated_description = Koha::Localizations->search({ >- code => $self->itemtype, >- entity => 'itemtypes', >- lang => $lang >- })->next; >+ my $translated_description = Koha::Localizations->search( >+ { >+ code => $self->itemtype, >+ entity => 'itemtypes', >+ lang => $lang >+ } >+ )->next; > return $translated_description >- ? $translated_description->translation >- : $self->description; >+ ? $translated_description->translation >+ : $self->description; > } > > =head3 translated_descriptions >@@ -119,18 +120,21 @@ sub translated_description { > =cut > > sub translated_descriptions { >- my ( $self ) = @_; >+ my ($self) = @_; > my @translated_descriptions = Koha::Localizations->search( >- { entity => 'itemtypes', >+ { >+ entity => 'itemtypes', > code => $self->itemtype, > } > )->as_list; >- return [ map { >- { >- lang => $_->lang, >- translation => $_->translation, >- } >- } @translated_descriptions ]; >+ return [ >+ map { >+ { >+ lang => $_->lang, >+ translation => $_->translation, >+ } >+ } @translated_descriptions >+ ]; > } > > =head3 can_be_deleted >@@ -142,8 +146,8 @@ Counts up the number of biblioitems and items with itemtype (code) and hands bac > =cut > > sub can_be_deleted { >- my ($self) = @_; >- my $nb_items = Koha::Items->search( { itype => $self->itemtype } )->count; >+ my ($self) = @_; >+ my $nb_items = Koha::Items->search( { itype => $self->itemtype } )->count; > my $nb_biblioitems = Koha::Biblioitems->search( { itemtype => $self->itemtype } )->count; > return $nb_items + $nb_biblioitems == 0 ? 1 : 0; > } >@@ -162,10 +166,12 @@ sub may_article_request { > my $itemtype = $self->itemtype; > my $category = $params->{categorycode}; > >- my $guess = Koha::CirculationRules->guess_article_requestable_itemtypes({ >- $category ? ( categorycode => $category ) : (), >- }); >- return ( $guess->{ $itemtype // q{} } || $guess->{ '*' } ) ? 1 : q{}; >+ my $guess = Koha::CirculationRules->guess_article_requestable_itemtypes( >+ { >+ $category ? ( categorycode => $category ) : (), >+ } >+ ); >+ return ( $guess->{ $itemtype // q{} } || $guess->{'*'} ) ? 1 : q{}; > } > > =head3 _library_limits >@@ -176,8 +182,8 @@ sub may_article_request { > > sub _library_limits { > return { >- class => "ItemtypesBranch", >- id => "itemtype", >+ class => "ItemtypesBranch", >+ id => "itemtype", > library => "branchcode", > }; > } >@@ -189,10 +195,10 @@ sub _library_limits { > =cut > > sub parent { >- my ( $self ) = @_; >+ my ($self) = @_; > my $parent_rs = $self->_result->parent_type; > return unless $parent_rs; >- return Koha::ItemType->_new_from_dbic( $parent_rs ); >+ return Koha::ItemType->_new_from_dbic($parent_rs); > > } > >@@ -203,8 +209,23 @@ sub parent { > =cut > > sub children_with_localization { >- my ( $self ) = @_; >- return Koha::ItemTypes->search_with_localization({ parent_type => $self->itemtype }); >+ my ($self) = @_; >+ return Koha::ItemTypes->search_with_localization( { parent_type => $self->itemtype } ); >+} >+ >+=head3 to_api_mapping >+ >+This method returns the mapping for representing a Koha::ItemType object >+on the API. >+ >+=cut >+ >+sub to_api_mapping { >+ return { 'itemtype' => 'item_type' }; >+} >+ >+sub from_api_mapping { >+ return { 'item_type' => 'itemtype' }; > } > > =head3 type >diff --git a/Koha/REST/V1/ItemTypes.pm b/Koha/REST/V1/ItemTypes.pm >new file mode 100644 >index 00000000000..91de0c4d0fd >--- /dev/null >+++ b/Koha/REST/V1/ItemTypes.pm >@@ -0,0 +1,48 @@ >+package Koha::REST::V1::ItemTypes; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use Koha::ItemTypes; >+ >+use Try::Tiny; >+ >+=head1 API >+ >+=head2 Methods >+ >+=head3 list >+ >+=cut >+ >+sub list { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $itemtypes_set = Koha::ItemTypes->new; >+ my $itemtypes = $c->objects->search( $itemtypes_set ); >+ >+ return $c->render( status => 200, openapi => $itemtypes ); >+ } catch { >+ $c->unhandled_exception($_); >+ }; >+ >+} >+ >+1; >diff --git a/api/v1/swagger/definitions/item_type.yaml b/api/v1/swagger/definitions/item_type.yaml >new file mode 100644 >index 00000000000..6023869aa44 >--- /dev/null >+++ b/api/v1/swagger/definitions/item_type.yaml >@@ -0,0 +1,96 @@ >+--- >+type: object >+properties: >+ item_type: >+ type: string >+ description: Unique key, a code associated with the item type >+ readOnly: true >+ parent_type: >+ description: Unique key, a code associated with the parent item type >+ type: >+ - string >+ - "null" >+ description: >+ description: A plain text explanation of the item type >+ type: string >+ rentalcharge: >+ description: The amount charged when this item is checked out/issued >+ type: >+ - number >+ - "null" >+ rentalcharge_daily: >+ description: The amount charged for each day between checkout date and due date >+ type: >+ - number >+ - "null" >+ rentalcharge_daily_calendar: >+ description: Controls if the daily rental fee is calculated directly or using finesCalendar >+ type: boolean >+ rentalcharge_hourly: >+ description: The amount charged for each hour between checkout date and due date >+ type: >+ - number >+ - "null" >+ rentalcharge_hourly_calendar: >+ description: Controls if the hourly rental fee is calculated directly or using finesCalendar >+ type: boolean >+ defaultreplacecost: >+ description: Default replacement cost >+ type: >+ - number >+ - "null" >+ processfee: >+ description: Default text be recorded in the column note when the processing fee is applied >+ type: >+ - number >+ - "null" >+ notforloan: >+ description: Controls if the item is available for loan >+ type: >+ - boolean >+ - "null" >+ imageurl: >+ description: URL for the item type icon >+ type: >+ - string >+ - "null" >+ summary: >+ description: Information from the summary field, may include HTML >+ type: >+ - string >+ - "null" >+ checkinmsg: >+ description: Message that is displayed when an item with the given item type is checked in >+ type: >+ - string >+ - "null" >+ checkinmsgtype: >+ description: Type (CSS class) for the checkinmsg, can be 'alert' or 'message' >+ type: >+ - string >+ - "null" >+ sip_media_type: >+ description: SIP2 protocol media type for this item type >+ type: >+ - string >+ - "null" >+ hideinopac: >+ description: Hide the item type from the search options in OPAC >+ type: boolean >+ searchcategory: >+ description: Group this item type with others with the same value on OPAC search options >+ type: >+ - string >+ - "null" >+ automatic_checkin: >+ description: Controls if automatic checkin is enabled for items of this type >+ type: boolean >+ translated_descriptions: >+ description: Translations of description plain text >+ type: array >+ items: >+ $ref: "item_type_translated_description.yaml" >+ >+additionalProperties: false >+required: >+ - item_type >diff --git a/api/v1/swagger/definitions/item_type_translated_description.yaml b/api/v1/swagger/definitions/item_type_translated_description.yaml >new file mode 100644 >index 00000000000..8cb95287a62 >--- /dev/null >+++ b/api/v1/swagger/definitions/item_type_translated_description.yaml >@@ -0,0 +1,13 @@ >+--- >+type: object >+properties: >+ lang: >+ description: Language identifier >+ type: string >+ translation: >+ description: Translated plain text >+ type: string >+additionalProperties: false >+required: >+ - lang >+ - translation >diff --git a/api/v1/swagger/paths/item_types.yaml b/api/v1/swagger/paths/item_types.yaml >new file mode 100644 >index 00000000000..d359a40d627 >--- /dev/null >+++ b/api/v1/swagger/paths/item_types.yaml >@@ -0,0 +1,59 @@ >+--- >+/item_types: >+ get: >+ x-mojo-to: ItemTypes#list >+ operationId: listItemTypes >+ tags: >+ - item_types >+ summary: List item types >+ produces: >+ - application/json >+ parameters: >+ - name: x-koha-embed >+ in: header >+ required: false >+ description: Embed list sent as a request header >+ type: array >+ items: >+ type: string >+ enum: >+ - translated_descriptions >+ collectionFormat: csv >+ - $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" >+ responses: >+ 200: >+ description: A list of item types >+ schema: >+ items: >+ $ref: "../swagger.yaml#/definitions/item_type" >+ type: array >+ 400: >+ description: Bad request >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ 403: >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ 404: >+ description: Resource 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" >+ x-koha-authorization: >+ permissions: >+ catalogue: 1 >diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml >index cdca9708372..87a0600bd8b 100644 >--- a/api/v1/swagger/swagger.yaml >+++ b/api/v1/swagger/swagger.yaml >@@ -84,6 +84,8 @@ definitions: > $ref: ./definitions/item.yaml > item_group: > $ref: ./definitions/item_group.yaml >+ item_type: >+ $ref: ./definitions/item_type.yaml > job: > $ref: ./definitions/job.yaml > library: >@@ -299,6 +301,8 @@ paths: > $ref: ./paths/import_batch_profiles.yaml#/~1import_batch_profiles > "/import_batch_profiles/{import_batch_profile_id}": > $ref: "./paths/import_batch_profiles.yaml#/~1import_batch_profiles~1{import_batch_profile_id}" >+ /item_types: >+ $ref: ./paths/item_types.yaml#/~1item_types > /items: > $ref: ./paths/items.yaml#/~1items > "/items/{item_id}": >@@ -964,6 +968,9 @@ tags: > - description: "Manage items\n" > name: items > x-displayName: Items >+ - description: "Manage item types\n" >+ name: item_types >+ x-displayName: Item Types > - description: "Manage jobs\n" > name: jobs > x-displayName: Jobs >diff --git a/t/db_dependent/api/v1/item_types.t b/t/db_dependent/api/v1/item_types.t >new file mode 100755 >index 00000000000..d45208ccfbc >--- /dev/null >+++ b/t/db_dependent/api/v1/item_types.t >@@ -0,0 +1,142 @@ >+#!/usr/bin/env perl >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::More tests => 1; >+use Test::Mojo; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use Koha::ItemTypes; >+use Koha::Database; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+ >+my $t = Test::Mojo->new('Koha::REST::V1'); >+t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); >+ >+subtest 'list_item_types() tests' => sub { >+ >+ plan tests => 12; >+ >+ $schema->storage->txn_begin; >+ >+ my $item_type = $builder->build_object( >+ { >+ class => 'Koha::ItemTypes', >+ value => { >+ itemtype => 'TEST_IT', >+ parent_type => undef, >+ description => 'Test item type', >+ rentalcharge => 100.0, >+ rentalcharge_daily => 50., >+ rentalcharge_daily_calendar => 0, >+ rentalcharge_hourly => 0.60, >+ rentalcharge_hourly_calendar => 1, >+ defaultreplacecost => 1000.0, >+ processfee => 20.0, >+ notforloan => 0, >+ imageurl => 'https://upload.wikimedia.org/wikipedia/commons/1/1f/202208_test-tube-4.svg', >+ summary => 'An item type for testing', >+ checkinmsg => 'Checking in test', >+ checkinmsgtype => 'message', >+ sip_media_type => 'spt', >+ hideinopac => 1, >+ searchcategory => 'test search category', >+ automatic_checkin => 0, >+ } >+ } >+ ); >+ >+ my $en = $builder->build_object( >+ { >+ class => 'Koha::Localizations', >+ value => { >+ entity => 'itemtypes', >+ code => 'TEST_IT', >+ lang => 'en', >+ translation => 'English word "test"', >+ } >+ } >+ ); >+ my $sv = $builder->build_object( >+ { >+ class => 'Koha::Localizations', >+ value => { >+ entity => 'itemtypes', >+ code => 'TEST_IT', >+ lang => 'sv_SE', >+ translation => 'Swedish word "test"', >+ } >+ } >+ ); >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 2**2 } # catalogue flag = 2 >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ ## Authorized user tests >+ # No category, 404 expected >+ $t->get_ok("//$userid:$password@/api/v1/item_types")->status_is(200)->json_has('/0'); >+ >+ for my $json ( @{ $t->tx->res->json } ) { >+ if ( $json->{item_type} eq 'TEST_IT' ) { >+ is( $json->{description}, 'Test item type' ); >+ ok( !exists $json->{translated_descriptions} ); >+ } >+ } >+ >+ $t->get_ok( "//$userid:$password@/api/v1/item_types" => { 'x-koha-embed' => 'translated_descriptions' } ) >+ ->status_is(200)->json_has('/0'); >+ >+ for my $json ( @{ $t->tx->res->json } ) { >+ if ( $json->{item_type} eq 'TEST_IT' ) { >+ is( $json->{description}, 'Test item type' ); >+ is_deeply( >+ $json->{translated_descriptions}, >+ [ >+ { lang => 'en', translation => 'English word "test"' }, >+ { lang => 'sv_SE', translation => 'Swedish word "test"' }, >+ ] >+ ); >+ } >+ } >+ >+ # Unauthorized access >+ $t->get_ok("//$unauth_userid:$password@/api/v1/item_types")->status_is(403); >+ >+ $schema->storage->txn_rollback; >+}; >-- >2.42.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 34008
:
155734
|
155737
|
155738
|
155739
|
155741
|
157915
|
157976
|
157977
| 158082 |
158083
|
158084