Bugzilla – Attachment 190631 Details for
Bug 41463
Add Koha REST API endpoints for OAI sets
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 41463: REST API endpoint to gain information about an OAI set
Bug-41463-REST-API-endpoint-to-gain-information-ab.patch (text/plain), 14.14 KB, created by
Aleisha Amohia
on 2025-12-19 01:03:40 UTC
(
hide
)
Description:
Bug 41463: REST API endpoint to gain information about an OAI set
Filename:
MIME Type:
Creator:
Aleisha Amohia
Created:
2025-12-19 01:03:40 UTC
Size:
14.14 KB
patch
obsolete
>From 911654df5cf5e4b1ee0d440b43e5ff09abf9b903 Mon Sep 17 00:00:00 2001 >From: Aleisha Amohia <aleisha@catalyst.net.nz> >Date: Wed, 17 Dec 2025 04:00:12 +0000 >Subject: [PATCH] Bug 41463: REST API endpoint to gain information about an OAI > set > >This API endpoint is to be used like: > >"/api/v1/oai_sets/{set_id}" > >and shows the following information about an OAI set: > >- set name >- set spec >- set ID >- total count of items in the set >- count of items in the set which also exist in the catalogue - this is useful for determining how many items have been deleted from the catalogue but has not yet been reflected in the OAI set > >To test: > >1. Apply the patch and rebuild resources for the new API endpoints to take effect, then restart services. In KTD this looks like: > >perl ./build-resources.PL >yarn api:bundle >restart_all > >2. Confirm the new getOAISet definition is available to the API: OPAC-URL/api/v1/.html > >3. In the staff interface, go to Koha administration -> OAI sets configuration and create a new set. Give it a spec and name then Save. Go to edit mappings and add the following rule, then Save: > >- Field: 942 >- Subfield: n >- Operator: not equal to >- Value: 1 > >(This would essentially exclude items from the set that are OPAC suppressed) > >4. Search for a record and edit it. Go to tab 9 to find tag 942 and set n to "No". Saving the record will add it to the OAI set. > >5. Now we need to add some items to the set that don't match biblios in the catalogue. The easiest way to do this is by directly adding fake items to the set in the database, something like this: > >sudo koha-mysql kohadev >insert into oai_sets_biblios (biblionumber, set_id) values (12345678, 1); >insert into oai_sets_biblios (biblionumber, set_id) values (123456378, 1); >insert into oai_sets_biblios (biblionumber, set_id) values (12345678, 1); > >So we now have 4 items in the set - 1 that matches an existing biblio in the catalogue, and 3 that don't (in practise, they may have existed once, but have since been deleted and the set hasn't harvested those deletions). > >6. Go to the API endpoint for your set and confirm the correction information is fetched: OPAC-URL/api/v1/oai_sets/{set_id} > >7. Confirm tests pass: > >prove t/db_dependent/OAI/Sets.t >prove t/db_dependent/api/v1/oai_sets.t > >Sponsored-by: Auckland University of Technology >--- > Koha/OAI/Set.pm | 66 +++++++++++++++ > Koha/REST/V1/OAI/Sets.pm | 58 +++++++++++++ > api/v1/swagger/definitions/oai_set.yaml | 21 +++++ > api/v1/swagger/paths/oai_sets.yaml | 47 +++++++++++ > api/v1/swagger/swagger.yaml | 4 + > t/db_dependent/OAI/Sets.t | 43 +++++++++- > t/db_dependent/api/v1/oai_sets.t | 103 ++++++++++++++++++++++++ > 7 files changed, 341 insertions(+), 1 deletion(-) > create mode 100644 Koha/REST/V1/OAI/Sets.pm > create mode 100644 api/v1/swagger/definitions/oai_set.yaml > create mode 100644 api/v1/swagger/paths/oai_sets.yaml > create mode 100755 t/db_dependent/api/v1/oai_sets.t > >diff --git a/Koha/OAI/Set.pm b/Koha/OAI/Set.pm >index 5b52edc3168..be38b7447d3 100644 >--- a/Koha/OAI/Set.pm >+++ b/Koha/OAI/Set.pm >@@ -33,6 +33,72 @@ Koha::OAI::Set - Koha OaiSet Object class > > =cut > >+=head3 biblionumbers >+ >+ my @biblionumbers = $set->biblionumbers->as_list; >+ >+Returns the biblionumbers contained in this set. >+ >+=cut >+ >+sub biblionumbers { >+ my ( $self, $params ) = @_; >+ >+ return $self->_result->oai_sets_biblios->search( {}, { columns => ['biblionumber'] } ); >+} >+ >+=head3 biblios >+ >+ my @biblios = $set->biblios->as_list; >+ >+Returns the Koha::Biblio objects that exist in the catalog for records in this set. >+ >+=cut >+ >+sub biblios { >+ my ( $self, $params ) = @_; >+ >+ return Koha::Biblios->search( { biblionumber => scalar $self->biblionumbers } ); >+} >+ >+=head3 to_api >+ >+ my $json = $set->to_api; >+ >+Overloaded method that returns a JSON representation of the Koha::OAI::Set object, >+suitable for API output. >+ >+=cut >+ >+sub to_api { >+ my ( $self, $params ) = @_; >+ >+ my $json_set = $self->SUPER::to_api($params); >+ >+ return unless $json_set; >+ >+ $json_set->{total_count} = $self->biblionumbers->count; >+ >+ $json_set->{catalog_count} = $self->biblios->count; >+ >+ return $json_set; >+} >+ >+=head3 to_api_mapping >+ >+This method returns the mapping for representing a Koha::OAI::Set object >+on the API. >+ >+=cut >+ >+sub to_api_mapping { >+ return { >+ id => 'set_id', >+ spec => 'spec', >+ name => 'name', >+ }; >+} >+ > =head2 Internal methods > > =head3 _type >diff --git a/Koha/REST/V1/OAI/Sets.pm b/Koha/REST/V1/OAI/Sets.pm >new file mode 100644 >index 00000000000..8bbda476acd >--- /dev/null >+++ b/Koha/REST/V1/OAI/Sets.pm >@@ -0,0 +1,58 @@ >+package Koha::REST::V1::OAI::Sets; >+ >+# 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 <https://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use Try::Tiny qw( catch try ); >+ >+use Koha::OAI::Sets; >+ >+=head1 NAME >+ >+Koha::REST::V1::OAI::Sets; >+ >+=head1 API >+ >+=head2 Methods >+ >+=head3 get >+ >+Controller function that handles retrieving an OAI set >+ >+=cut >+ >+sub get { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $set = Koha::OAI::Sets->find( $c->param('set_id') ); >+ >+ return $c->render_resource_not_found("OAI set") >+ unless $set; >+ >+ return $c->render( >+ status => 200, >+ openapi => $c->objects->to_api($set), >+ ); >+ } catch { >+ $c->unhandled_exception($_); >+ } >+} >+ >+1; >diff --git a/api/v1/swagger/definitions/oai_set.yaml b/api/v1/swagger/definitions/oai_set.yaml >new file mode 100644 >index 00000000000..57cd6b545da >--- /dev/null >+++ b/api/v1/swagger/definitions/oai_set.yaml >@@ -0,0 +1,21 @@ >+--- >+type: object >+properties: >+ set_id: >+ type: integer >+ description: Internal OAI set identifier >+ spec: >+ type: string >+ description: Indicates a hierarchy of sets >+ name: >+ type: string >+ description: Name of set >+ total_count: >+ type: integer >+ description: Number of total items in the set >+ catalog_count: >+ type: integer >+ description: Number of items which exist both in the set and in the catalog >+additionalProperties: false >+required: >+ - set_id >diff --git a/api/v1/swagger/paths/oai_sets.yaml b/api/v1/swagger/paths/oai_sets.yaml >new file mode 100644 >index 00000000000..d87857773d0 >--- /dev/null >+++ b/api/v1/swagger/paths/oai_sets.yaml >@@ -0,0 +1,47 @@ >+--- >+"/oai_sets/{set_id}": >+ get: >+ x-mojo-to: OAI::Sets#get >+ operationId: getOAISet >+ tags: >+ - oai_sets >+ summary: Get OAI set >+ parameters: >+ - name: set_id >+ in: path >+ description: Internal OAI set identifier >+ required: true >+ type: integer >+ produces: >+ - application/json >+ responses: >+ "200": >+ description: An OAI set >+ schema: >+ $ref: "../swagger.yaml#/definitions/oai_set" >+ "400": >+ description: Bad request >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "404": >+ description: Patron 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: >+ parameters: manage_oai_sets >diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml >index dcb0a3cc66e..8ac7f73d130 100644 >--- a/api/v1/swagger/swagger.yaml >+++ b/api/v1/swagger/swagger.yaml >@@ -142,6 +142,8 @@ definitions: > $ref: ./definitions/list.yaml > merge_biblios: > $ref: ./definitions/merge_biblios.yaml >+ oai_set: >+ $ref: ./definitions/oai_set.yaml > order: > $ref: ./definitions/order.yaml > order_claim: >@@ -483,6 +485,8 @@ paths: > $ref: "./paths/libraries.yaml#/~1libraries~1{library_id}~1cash_registers" > "/libraries/{library_id}/desks": > $ref: "./paths/libraries.yaml#/~1libraries~1{library_id}~1desks" >+ "/oai_sets/{set_id}": >+ $ref: "./paths/oai_sets.yaml#/~1oai_sets~1{set_id}" > "/oauth/login/{provider_code}/{interface}": > $ref: ./paths/oauth.yaml#/~1oauth~1login~1{provider_code}~1{interface} > /oauth/token: >diff --git a/t/db_dependent/OAI/Sets.t b/t/db_dependent/OAI/Sets.t >index fe46c89b1c9..f973756efca 100755 >--- a/t/db_dependent/OAI/Sets.t >+++ b/t/db_dependent/OAI/Sets.t >@@ -19,12 +19,13 @@ > use Modern::Perl; > > use Test::NoWarnings; >-use Test::More tests => 154; >+use Test::More tests => 155; > use Test::MockModule; > use Test::Warn; > use MARC::Record; > > use Koha::Database; >+use Koha::OAI::Sets; > use C4::OAI::Sets > qw( AddOAISet GetOAISets GetOAISet GetOAISetBySpec ModOAISet ModOAISetMappings GetOAISetsMappings GetOAISetMappings AddOAISetsBiblios GetOAISetsBiblio ModOAISetsBiblios DelOAISet DelOAISetsBiblio UpdateOAISetsBiblio CalcOAISetsBiblio ); > >@@ -735,4 +736,44 @@ ModOAISetMappings( $setRep_id, $mappingRepC ); > my @setsRepC = CalcOAISetsBiblio($record_rep); > is_deeply( \@setsRepC, [$setRep_id], 'The $record belongs to $setRep_id (matching on second field, second subfield)' ); > >+subtest 'Koha::OAI::Sets tests' => sub { >+ >+ plan tests => 2; >+ >+ my $set = $builder->build_object( >+ { >+ class => 'Koha::OAI::Sets', >+ value => { spec => 'A' } >+ } >+ ); >+ my $set_id = $set->id; >+ >+ my $set_item_deleted_1 = $builder->build_object( >+ { >+ class => 'Koha::OAI::Set::Biblios', >+ value => { set_id => $set_id, biblionumber => 123456789 } >+ } >+ ); >+ >+ my $set_item_deleted_2 = $builder->build_object( >+ { >+ class => 'Koha::OAI::Set::Biblios', >+ value => { set_id => $set_id, biblionumber => 987654321 } >+ } >+ ); >+ >+ my $biblio = $builder->build_sample_biblio(); >+ >+ my $set_item_in_catalog = $builder->build_object( >+ { >+ class => 'Koha::OAI::Set::Biblios', >+ value => { set_id => $set_id, biblionumber => $biblio->id } >+ } >+ ); >+ >+ my $fetched_set = Koha::OAI::Sets->find($set_id); >+ is( $fetched_set->biblionumbers->count, 3, "Set contains three items" ); >+ is( $fetched_set->biblios->count, 1, "Set contains one item that currently exists in the catalog" ); >+}; >+ > $schema->storage->txn_rollback; >diff --git a/t/db_dependent/api/v1/oai_sets.t b/t/db_dependent/api/v1/oai_sets.t >new file mode 100755 >index 00000000000..ae1c5c73950 >--- /dev/null >+++ b/t/db_dependent/api/v1/oai_sets.t >@@ -0,0 +1,103 @@ >+#!/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 <https://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::More tests => 2; >+use Test::NoWarnings; >+use Test::Mojo; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use Koha::OAI::Sets; >+use Koha::OAI::Set::Biblios; >+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 'get() tests' => sub { >+ >+ plan tests => 5; >+ >+ $schema->storage->txn_begin; >+ >+ Koha::OAI::Set::Biblios->search->delete; >+ Koha::OAI::Sets->search->delete; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 3**2 } # parameters flag = 3 >+ } >+ ); >+ 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; >+ >+ my $set = $builder->build_object( >+ { >+ class => 'Koha::OAI::Sets', >+ value => { spec => 'A' } >+ } >+ ); >+ my $set_id = $set->id; >+ >+ my $set_item_deleted_1 = $builder->build_object( >+ { >+ class => 'Koha::OAI::Set::Biblios', >+ value => { set_id => $set_id, biblionumber => 123456789 } >+ } >+ ); >+ >+ my $set_item_deleted_2 = $builder->build_object( >+ { >+ class => 'Koha::OAI::Set::Biblios', >+ value => { set_id => $set_id, biblionumber => 987654321 } >+ } >+ ); >+ >+ my $biblio = $builder->build_sample_biblio(); >+ >+ my $set_item_in_catalog = $builder->build_object( >+ { >+ class => 'Koha::OAI::Set::Biblios', >+ value => { set_id => $set_id, biblionumber => $biblio->id } >+ } >+ ); >+ >+ $t->get_ok("//$userid:$password@/api/v1/oai_sets/$set_id")->status_is(200)->json_is( $set->to_api ); >+ >+ # Unauthorized access >+ $t->get_ok("//$unauth_userid:$password@/api/v1/oai_sets/$set_id")->status_is(403); >+ >+ $schema->storage->txn_rollback; >+}; >-- >2.39.5
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 41463
:
190565
|
190610
| 190631