View | Details | Raw Unified | Return to bug 15108
Collapse All | Expand All

(-)a/Koha/OAI/Server/GetRecord.pm (-22 / +66 lines)
Lines 32-51 sub new { Link Here
32
32
33
    my $self = HTTP::OAI::GetRecord->new(%args);
33
    my $self = HTTP::OAI::GetRecord->new(%args);
34
34
35
    my $prefix = $repository->{koha_identifier} . ':';
36
    my ($biblionumber) = $args{identifier} =~ /^$prefix(.*)/;
37
    my $items_included = $repository->items_included( $args{metadataPrefix} );
35
    my $dbh = C4::Context->dbh;
38
    my $dbh = C4::Context->dbh;
36
    my $sth = $dbh->prepare("
39
    my $sql = "
37
        SELECT timestamp
40
        SELECT timestamp
38
        FROM   biblioitems
41
        FROM   biblioitems
39
        WHERE  biblionumber=? " );
42
        WHERE  biblionumber=?
40
    my $prefix = $repository->{koha_identifier} . ':';
43
    ";
41
    my ($biblionumber) = $args{identifier} =~ /^$prefix(.*)/;
44
    my @bind_params = ($biblionumber);
42
    $sth->execute( $biblionumber );
45
    if ( $items_included ) {
46
        # Take latest timestamp of biblio and any items
47
        $sql .= "
48
            UNION
49
            SELECT timestamp from deleteditems
50
            WHERE biblionumber=?
51
            UNION
52
            SELECT timestamp from items
53
            WHERE biblionumber=?
54
        ";
55
        push @bind_params, $biblionumber;
56
        push @bind_params, $biblionumber;
57
        $sql = "
58
            SELECT max(timestamp)
59
            FROM ($sql) bib
60
        ";
61
    }
62
63
    my $sth = $dbh->prepare( $sql ) || die( 'Could not prepare statement: ' . $dbh->errstr );
64
    $sth->execute( @bind_params ) || die( 'Could not execute statement: ' . $sth->errstr );
43
    my ($timestamp, $deleted);
65
    my ($timestamp, $deleted);
44
    unless ( ($timestamp) = $sth->fetchrow ) {
66
    unless ( ($timestamp = $sth->fetchrow) ) {
45
        unless ( ($timestamp) = $dbh->selectrow_array(q/
67
        $sql = "
46
            SELECT timestamp
68
            SELECT timestamp
47
            FROM deletedbiblio
69
            FROM deletedbiblio
48
            WHERE biblionumber=? /, undef, $biblionumber ))
70
            WHERE biblionumber=?
71
        ";
72
        @bind_params = ($biblionumber);
73
74
        if ( $items_included ) {
75
            # Take latest timestamp among biblio and items
76
            $sql .= "
77
                UNION
78
                SELECT timestamp from deleteditems
79
                WHERE biblionumber=?
80
            ";
81
            push @bind_params, $biblionumber;
82
            $sql = "
83
                SELECT max(timestamp)
84
                FROM ($sql) bib
85
            ";
86
        }
87
88
        $sth = $dbh->prepare($sql) || die('Could not prepare statement: ' . $dbh->errstr);
89
        $sth->execute( @bind_params ) || die('Could not execute statement: ' . $sth->errstr);
90
        unless ( ($timestamp = $sth->fetchrow) )
49
        {
91
        {
50
            return HTTP::OAI::Response->new(
92
            return HTTP::OAI::Response->new(
51
             requestURL  => $repository->self_url(),
93
             requestURL  => $repository->self_url(),
Lines 55-82 sub new { Link Here
55
                ) ],
97
                ) ],
56
            );
98
            );
57
        }
99
        }
58
        else {
100
        $deleted = 1;
59
            $deleted = 1;
60
        }
61
    }
101
    }
62
102
63
    # We fetch it using this method, rather than the database directly,
64
    # so it'll include the item data
65
    my $marcxml;
66
    $marcxml = $repository->get_biblio_marcxml($biblionumber, $args{metadataPrefix})
67
        unless $deleted;
68
    my $oai_sets = GetOAISetsBiblio($biblionumber);
103
    my $oai_sets = GetOAISetsBiblio($biblionumber);
69
    my @setSpecs;
104
    my @setSpecs;
70
    foreach (@$oai_sets) {
105
    foreach (@$oai_sets) {
71
        push @setSpecs, $_->{spec};
106
        push @setSpecs, $_->{spec};
72
    }
107
    }
73
108
74
    #$self->header( HTTP::OAI::Header->new( identifier  => $args{identifier} ) );
109
    if ($deleted) {
75
    $self->record(
110
        $self->record(
76
        $deleted
111
            Koha::OAI::Server::DeletedRecord->new($timestamp, \@setSpecs, %args)
77
        ? Koha::OAI::Server::DeletedRecord->new($timestamp, \@setSpecs, %args)
112
        );
78
        : Koha::OAI::Server::Record->new($repository, $marcxml, $timestamp, \@setSpecs, %args)
113
    } else {
79
    );
114
        # We fetch it using this method, rather than the database directly,
115
        # so it'll include the item data
116
        my $marcxml;
117
        $marcxml = $repository->get_biblio_marcxml($biblionumber, $args{metadataPrefix})
118
            unless $deleted;
119
120
        $self->record(
121
            Koha::OAI::Server::Record->new($repository, $marcxml, $timestamp, \@setSpecs, %args)
122
        );
123
    }
