Bug 25898: Prohibit indirect object notation
[koha.git] / Koha / OAI / Server / Repository.pm
blobca34ee8d00337acb99763aa98a3b2e616c7f07b3
1 # Copyright Tamil s.a.r.l. 2008-2015
2 # Copyright Biblibre 2008-2015
3 # Copyright The National Library of Finland, University of Helsinki 2016
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 package Koha::OAI::Server::Repository;
22 use Modern::Perl;
23 use HTTP::OAI;
24 use HTTP::OAI::Repository qw/:validate/;
26 use base ("HTTP::OAI::Repository");
28 use Koha::OAI::Server::Identify;
29 use Koha::OAI::Server::ListSets;
30 use Koha::OAI::Server::ListMetadataFormats;
31 use Koha::OAI::Server::GetRecord;
32 use Koha::OAI::Server::ListRecords;
33 use Koha::OAI::Server::ListIdentifiers;
34 use XML::SAX::Writer;
35 use YAML::Syck qw( LoadFile );
36 use CGI qw/:standard -oldstyle_urls/;
37 use C4::Context;
38 use C4::Biblio;
39 use Koha::XSLT::Base;
41 =head1 NAME
43 Koha::OAI::Server::Repository - Handles OAI-PMH requests for a Koha database.
45 =head1 SYNOPSIS
47 use Koha::OAI::Server::Repository;
49 my $repository = Koha::OAI::Server::Repository->new();
51 =head1 DESCRIPTION
53 This object extend HTTP::OAI::Repository object.
54 It accepts OAI-PMH HTTP requests and returns result.
56 This OAI-PMH server can operate in a simple mode and extended one.
58 In simple mode, repository configuration comes entirely from Koha system
59 preferences (OAI-PMH:archiveID and OAI-PMH:MaxCount) and the server returns
60 records in marcxml or dublin core format. Dublin core records are created from
61 koha marcxml records transformed with XSLT. Used XSL file is located in koha-
62 tmpl/intranet-tmpl/prog/en/xslt directory and chosen based on marcflavour,
63 respecively MARC21slim2OAIDC.xsl for MARC21 and MARC21slim2OAIDC.xsl for
64 UNIMARC.
66 In extended mode, it's possible to parameter other format than marcxml or
67 Dublin Core. A new syspref OAI-PMH:ConfFile specify a YAML configuration file
68 which list available metadata formats and XSL file used to create them from
69 marcxml records. If this syspref isn't set, Koha OAI server works in simple
70 mode. A configuration file koha-oai.conf can look like that:
72 ---
73 format:
74 vs:
75 metadataPrefix: vs
76 metadataNamespace: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs
77 schema: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs.xsd
78 xsl_file: /usr/local/koha/xslt/vs.xsl
79 marc21:
80 metadataPrefix: marc21
81 metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
82 schema: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
83 include_items: 1
84 marcxml:
85 metadataPrefix: marxml
86 metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
87 schema: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
88 include_items: 1
89 oai_dc:
90 metadataPrefix: oai_dc
91 metadataNamespace: http://www.openarchives.org/OAI/2.0/oai_dc/
92 schema: http://www.openarchives.org/OAI/2.0/oai_dc.xsd
93 xsl_file: /usr/local/koha/koha-tmpl/intranet-tmpl/xslt/UNIMARCslim2OAIDC.xsl
95 Note the 'include_items' parameter which is the only mean to return item-level info.
97 =cut
100 sub new {
101 my ($class, %args) = @_;
102 my $self = $class->SUPER::new(%args);
104 $self->{ koha_identifier } = C4::Context->preference("OAI-PMH:archiveID");
105 $self->{ koha_max_count } = C4::Context->preference("OAI-PMH:MaxCount");
106 $self->{ koha_metadata_format } = ['oai_dc', 'marc21', 'marcxml'];
107 $self->{ xslt_engine } = Koha::XSLT::Base->new;
109 # Load configuration file if defined in OAI-PMH:ConfFile syspref
110 if ( my $file = C4::Context->preference("OAI-PMH:ConfFile") ) {
111 $self->{ conf } = LoadFile( $file );
112 my @formats = keys %{ $self->{conf}->{format} };
113 $self->{ koha_metadata_format } = \@formats;
116 # OAI-PMH handles dates in UTC, so do that on the database level to avoid need for
117 # any conversions
118 my $sth = C4::Context->dbh->prepare('SELECT @@session.time_zone');
119 $sth->execute();
120 my ( $orig_tz ) = $sth->fetchrow();
121 $self->{ mysql_orig_tz } = $orig_tz;
122 C4::Context->dbh->prepare("SET time_zone='+00:00'")->execute();
124 # Check for grammatical errors in the request
125 my @errs = validate_request( CGI::Vars() );
127 # Is metadataPrefix supported by the repository?
128 my $mdp = param('metadataPrefix') || '';
129 if ( $mdp && !grep { $_ eq $mdp } @{$self->{ koha_metadata_format }} ) {
130 push @errs, HTTP::OAI::Error->new(
131 code => 'cannotDisseminateFormat',
132 message => "Dissemination as '$mdp' is not supported",
136 my $response;
137 if ( @errs ) {
138 $response = HTTP::OAI::Response->new(
139 requestURL => self_url(),
140 errors => \@errs,
143 else {
144 my %attr = CGI::Vars();
145 my $verb = delete $attr{verb};
146 my $class = "Koha::OAI::Server::$verb";
147 $response = $class->new($self, %attr);
150 $response->set_handler( XML::SAX::Writer->new( Output => *STDOUT ) );
151 $response->xslt( "/opac-tmpl/xslt/OAI.xslt" );
152 $response->generate;
154 bless $self, $class;
155 return $self;
159 sub DESTROY {
160 my ( $self ) = @_;
162 # Reset time zone to the original value
163 C4::Context->dbh->prepare("SET time_zone='" . $self->{ mysql_orig_tz } . "'")->execute()
164 if $self->{ mysql_orig_tz };
168 sub get_biblio_marcxml {
169 my ($self, $biblionumber, $format) = @_;
170 my $with_items = 0;
171 if ( my $conf = $self->{conf} ) {
172 $with_items = $conf->{format}->{$format}->{include_items};
174 my $record = GetMarcBiblio({
175 biblionumber => $biblionumber,
176 embed_items => $with_items,
177 opac => 1 });
178 $record ? $record->as_xml_record() : undef;
182 sub stylesheet {
183 my ( $self, $format ) = @_;
184 my $xsl_file = $self->{ conf }
185 ? $self->{ conf }->{ format }->{ $format }->{ xsl_file }
186 : ( C4::Context->config('intrahtdocs') .
187 '/prog/en/xslt/' .
188 C4::Context->preference('marcflavour') .
189 'slim2OAIDC.xsl'
191 return $xsl_file;
195 sub items_included {
196 my ( $self, $format ) = @_;
198 if ( my $conf = $self->{ conf } ) {
199 return $conf->{ format }->{ $format }->{ include_items };
201 return 0;