From aadc56be39c34a40655221fc0b78a022c03c4f39 Mon Sep 17 00:00:00 2001 From: Jiri Kozlovsky Date: Mon, 1 Aug 2016 05:47:05 +0200 Subject: [PATCH] Bug 17007: REST API: add route to get biblio This patch adds route to get one biblio from koha.biblios table. On top of this biblio there is added key "items" with value being array of items belonging to the requested biblio. As Magnus Enger pointed out, we should hide all the items defined in the OpacHiddenItems syspref from all but staff. This patch adds this functionality. To test: 1. Open a browser tab on Koha staff and log in (to create CGISESSID cookie). 2. Send GET request to http://yourlibrary/api/v1/biblios/YYY where YYY is an existing biblionumber. 3. Make sure the returned data is correct. 4. Find items which are hidden in OPAC with OpacHiddenItems syspref, note their record's biblionumber and repeat point 2 with it. 5. Check that if you are logged in as staff, you see all the items (even those hidden from OPAC) 6. Check that if you are not logged in as staff, you see only the items which are not hidden from OPAC 7. Run unit tests in t/db_dependent/api/v1/biblios.t Signed-off-by: Lari Taskula --- Koha/REST/V1/Biblio.pm | 76 ++++++++++++++++++++++++++ api/v1/definitions/biblio.json | 65 ++++++++++++++++++++++ api/v1/definitions/index.json | 1 + api/v1/swagger.json | 32 +++++++++++ t/db_dependent/api/v1/biblios.t | 116 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 290 insertions(+) create mode 100644 Koha/REST/V1/Biblio.pm create mode 100644 api/v1/definitions/biblio.json create mode 100644 t/db_dependent/api/v1/biblios.t diff --git a/Koha/REST/V1/Biblio.pm b/Koha/REST/V1/Biblio.pm new file mode 100644 index 0000000..a10a8fa --- /dev/null +++ b/Koha/REST/V1/Biblio.pm @@ -0,0 +1,76 @@ +package Koha::REST::V1::Biblio; + +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; +use Mojo::JSON; + +use C4::Auth qw( haspermission ); +use C4::Context; +use C4::Items qw( GetItem GetHiddenItemnumbers ); + +use Koha::Biblios; +use Koha::Items; + +sub get { + my ($c, $args, $cb) = @_; + + my $biblionumber = $c->param('biblionumber'); + my $biblio = Koha::Biblios->find($biblionumber); + + unless ($biblio) { + return $c->$cb({error => "Biblio not found"}, 404); + } + + my $items ||= Koha::Items->search( { biblionumber => $biblionumber }, { + columns => [qw/itemnumber/], + })->unblessed; + + my $user = $c->stash('koha.user'); + my $isStaff = haspermission($user->userid, {borrowers => 1}); + + # Hide the hidden items from all but staff + my $opachiddenitems = ! $isStaff + && ( C4::Context->preference('OpacHiddenItems') !~ /^\s*$/ ); + + if ($opachiddenitems) { + + my @hiddenitems = C4::Items::GetHiddenItemnumbers( @{$items} ); + + my @filteredItems = (); + + # Convert to a hash for quick searching + my %hiddenitems = map { $_ => 1 } @hiddenitems; + foreach my $itemnumber ( map { $_->{itemnumber} } @{$items} ) { + next if $hiddenitems{$itemnumber}; + push @filteredItems, { itemnumber => $itemnumber }; + } + + $items = \@filteredItems; + } + + $biblio = $biblio->unblessed; + $biblio->{items} = $items; + + return $c->$cb($biblio, 200); +} + +1; diff --git a/api/v1/definitions/biblio.json b/api/v1/definitions/biblio.json new file mode 100644 index 0000000..a3b35b7 --- /dev/null +++ b/api/v1/definitions/biblio.json @@ -0,0 +1,65 @@ +{ + "type": "object", + "properties": { + "biblionumber": { + "type": "string", + "description": "internal bibliographic record identifier" + }, + "frameworkcode": { + "type": "string", + "description": "foreign key from the biblio_framework table to identify which framework was used in cataloging this record" + }, + "author": { + "type": ["string", "null"], + "description": "statement of responsibility from MARC record (100$a in MARC21)" + }, + "title": { + "type": ["string", "null"], + "description": "title (without the subtitle) from the MARC record (245$a in MARC21)" + }, + "untitle": { + "type": ["string", "null"], + "description": "uniform title (without the subtitle) from the MARC record (240$a in MARC21)" + }, + "notes": { + "type": ["string", "null"], + "description": "values from the general notes field in the MARC record (500$a in MARC21) split by bar (|)" + }, + "serial": { + "type": ["string", "null"], + "description": "Boolean indicating whether biblio is for a serial" + }, + "seriestitle": { + "type": ["string", "null"], + "description": "Title for describing the series" + }, + "copyrightdate": { + "type": ["string", "null"], + "description": "publication or copyright date from the MARC record" + }, + "timestamp": { + "type": "string", + "description": "date and time this record was last touched" + }, + "datecreated": { + "type": "string", + "description": "the date this record was added to Koha" + }, + "abstract": { + "type": ["string", "null"], + "description": "summary from the MARC record (520$a in MARC21)" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "itemnumber": { + "type": "string", + "description": "internal item identifier" + } + } + } + } + } +} diff --git a/api/v1/definitions/index.json b/api/v1/definitions/index.json index 3f69544..10efd36 100644 --- a/api/v1/definitions/index.json +++ b/api/v1/definitions/index.json @@ -2,5 +2,6 @@ "patron": { "$ref": "patron.json" }, "holds": { "$ref": "holds.json" }, "hold": { "$ref": "hold.json" }, + "biblio": { "$ref": "biblio.json" }, "error": { "$ref": "error.json" } } diff --git a/api/v1/swagger.json b/api/v1/swagger.json index b3f30f8..2bc6aa7 100644 --- a/api/v1/swagger.json +++ b/api/v1/swagger.json @@ -332,6 +332,31 @@ } } } + }, + "/biblios/{biblionumber}": { + "get": { + "operationId": "getBiblio", + "tags": ["biblios"], + "parameters": [ + { "$ref": "#/parameters/biblionumberPathParam" } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "responses": { + "200": { + "description": "An biblio", + "schema": { "$ref": "#/definitions/biblio" } + }, + "400": { + "description": "Missing or wrong parameters", + "schema": { "$ref": "#/definitions/error" } + }, + "404": { + "description": "Biblio not found", + "schema": { "$ref": "#/definitions/error" } + } + } + } } }, "definitions": { @@ -351,6 +376,13 @@ "description": "Internal hold identifier", "required": true, "type": "integer" + }, + "biblionumberPathParam": { + "name": "biblionumber", + "in": "path", + "description": "Internal biblio identifier", + "required": true, + "type": "integer" } } } diff --git a/t/db_dependent/api/v1/biblios.t b/t/db_dependent/api/v1/biblios.t new file mode 100644 index 0000000..848fb7a --- /dev/null +++ b/t/db_dependent/api/v1/biblios.t @@ -0,0 +1,116 @@ +#!/usr/bin/env perl + +# Copyright 2016 Koha-Suomi +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Test::More tests => 7; +use Test::Mojo; +use t::lib::TestBuilder; + +use C4::Auth; +use C4::Biblio; +use C4::Context; +use C4::Items; + +use Koha::Database; +use Koha::Patron; +use Koha::Items; + +my $builder = t::lib::TestBuilder->new(); + +my $dbh = C4::Context->dbh; +$dbh->{AutoCommit} = 0; +$dbh->{RaiseError} = 1; + +$ENV{REMOTE_ADDR} = '127.0.0.1'; +my $t = Test::Mojo->new('Koha::REST::V1'); + +my $categorycode = $builder->build({ source => 'Category' })->{ categorycode }; +my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode }; +my $borrower = $builder->build({ + source => 'Borrower', + value => { + branchcode => $branchcode, + categorycode => $categorycode, + flags => 16, + } +}); + +my $librarian = $builder->build({ + source => "Borrower", + value => { + categorycode => $categorycode, + branchcode => $branchcode, + flags => 4, + }, +}); + +my ($session) = create_session($borrower); + +my $biblio = $builder->build({ + source => 'Biblio' +}); +my $biblionumber = $biblio->{biblionumber}; +my $item1 = $builder->build({ + source => 'Item', + value => { + biblionumber => $biblionumber, + } +}); +my $item2 = $builder->build({ + source => 'Item', + value => { + biblionumber => $biblionumber, + } +}); +my $item1number = $item1->{itemnumber}; +my $item2number = $item2->{itemnumber}; + +my $nonExistentBiblionumber = -14362719; +my $tx = $t->ua->build_tx(GET => "/api/v1/biblios/$nonExistentBiblionumber"); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$t->request_ok($tx) + ->status_is(404); + +$tx = $t->ua->build_tx(GET => "/api/v1/biblios/$biblionumber"); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$t->request_ok($tx) + ->status_is(200) + ->json_is('/items/0/itemnumber' => $item1number) + ->json_is('/items/1/itemnumber' => $item2number) + ->json_is('/biblionumber' => $biblionumber); + +$dbh->rollback; + +sub create_session { + my (@borrowers) = @_; + + my @sessions; + foreach $borrower (@borrowers) { + my $session = C4::Auth::get_session(''); + $session->param('number', $borrower->{borrowernumber}); + $session->param('id', $borrower->{userid}); + $session->param('ip', '127.0.0.1'); + $session->param('lasttime', time()); + $session->flush; + push @sessions, $session; + } + + return @sessions; +} -- 1.9.1