80
    return $self;
124
    return $self;
81
}
125
}
82
126
(-)a/Koha/OAI/Server/Identify.pm (-2 / +3 lines)
Lines 1-5 Link Here
1
# Copyright Tamil s.a.r.l. 2008-2015
1
# Copyright Tamil s.a.r.l. 2008-2015
2
# Copyright Biblibre 2008-2015
2
# Copyright Biblibre 2008-2015
3
# Copyright The National Library of Finland, University of Helsinki 2016
3
#
4
#
4
# This file is part of Koha.
5
# This file is part of Koha.
5
#
6
#
Lines 33-40 sub new { Link Here
33
        repositoryName      => C4::Context->preference("LibraryName"),
34
        repositoryName      => C4::Context->preference("LibraryName"),
34
        adminEmail          => C4::Context->preference("KohaAdminEmailAddress"),
35
        adminEmail          => C4::Context->preference("KohaAdminEmailAddress"),
35
        MaxCount            => C4::Context->preference("OAI-PMH:MaxCount"),
36
        MaxCount            => C4::Context->preference("OAI-PMH:MaxCount"),
36
        granularity         => 'YYYY-MM-DD',
37
        granularity         => 'YYYY-MM-DDThh:mm:ssZ',
37
        earliestDatestamp   => '0001-01-01',
38
        earliestDatestamp   => '0001-01-01T00:00:00Z',
38
        deletedRecord       => C4::Context->preference("OAI-PMH:DeletedRecord") || 'no',
39
        deletedRecord       => C4::Context->preference("OAI-PMH:DeletedRecord") || 'no',
39
    );
40
    );
40
41
(-)a/Koha/OAI/Server/ListBase.pm (+179 lines)
Line 0 Link Here
1
package Koha::OAI::Server::ListBase;
2
3
# Copyright The National Library of Finland, University of Helsinki 2016
4
#
5
# This file is part of Koha.
6
#
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.
11
#
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.
16
#
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>.
19
20
=head1 NAME
21
22
Koha::OAI::Server::ListBase - OAI ListIdentifiers/ListRecords shared functionality
23
24
=head1 DESCRIPTION
25
26
Koha::OAI::Server::ListBase contains OAI-PMH functions shared by ListIdentifiers and ListRecords.
27
28
=cut
29
30
use Modern::Perl;
31
use C4::Biblio;
32
use HTTP::OAI;
33
use Koha::OAI::Server::ResumptionToken;
34
use Koha::OAI::Server::Record;
35
use Koha::OAI::Server::DeletedRecord;
36
use C4::OAI::Sets;
37
use MARC::File::XML;
38
39
sub GetRecords {
40
    my ($class, $self, $repository, $metadata, %args) = @_;
41
42
    my $token = new Koha::OAI::Server::ResumptionToken( %args );
43
    my $dbh = C4::Context->dbh;
44
    my $set;
45
    if ( defined $token->{'set'} ) {
46
        $set = GetOAISetBySpec($token->{'set'});
47
    }
48
    my $offset = $token->{offset};
49
    my $deleted = defined $token->{deleted} ? $token->{deleted} : 1;
50
    my $max = $repository->{koha_max_count};
51
    my $count = 0;
52
    my $format = $args{metadataPrefix} || $token->{metadata_prefix};
53
    my $include_items = $repository->items_included( $format );
54
55
    # Since creating a union of normal and deleted record tables would be a heavy
56
    # operation in a large database, build results in two stages:
57
    # first deleted records ($deleted == 1), then normal records ($deleted == 0)
58
    STAGELOOP:
59
    for ( ; $deleted >= 0; $deleted-- ) {
60
        my $table = $deleted ? 'deletedbiblioitems' : 'biblioitems';
61
        my $sql = "
62
            SELECT biblionumber
63
            FROM $table
64
            WHERE (timestamp >= ? AND timestamp <= ?)
65
        ";
66
        my @bind_params = ($token->{'from_arg'}, $token->{'until_arg'});
67
68
        if ($include_items) {
69
            $sql .= "
70
                OR biblionumber IN (SELECT biblionumber from deleteditems WHERE timestamp >= ? AND timestamp <= ?)
71
            ";
72
            push @bind_params, ($token->{'from_arg'}, $token->{'until_arg'});
73
            if (!$deleted) {
74
                $sql .= "
75
                    OR biblionumber IN (SELECT biblionumber from items WHERE timestamp >= ? AND timestamp <= ?)
76
                ";
77
                push @bind_params, ($token->{'from_arg'}, $token->{'until_arg'});
78
            }
79
        }
80
81
        $sql .= "
82
            ORDER BY timestamp
83
        ";
84
85
        # Use a subquery for sets since it allows us to use an index in
86
        # biblioitems table and is quite a bit faster than a join.
87
        if (defined $set) {
88
            $sql = "
89
                SELECT bi.* FROM ($sql) bi
90
                  WHERE bi.biblionumber in (SELECT osb.biblionumber FROM oai_sets_biblios osb WHERE osb.set_id = ?)
91
            ";
92
            push @bind_params, $set->{'id'};
93
        }
94
95
        $sql .= "
96
            LIMIT " . ($max + 1) . "
97
            OFFSET $offset
98
        ";
99
100
        my $sth = $dbh->prepare( $sql ) || die( 'Could not prepare statement: ' . $dbh->errstr );
101
102
        if ( $deleted ) {
103
            $sql = "
104
                SELECT MAX(timestamp)
105
                FROM (
106
                    SELECT timestamp FROM deletedbiblioitems WHERE biblionumber = ?
107
                    UNION
108
                    SELECT timestamp FROM deleteditems WHERE biblionumber = ?
109
                ) bis
110
            ";
111
        } else {
112
            $sql = "
113
                SELECT MAX(timestamp)
114
                FROM (
115
                    SELECT timestamp FROM biblioitems WHERE biblionumber = ?
116
                    UNION
117
                    SELECT timestamp FROM deleteditems WHERE biblionumber = ?
118
                    UNION
119
                    SELECT timestamp FROM items WHERE biblionumber = ?
120
                ) bi
121
            ";
122
        }
123
        my $record_sth = $dbh->prepare( $sql ) || die( 'Could not prepare statement: ' . $dbh->errstr );
124
125
        $sth->execute( @bind_params ) || die( 'Could not execute statement: ' . $sth->errstr );
126
        while ( my ($biblionumber) = $sth->fetchrow ) {
127
            $count++;
128
            if ( $count > $max ) {
129
                $self->resumptionToken(
130
                    new Koha::OAI::Server::ResumptionToken(
131
                        metadataPrefix  => $token->{metadata_prefix},
132
                        from            => $token->{from},
133
                        until           => $token->{until},
134
                        offset          => $offset + $max,
135
                        set             => $token->{set},
136
                        deleted         => $deleted
137
                    )
138
                );
139
                last STAGELOOP;
140
            }
141
            my @params = $deleted ? ( $biblionumber, $biblionumber ) : ( $biblionumber, $biblionumber, $biblionumber );
142
            $record_sth->execute( @params ) || die( 'Could not execute statement: ' . $sth->errstr );
143
144
            my ($timestamp) = $record_sth->fetchrow;
145
146
            my $oai_sets = GetOAISetsBiblio($biblionumber);
147
            my @setSpecs;
148
            foreach ( @$oai_sets ) {
149
                push @setSpecs, $_->{spec};
150
            }
151
            if ( $metadata ) {
152
                my $marcxml = !$deleted ? $repository->get_biblio_marcxml($biblionumber, $format) : undef;
153
                if ( $marcxml ) {
154
                  $self->record( Koha::OAI::Server::Record->new(
155
                      $repository, $marcxml, $timestamp, \@setSpecs,
156
                      identifier      => $repository->{ koha_identifier } . ':' . $biblionumber,
157
                      metadataPrefix  => $token->{metadata_prefix}
158
                  ) );
159
                } else {
160
                  $self->record( Koha::OAI::Server::DeletedRecord->new(
161
                      $timestamp, \@setSpecs, identifier => $repository->{ koha_identifier } . ':' . $biblionumber
162
                  ) );
163
                }
164
            } else {
165
                $timestamp =~ s/ /T/, $timestamp .= 'Z';
166
                $self->identifier( new HTTP::OAI::Header(
167
                    identifier => $repository->{ koha_identifier} . ':' . $biblionumber,
168
                    datestamp  => $timestamp,
169
                    status     => $deleted ? 'deleted' : undef
170
                ) );
171
            }
172
        }
173
        # Reset offset for next stage
174
        $offset = 0;
175
    }
176
    return $count;
177
}
178
179
1;
(-)a/Koha/OAI/Server/ListIdentifiers.pm (-56 / +3 lines)
Lines 1-5 Link Here
1
# Copyright Tamil s.a.r.l. 2008-2015
1
# Copyright Tamil s.a.r.l. 2008-2015
2
# Copyright Biblibre 2008-2015
2
# Copyright Biblibre 2008-2015
3
# Copyright The National Library of Finland, University of Helsinki 2016
3
#
4
#
4
# This file is part of Koha.
5
# This file is part of Koha.
5
#
6
#
Lines 19-87 Link Here
19
package Koha::OAI::Server::ListIdentifiers;
20
package Koha::OAI::Server::ListIdentifiers;
20
21
21
use Modern::Perl;
22
use Modern::Perl;
22
use HTTP::OAI;
23
use C4::OAI::Sets;
24
25
use base ("HTTP::OAI::ListIdentifiers");
26
23
24
use base qw(HTTP::OAI::ListIdentifiers Koha::OAI::Server::ListBase);
27
25
28
sub new {
26
sub new {
29
    my ($class, $repository, %args) = @_;
27
    my ($class, $repository, %args) = @_;
30
28
31
    my $self = HTTP::OAI::ListIdentifiers->new(%args);
29
    my $self = HTTP::OAI::ListIdentifiers->new(%args);
32
30
33
    my $token = new Koha::OAI::Server::ResumptionToken( %args );
31
    my $count = $class->GetRecords($self, $repository, 0, %args);
34
    my $dbh = C4::Context->dbh;
35
    my $set;
36
    if(defined $token->{'set'}) {
37
        $set = GetOAISetBySpec($token->{'set'});
38
    }
39
    my $max = $repository->{koha_max_count};
40
    my $sql = "
41
        (SELECT biblioitems.biblionumber, biblioitems.timestamp
42
        FROM biblioitems
43
    ";
44
    $sql .= " JOIN oai_sets_biblios ON biblioitems.biblionumber = oai_sets_biblios.biblionumber " if defined $set;
45
    $sql .= " WHERE timestamp >= ? AND timestamp <= ? ";
46
    $sql .= " AND oai_sets_biblios.set_id = ? " if defined $set;
47
    $sql .= ") UNION
48
        (SELECT deletedbiblio.biblionumber, timestamp FROM deletedbiblio";
49
    $sql .= " JOIN oai_sets_biblios ON deletedbiblio.biblionumber = oai_sets_biblios.biblionumber " if defined $set;
50
    $sql .= " WHERE DATE(timestamp) >= ? AND DATE(timestamp) <= ? ";
51
    $sql .= " AND oai_sets_biblios.set_id = ? " if defined $set;
52
53
    $sql .= ") ORDER BY biblionumber
54
        LIMIT " . ($max+1) . "
55
        OFFSET $token->{offset}
56
    ";
57
    my $sth = $dbh->prepare( $sql );
58
    my @bind_params = ($token->{'from_arg'}, $token->{'until_arg'});
59
    push @bind_params, $set->{'id'} if defined $set;
60
    push @bind_params, ($token->{'from'}, $token->{'until'});
61
    push @bind_params, $set->{'id'} if defined $set;
62
    $sth->execute( @bind_params );
63
64
    my $count = 0;
65
    while ( my ($biblionumber, $timestamp) = $sth->fetchrow ) {
66
        $count++;
67
        if ( $count > $max ) {
68
            $self->resumptionToken(
69
                new Koha::OAI::Server::ResumptionToken(
70
                    metadataPrefix  => $token->{metadata_prefix},
71
                    from            => $token->{from},
72
                    until           => $token->{until},
73
                    offset          => $token->{offset} + $max,
74
                    set             => $token->{set}
75
                )
76
            );
77
            last;
78
        }
79
        $timestamp =~ s/ /T/, $timestamp .= 'Z';
80
        $self->identifier( new HTTP::OAI::Header(
81
            identifier => $repository->{ koha_identifier} . ':' . $biblionumber,
82
            datestamp  => $timestamp,
83
        ) );
84
    }
85
32
86
    # Return error if no results
33
    # Return error if no results
87
    unless ($count) {
34
    unless ($count) {
(-)a/Koha/OAI/Server/ListMetadataFormats.pm (-1 / +6 lines)
Lines 1-5 Link Here
1
# Copyright Tamil s.a.r.l. 2008-2015
1
# Copyright Tamil s.a.r.l. 2008-2015
2
# Copyright Biblibre 2008-2015
2
# Copyright Biblibre 2008-2015
3
# Copyright The National Library of Finland, University of Helsinki 2016
3
#
4
#
4
# This file is part of Koha.
5
# This file is part of Koha.
5
#
6
#
Lines 23-29 use HTTP::OAI; Link Here
23
24
24
use base ("HTTP::OAI::ListMetadataFormats");
25
use base ("HTTP::OAI::ListMetadataFormats");
25
26
26
27
sub new {
27
sub new {
28
    my ($class, $repository) = @_;
28
    my ($class, $repository) = @_;
29
29
Lines 45-50 sub new { Link Here
45
            metadataNamespace => 'http://www.openarchives.org/OAI/2.0/oai_dc/'
45
            metadataNamespace => 'http://www.openarchives.org/OAI/2.0/oai_dc/'
46
        ) );
46
        ) );
47
        $self->metadataFormat( HTTP::OAI::MetadataFormat->new(
47
        $self->metadataFormat( HTTP::OAI::MetadataFormat->new(
48
            metadataPrefix    => 'marc21',
49
            schema            => 'http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd',
50
            metadataNamespace => 'http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim'
51
        ) );
52
        $self->metadataFormat( HTTP::OAI::MetadataFormat->new(
48
            metadataPrefix    => 'marcxml',
53
            metadataPrefix    => 'marcxml',
49
            schema            => 'http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd',
54
            schema            => 'http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd',
50
            metadataNamespace => 'http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim'
55
            metadataNamespace => 'http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim'
(-)a/Koha/OAI/Server/ListRecords.pm (-73 / +3 lines)
Lines 1-5 Link Here
1
# Copyright Tamil s.a.r.l. 2008-2015
1
# Copyright Tamil s.a.r.l. 2008-2015
2
# Copyright Biblibre 2008-2015
2
# Copyright Biblibre 2008-2015
3
# Copyright The National Library of Finland, University of Helsinki 2016
3
#
4
#
4
# This file is part of Koha.
5
# This file is part of Koha.
5
#
6
#
Lines 19-104 Link Here
19
package Koha::OAI::Server::ListRecords;
20
package Koha::OAI::Server::ListRecords;
20
21
21
use Modern::Perl;
22
use Modern::Perl;
22
use C4::Biblio;
23
use HTTP::OAI;
24
use Koha::OAI::Server::ResumptionToken;
25
use Koha::OAI::Server::Record;
26
use Koha::OAI::Server::DeletedRecord;
27
use C4::OAI::Sets;
28
use MARC::File::XML;
29
30
use base ("HTTP::OAI::ListRecords");
31
23
24
use base qw(HTTP::OAI::ListRecords Koha::OAI::Server::ListBase);
32
25
33
sub new {
26
sub new {
34
    my ($class, $repository, %args) = @_;
27
    my ($class, $repository, %args) = @_;
35
28
36
    my $self = HTTP::OAI::ListRecords->new(%args);
29
    my $self = HTTP::OAI::ListRecords->new(%args);
37
30
38
    my $token = new Koha::OAI::Server::ResumptionToken( %args );
31
    my $count = $class->GetRecords($self, $repository, 1, %args);
39
    my $dbh = C4::Context->dbh;
40
    my $set;
41
    if(defined $token->{'set'}) {
42
        $set = GetOAISetBySpec($token->{'set'});
43
    }
44
    my $max = $repository->{koha_max_count};
45
    my $sql = "
46
        (SELECT biblioitems.biblionumber, biblioitems.timestamp, marcxml
47
        FROM biblioitems
48
    ";
49
    $sql .= " JOIN oai_sets_biblios ON biblioitems.biblionumber = oai_sets_biblios.biblionumber " if defined $set;
50
    $sql .= " WHERE timestamp >= ? AND timestamp <= ? ";
51
    $sql .= " AND oai_sets_biblios.set_id = ? " if defined $set;
52
    $sql .= ") UNION
53
        (SELECT deletedbiblio.biblionumber, null as marcxml, timestamp FROM deletedbiblio";
54
    $sql .= " JOIN oai_sets_biblios ON deletedbiblio.biblionumber = oai_sets_biblios.biblionumber " if defined $set;
55
    $sql .= " WHERE DATE(timestamp) >= ? AND DATE(timestamp) <= ? ";
56
    $sql .= " AND oai_sets_biblios.set_id = ? " if defined $set;
57
58
    $sql .= ") ORDER BY biblionumber
59
        LIMIT " . ($max + 1) . "
60
        OFFSET $token->{offset}
61
    ";
62
    my $sth = $dbh->prepare( $sql );
63
    my @bind_params = ($token->{'from_arg'}, $token->{'until_arg'});
64
    push @bind_params, $set->{'id'} if defined $set;
65
    push @bind_params, ($token->{'from'}, $token->{'until'});
66
    push @bind_params, $set->{'id'} if defined $set;
67
    $sth->execute( @bind_params );
68
69
    my $count = 0;
70
    my $format = $args{metadataPrefix} || $token->{metadata_prefix};
71
    while ( my ($biblionumber, $timestamp) = $sth->fetchrow ) {
72
        $count++;
73
        if ( $count > $max ) {
74
            $self->resumptionToken(
75
                new Koha::OAI::Server::ResumptionToken(
76
                    metadataPrefix  => $token->{metadata_prefix},
77
                    from            => $token->{from},
78
                    until           => $token->{until},
79
                    offset          => $token->{offset} + $max,
80
                    set             => $token->{set}
81
                )
82
            );
83
            last;
84
        }
85
        my $marcxml = $repository->get_biblio_marcxml($biblionumber, $format);
86
        my $oai_sets = GetOAISetsBiblio($biblionumber);
87
        my @setSpecs;
88
        foreach (@$oai_sets) {
89
            push @setSpecs, $_->{spec};
90
        }
91
        if ($marcxml) {
92
          $self->record( Koha::OAI::Server::Record->new(
93
              $repository, $marcxml, $timestamp, \@setSpecs,
94
              identifier      => $repository->{ koha_identifier } . ':' . $biblionumber,
95
              metadataPrefix  => $token->{metadata_prefix}
96
          ) );
97
        } else {
98
          $self->record( Koha::OAI::Server::DeletedRecord->new(
99
          $timestamp, \@setSpecs, identifier => $repository->{ koha_identifier } . ':' . $biblionumber ) );
100
        }
101
    }
102
32
103
    # Return error if no results
33
    # Return error if no results
104
    unless ($count) {
34
    unless ($count) {
(-)a/Koha/OAI/Server/Record.pm (-1 / +1 lines)
Lines 43-49 sub new { Link Here
43
    my $parser = XML::LibXML->new();
43
    my $parser = XML::LibXML->new();
44
    my $record_dom = $parser->parse_string( $marcxml );
44
    my $record_dom = $parser->parse_string( $marcxml );
45
    my $format =  $args{metadataPrefix};
45
    my $format =  $args{metadataPrefix};
46
    if ( $format ne 'marcxml' ) {
46
    if ( $format ne 'marc21' && $format ne 'marcxml' ) {
47
        my %args = (
47
        my %args = (
48
            OPACBaseURL => "'" . C4::Context->preference('OPACBaseURL') . "'"
48
            OPACBaseURL => "'" . C4::Context->preference('OPACBaseURL') . "'"
49
        );
49
        );
(-)a/Koha/OAI/Server/Repository.pm (-3 / +24 lines)
Lines 1-5 Link Here
1
# Copyright Tamil s.a.r.l. 2008-2015
1
# Copyright Tamil s.a.r.l. 2008-2015
2
# Copyright Biblibre 2008-2015
2
# Copyright Biblibre 2008-2015
3
# Copyright The National Library of Finland, University of Helsinki 2016
3
#
4
#
4
# This file is part of Koha.
5
# This file is part of Koha.
5
#
6
#
Lines 77-82 mode. A configuration file koha-oai.conf can look like that: Link Here
77
      metadataNamespace: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs
78
      metadataNamespace: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs
78
      schema: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs.xsd
79
      schema: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs.xsd
79
      xsl_file: /usr/local/koha/xslt/vs.xsl
80
      xsl_file: /usr/local/koha/xslt/vs.xsl
81
    marc21:
82
      metadataPrefix: marc21
83
      metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
84
      schema: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
85
      include_items: 1
80
    marcxml:
86
    marcxml:
81
      metadataPrefix: marxml
87
      metadataPrefix: marxml
82
      metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
88
      metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
Lines 88-94 mode. A configuration file koha-oai.conf can look like that: Link Here
88
      schema: http://www.openarchives.org/OAI/2.0/oai_dc.xsd
94
      schema: http://www.openarchives.org/OAI/2.0/oai_dc.xsd
89
      xsl_file: /usr/local/koha/koha-tmpl/intranet-tmpl/xslt/UNIMARCslim2OAIDC.xsl
95
      xsl_file: /usr/local/koha/koha-tmpl/intranet-tmpl/xslt/UNIMARCslim2OAIDC.xsl
90
96
91
Note de 'include_items' parameter which is the only mean to return item-level info.
97
Note the 'include_items' parameter which is the only mean to return item-level info.
92
98
93
=cut
99
=cut
94
100
Lines 99-105 sub new { Link Here
99
105
100
    $self->{ koha_identifier      } = C4::Context->preference("OAI-PMH:archiveID");
106
    $self->{ koha_identifier      } = C4::Context->preference("OAI-PMH:archiveID");
101
    $self->{ koha_max_count       } = C4::Context->preference("OAI-PMH:MaxCount");
107
    $self->{ koha_max_count       } = C4::Context->preference("OAI-PMH:MaxCount");
102
    $self->{ koha_metadata_format } = ['oai_dc', 'marcxml'];
108
    $self->{ koha_metadata_format } = ['oai_dc', 'marc21', 'marcxml'];
103
    $self->{ koha_stylesheet      } = { }; # Build when needed
109
    $self->{ koha_stylesheet      } = { }; # Build when needed
104
110
105
    # Load configuration file if defined in OAI-PMH:ConfFile syspref
111
    # Load configuration file if defined in OAI-PMH:ConfFile syspref
Lines 109-118 sub new { Link Here
109
        $self->{ koha_metadata_format } =  \@formats;
115
        $self->{ koha_metadata_format } =  \@formats;
110
    }
116
    }
111
117
118
    # OAI-PMH handles dates in UTC, so do that on the database level to avoid need for
119
    # any conversions
120
    C4::Context->dbh->prepare("SET time_zone='+00:00'")->execute();
121
112
    # Check for grammatical errors in the request
122
    # Check for grammatical errors in the request
113
    my @errs = validate_request( CGI::Vars() );
123
    my @errs = validate_request( CGI::Vars() );
114
124
115
    # Is metadataPrefix supported by the respository?
125
    # Is metadataPrefix supported by the repository?
116
    my $mdp = param('metadataPrefix') || '';
126
    my $mdp = param('metadataPrefix') || '';
117
    if ( $mdp && !grep { $_ eq $mdp } @{$self->{ koha_metadata_format }} ) {
127
    if ( $mdp && !grep { $_ eq $mdp } @{$self->{ koha_metadata_format }} ) {
118
        push @errs, new HTTP::OAI::Error(
128
        push @errs, new HTTP::OAI::Error(
Lines 166-171 sub stylesheet { Link Here
166
                         '/prog/en/xslt/' .
176
                         '/prog/en/xslt/' .
167
                         C4::Context->preference('marcflavour') .
177
                         C4::Context->preference('marcflavour') .
168
                         'slim2OAIDC.xsl' );
178
                         'slim2OAIDC.xsl' );
179
        $xsl_file || die( "No stylesheet found for $format" );
169
        my $parser = XML::LibXML->new();
180
        my $parser = XML::LibXML->new();
170
        my $xslt = XML::LibXSLT->new();
181
        my $xslt = XML::LibXSLT->new();
171
        my $style_doc = $parser->parse_file( $xsl_file );
182
        my $style_doc = $parser->parse_file( $xsl_file );
Lines 176-179 sub stylesheet { Link Here
176
    return $stylesheet;
187
    return $stylesheet;
177
}
188
}
178
189
190
191
sub items_included {
192
    my ( $self, $format ) = @_;
193
194
    if ( my $conf = $self->{ conf } ) {
195
        return $conf->{ format }->{ $format }->{ include_items };
196
    }
197
    return 0;
198
}
199
179
1;
200
1;
(-)a/Koha/OAI/Server/ResumptionToken.pm (-4 / +9 lines)
Lines 1-5 Link Here
1
# Copyright Tamil s.a.r.l. 2008-2015
1
# Copyright Tamil s.a.r.l. 2008-2015
2
# Copyright Biblibre 2008-2015
2
# Copyright Biblibre 2008-2015
3
# Copyright The National Library of Finland, University of Helsinki 2016
3
#
4
#
4
# This file is part of Koha.
5
# This file is part of Koha.
5
#
6
#
Lines 31-46 use base ("HTTP::OAI::ResumptionToken"); Link Here
31
# - from
32
# - from
32
# - until
33
# - until
33
# - offset
34
# - offset
35
# - deleted
34
36
37
sub deleted { shift->_elem('deleted',@_) }
35
38
36
sub new {
39
sub new {
37
    my ($class, %args) = @_;
40
    my ($class, %args) = @_;
38
41
39
    my $self = $class->SUPER::new(%args);
42
    my $self = $class->SUPER::new(%args);
40
43
41
    my ($metadata_prefix, $offset, $from, $until, $set);
44
    my ($metadata_prefix, $offset, $from, $until, $set, $deleted);
42
    if ( $args{ resumptionToken } ) {
45
    if ( $args{ resumptionToken } ) {
43
        ($metadata_prefix, $offset, $from, $until, $set)
46
        ($metadata_prefix, $offset, $from, $until, $set, $deleted)
44
            = split( '/', $args{resumptionToken} );
47
            = split( '/', $args{resumptionToken} );
45
    }
48
    }
46
    else {
49
    else {
Lines 55-61 sub new { Link Here
55
        $from .= 'T00:00:00Z' if length($from) == 10;
58
        $from .= 'T00:00:00Z' if length($from) == 10;
56
        $until .= 'T23:59:59Z' if length($until) == 10;
59
        $until .= 'T23:59:59Z' if length($until) == 10;
57
        $offset = $args{ offset } || 0;
60
        $offset = $args{ offset } || 0;
58
        $set = $args{set} || '';
61
        $set = $args{ set } || '';
62
        $deleted = defined $args{ deleted } ? $args{ deleted } : 1;
59
    }
63
    }
60
64
61
    $self->{ metadata_prefix } = $metadata_prefix;
65
    $self->{ metadata_prefix } = $metadata_prefix;
Lines 65-73 sub new { Link Here
65
    $self->{ set             } = $set;
69
    $self->{ set             } = $set;
66
    $self->{ from_arg        } = _strip_UTC_designators($from);
70
    $self->{ from_arg        } = _strip_UTC_designators($from);
67
    $self->{ until_arg       } = _strip_UTC_designators($until);
71
    $self->{ until_arg       } = _strip_UTC_designators($until);
72
    $self->{ deleted         } = $deleted;
68
73
69
    $self->resumptionToken(
74
    $self->resumptionToken(
70
        join( '/', $metadata_prefix, $offset, $from, $until, $set ) );
75
        join( '/', $metadata_prefix, $offset, $from, $until, $set, $deleted ) );
71
    $self->cursor( $offset );
76
    $self->cursor( $offset );
72
77
73
    return $self;
78
    return $self;
(-)a/installer/data/mysql/atomicupdate/Bug15108-OAI-PMH_provider_improvements.pl (+34 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use C4::Context;
21
use Koha::AtomicUpdater;
22
23
my $dbh = C4::Context->dbh();
24
my $atomicUpdater = Koha::AtomicUpdater->new();
25
26
unless($atomicUpdater->find('Bug15108')) {
27
28
    $dbh->do("ALTER TABLE biblioitems ADD KEY `timestamp` (`timestamp`);");
29
    $dbh->do("ALTER TABLE deletedbiblioitems ADD KEY `timestamp` (`timestamp`);");
30
    $dbh->do("ALTER TABLE items ADD KEY `timestamp` (`timestamp`);");
31
    $dbh->do("ALTER TABLE deleteditems ADD KEY `timestamp` (`timestamp`);");
32
33
    print "Upgrade done (Bug 15108 - OAI-PMH provider improvements)\n";
34
}
(-)a/installer/data/mysql/kohastructure.sql (-11 / +14 lines)
Lines 201-206 CREATE TABLE `biblioitems` ( -- information related to bibliographic records in Link Here
201
  KEY `isbn` (`isbn`(255)),
201
  KEY `isbn` (`isbn`(255)),
202
  KEY `issn` (`issn`(255)),
202
  KEY `issn` (`issn`(255)),
203
  KEY `publishercode` (`publishercode`),
203
  KEY `publishercode` (`publishercode`),
204
  KEY `timestamp` (`timestamp`),
204
  CONSTRAINT `biblioitems_ibfk_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE
205
  CONSTRAINT `biblioitems_ibfk_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE
205
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
206
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
206
207
Lines 553-559 CREATE TABLE `deletedbiblioitems` ( -- information about bibliographic records t Link Here
553
  KEY `bibnoidx` (`biblionumber`),
554
  KEY `bibnoidx` (`biblionumber`),
554
  KEY `itemtype_idx` (`itemtype`),
555
  KEY `itemtype_idx` (`itemtype`),
555
  KEY `isbn` (`isbn`(255)),
556
  KEY `isbn` (`isbn`(255)),
556
  KEY `publishercode` (`publishercode`)
557
  KEY `publishercode` (`publishercode`),
558
  KEY `timestamp` (`timestamp`)
557
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
559
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
558
560
559
--
561
--
Lines 694-700 CREATE TABLE `deleteditems` ( Link Here
694
  KEY `delitembibnoidx` (`biblionumber`),
696
  KEY `delitembibnoidx` (`biblionumber`),
695
  KEY `delhomebranch` (`homebranch`),
697
  KEY `delhomebranch` (`homebranch`),
696
  KEY `delholdingbranch` (`holdingbranch`),
698
  KEY `delholdingbranch` (`holdingbranch`),
697
  KEY `itype_idx` (`itype`)
699
  KEY `itype_idx` (`itype`),
700
  KEY `timestamp` (`timestamp`)
698
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
701
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
699
702
700
--
703
--
Lines 899-905 CREATE TABLE `refund_lost_item_fee_rules` ( -- refund lost item fee rules tbale Link Here
899
--
902
--
900
903
901
DROP TABLE IF EXISTS `items`;
904
DROP TABLE IF EXISTS `items`;
902
CREATE TABLE `items` ( -- holdings/item information 
905
CREATE TABLE `items` ( -- holdings/item information
903
  `itemnumber` int(11) NOT NULL auto_increment, -- primary key and unique identifier added by Koha
906
  `itemnumber` int(11) NOT NULL auto_increment, -- primary key and unique identifier added by Koha
904
  `biblionumber` int(11) NOT NULL default 0, -- foreign key from biblio table used to link this item to the right bib record
907
  `biblionumber` int(11) NOT NULL default 0, -- foreign key from biblio table used to link this item to the right bib record
905
  `biblioitemnumber` int(11) NOT NULL default 0, -- foreign key from the biblioitems table to link to item to additional information
908
  `biblioitemnumber` int(11) NOT NULL default 0, -- foreign key from the biblioitems table to link to item to additional information
Lines 955-960 CREATE TABLE `items` ( -- holdings/item information Link Here
955
  KEY `items_location` (`location`),
958
  KEY `items_location` (`location`),
956
  KEY `items_ccode` (`ccode`),
959
  KEY `items_ccode` (`ccode`),
957
  KEY `itype_idx` (`itype`),
960
  KEY `itype_idx` (`itype`),
961
  KEY `timestamp` (`timestamp`),
958
  CONSTRAINT `items_ibfk_1` FOREIGN KEY (`biblioitemnumber`) REFERENCES `biblioitems` (`biblioitemnumber`) ON DELETE CASCADE ON UPDATE CASCADE,
962
  CONSTRAINT `items_ibfk_1` FOREIGN KEY (`biblioitemnumber`) REFERENCES `biblioitems` (`biblioitemnumber`) ON DELETE CASCADE ON UPDATE CASCADE,
959
  CONSTRAINT `items_ibfk_2` FOREIGN KEY (`homebranch`) REFERENCES `branches` (`branchcode`) ON UPDATE CASCADE,
963
  CONSTRAINT `items_ibfk_2` FOREIGN KEY (`homebranch`) REFERENCES `branches` (`branchcode`) ON UPDATE CASCADE,
960
  CONSTRAINT `items_ibfk_3` FOREIGN KEY (`holdingbranch`) REFERENCES `branches` (`branchcode`) ON UPDATE CASCADE,
964
  CONSTRAINT `items_ibfk_3` FOREIGN KEY (`holdingbranch`) REFERENCES `branches` (`branchcode`) ON UPDATE CASCADE,
Lines 2236-2242 CREATE TABLE `userflags` ( Link Here
2236
--
2240
--
2237
2241
2238
DROP TABLE IF EXISTS `virtualshelves`;
2242
DROP TABLE IF EXISTS `virtualshelves`;
2239
CREATE TABLE `virtualshelves` ( -- information about lists (or virtual shelves) 
2243
CREATE TABLE `virtualshelves` ( -- information about lists (or virtual shelves)
2240
  `shelfnumber` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha
2244
  `shelfnumber` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha
2241
  `shelfname` varchar(255) default NULL, -- name of the list
2245
  `shelfname` varchar(255) default NULL, -- name of the list
2242
  `owner` int default NULL, -- foreign key linking to the borrowers table (using borrowernumber) for the creator of this list (changed from varchar(80) to int)
2246
  `owner` int default NULL, -- foreign key linking to the borrowers table (using borrowernumber) for the creator of this list (changed from varchar(80) to int)
Lines 2431-2442 CREATE TABLE `permissions` ( Link Here
2431
2435
2432
DROP TABLE IF EXISTS `serialitems`;
2436
DROP TABLE IF EXISTS `serialitems`;
2433
CREATE TABLE `serialitems` (
2437
CREATE TABLE `serialitems` (
2434
	`itemnumber` int(11) NOT NULL,
2438
  `itemnumber` int(11) NOT NULL,
2435
	`serialid` int(11) NOT NULL,
2439
  `serialid` int(11) NOT NULL,
2436
	UNIQUE KEY `serialitemsidx` (`itemnumber`),
2440
  UNIQUE KEY `serialitemsidx` (`itemnumber`),
2437
	KEY `serialitems_sfk_1` (`serialid`),
2441
  KEY `serialitems_sfk_1` (`serialid`),
2438
	CONSTRAINT `serialitems_sfk_1` FOREIGN KEY (`serialid`) REFERENCES `serial` (`serialid`) ON DELETE CASCADE ON UPDATE CASCADE,
2442
  CONSTRAINT `serialitems_sfk_1` FOREIGN KEY (`serialid`) REFERENCES `serial` (`serialid`) ON DELETE CASCADE ON UPDATE CASCADE,
2439
	CONSTRAINT `serialitems_sfk_2` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE
2443
  CONSTRAINT `serialitems_sfk_2` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE
2440
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2444
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2441
2445
2442
--
2446
--
2443
- 

Return to bug 15108