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

(-)a/C4/OAI/Sets.pm (+485 lines)
Line 0 Link Here
1
package C4::OAI::Sets;
2
3
# Copyright 2011 BibLibre
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 2 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
=head1 NAME
21
22
C4::OAI::Sets - OAI Sets management functions
23
24
=head1 DESCRIPTION
25
26
C4::OAI::Sets contains functions for managing storage and editing of OAI Sets.
27
28
OAI Set description can be found L<here|http://www.openarchives.org/OAI/openarchivesprotocol.html#Set>
29
30
=cut
31
32
use Modern::Perl;
33
use C4::Context;
34
35
use vars qw(@ISA @EXPORT);
36
37
BEGIN {
38
    require Exporter;
39
    @ISA = qw(Exporter);
40
    @EXPORT = qw(
41
        &GetOAISets &GetOAISet &GetOAISetBySpec &ModOAISet &DelOAISet &AddOAISet
42
        &GetOAISetsMappings &GetOAISetMappings &ModOAISetMappings
43
        &GetOAISetsBiblio &ModOAISetsBiblios
44
    );
45
}
46
47
=head1 FUNCTIONS
48
49
=head2 GetOAISets
50
51
    $oai_sets = GetOAISets;
52
53
GetOAISets return a array reference of hash references describing the sets.
54
The hash references looks like this:
55
56
    {
57
        'name'         => 'set name',
58
        'spec'         => 'set spec',
59
        'descriptions' => [
60
            'description 1',
61
            'description 2',
62
            ...
63
        ]
64
    }
65
66
=cut
67
68
sub GetOAISets {
69
    my $dbh = C4::Context->dbh;
70
    my $query = qq{
71
        SELECT * FROM oai_sets
72
    };
73
    my $sth = $dbh->prepare($query);
74
    $sth->execute;
75
    my $results = $sth->fetchall_arrayref({});
76
77
    $query = qq{
78
        SELECT description
79
        FROM oai_sets_descriptions
80
        WHERE set_id = ?
81
    };
82
    $sth = $dbh->prepare($query);
83
    foreach my $set (@$results) {
84
        $sth->execute($set->{'id'});
85
        my $desc = $sth->fetchall_arrayref({});
86
        foreach (@$desc) {
87
            push @{$set->{'descriptions'}}, $_->{'description'};
88
        }
89
    }
90
91
    return $results;
92
}
93
94
=head2 GetOAISet
95
96
    $set = GetOAISet($set_id);
97
98
GetOAISet returns a hash reference describing the set with the given set_id.
99
100
See GetOAISets to see what the hash looks like.
101
102
=cut
103
104
sub GetOAISet {
105
    my ($set_id) = @_;
106
107
    return unless $set_id;
108
109
    my $dbh = C4::Context->dbh;
110
    my $query = qq{
111
        SELECT *
112
        FROM oai_sets
113
        WHERE id = ?
114
    };
115
    my $sth = $dbh->prepare($query);
116
    $sth->execute($set_id);
117
    my $set = $sth->fetchrow_hashref;
118
119
    $query = qq{
120
        SELECT description
121
        FROM oai_sets_descriptions
122
        WHERE set_id = ?
123
    };
124
    $sth = $dbh->prepare($query);
125
    $sth->execute($set->{'id'});
126
    my $desc = $sth->fetchall_arrayref({});
127
    foreach (@$desc) {
128
        push @{$set->{'descriptions'}}, $_->{'description'};
129
    }
130
131
    return $set;
132
}
133
134
=head2 GetOAISetBySpec
135
136
    my $set = GetOAISetBySpec($setSpec);
137
138
Returns a hash describing the set whose spec is $setSpec
139
140
=cut
141
142
sub GetOAISetBySpec {
143
    my $setSpec = shift;
144
145
    return unless defined $setSpec;
146
147
    my $dbh = C4::Context->dbh;
148
    my $query = qq{
149
        SELECT *
150
        FROM oai_sets
151
        WHERE spec = ?
152
        LIMIT 1
153
    };
154
    my $sth = $dbh->prepare($query);
155
    $sth->execute($setSpec);
156
157
    return $sth->fetchrow_hashref;
158
}
159
160
=head2 ModOAISet
161
162
    my $set = {
163
        'id' => $set_id,                 # mandatory
164
        'spec' => $spec,                 # mandatory
165
        'name' => $name,                 # mandatory
166
        'descriptions => \@descriptions, # optional, [] to remove descriptions
167
    };
168
    ModOAISet($set);
169
170
ModOAISet modify a set in the database.
171
172
=cut
173
174
sub ModOAISet {
175
    my ($set) = @_;
176
177
    return unless($set && $set->{'spec'} && $set->{'name'});
178
179
    if(!defined $set->{'id'}) {
180
        warn "Set ID not defined, can't modify the set";
181
        return;
182
    }
183
184
    my $dbh = C4::Context->dbh;
185
    my $query = qq{
186
        UPDATE oai_sets
187
        SET spec = ?,
188
            name = ?
189
        WHERE id = ?
190
    };
191
    my $sth = $dbh->prepare($query);
192
    $sth->execute($set->{'spec'}, $set->{'name'}, $set->{'id'});
193
194
    if($set->{'descriptions'}) {
195
        $query = qq{
196
            DELETE FROM oai_sets_descriptions
197
            WHERE set_id = ?
198
        };
199
        $sth = $dbh->prepare($query);
200
        $sth->execute($set->{'id'});
201
202
        if(scalar @{$set->{'descriptions'}} > 0) {
203
            $query = qq{
204
                INSERT INTO oai_sets_descriptions (set_id, description)
205
                VALUES (?,?)
206
            };
207
            $sth = $dbh->prepare($query);
208
            foreach (@{ $set->{'descriptions'} }) {
209
                $sth->execute($set->{'id'}, $_) if $_;
210
            }
211
        }
212
    }
213
}
214
215
=head2 DelOAISet
216
217
    DelOAISet($set_id);
218
219
DelOAISet remove the set with the given set_id
220
221
=cut
222
223
sub DelOAISet {
224
    my ($set_id) = @_;
225
226
    return unless $set_id;
227
228
    my $dbh = C4::Context->dbh;
229
    my $query = qq{
230
        DELETE oai_sets, oai_sets_descriptions, oai_sets_mappings
231
        FROM oai_sets
232
          LEFT JOIN oai_sets_descriptions ON oai_sets_descriptions.set_id = oai_sets.id
233
          LEFT JOIN oai_sets_mappings ON oai_sets_mappings.set_id = oai_sets.id
234
        WHERE oai_sets.id = ?
235
    };
236
    my $sth = $dbh->prepare($query);
237
    $sth->execute($set_id);
238
}
239
240
=head2 AddOAISet
241
242
    my $set = {
243
        'id' => $set_id,                 # mandatory
244
        'spec' => $spec,                 # mandatory
245
        'name' => $name,                 # mandatory
246
        'descriptions => \@descriptions, # optional
247
    };
248
    my $set_id = AddOAISet($set);
249
250
AddOAISet adds a new set and returns its id, or undef if something went wrong.
251
252
=cut
253
254
sub AddOAISet {
255
    my ($set) = @_;
256
257
    return unless($set && $set->{'spec'} && $set->{'name'});
258
259
    my $set_id;
260
    my $dbh = C4::Context->dbh;
261
    my $query = qq{
262
        INSERT INTO oai_sets (spec, name)
263
        VALUES (?,?)
264
    };
265
    my $sth = $dbh->prepare($query);
266
    if( $sth->execute($set->{'spec'}, $set->{'name'}) ) {
267
        $set_id = $dbh->last_insert_id(undef, undef, 'oai_sets', undef);
268
        if($set->{'descriptions'}) {
269
            $query = qq{
270
                INSERT INTO oai_sets_descriptions (set_id, description)
271
                VALUES (?,?)
272
            };
273
            $sth = $dbh->prepare($query);
274
            foreach( @{ $set->{'descriptions'} } ) {
275
                $sth->execute($set_id, $_) if $_;
276
            }
277
        }
278
    } else {
279
        warn "AddOAISet failed";
280
    }
281
282
    return $set_id;
283
}
284
285
=head2 GetOAISetsMappings
286
287
    my $mappings = GetOAISetsMappings;
288
289
GetOAISetsMappings returns mappings for all OAI Sets.
290
291
Mappings define how biblios are categorized in sets.
292
A mapping is defined by three properties:
293
294
    {
295
        marcfield => 'XXX',     # the MARC field to check
296
        marcsubfield => 'Y',    # the MARC subfield to check
297
        marcvalue => 'zzzz',    # the value to check
298
    }
299
300
If defined in a set mapping, a biblio which have at least one 'Y' subfield of
301
one 'XXX' field equal to 'zzzz' will belong to this set.
302
If multiple mappings are defined in a set, the biblio will belong to this set
303
if at least one condition is matched.
304
305
GetOAISetsMappings returns a hashref of arrayrefs of hashrefs.
306
The first hashref keys are the sets IDs, so it looks like this:
307
308
    $mappings = {
309
        '1' => [
310
            {
311
                marcfield => 'XXX',
312
                marcsubfield => 'Y',
313
                marcvalue => 'zzzz'
314
            },
315
            {
316
                ...
317
            },
318
            ...
319
        ],
320
        '2' => [...],
321
        ...
322
    };
323
324
=cut
325
326
sub GetOAISetsMappings {
327
    my $dbh = C4::Context->dbh;
328
    my $query = qq{
329
        SELECT * FROM oai_sets_mappings
330
    };
331
    my $sth = $dbh->prepare($query);
332
    $sth->execute;
333
334
    my $mappings = {};
335
    while(my $result = $sth->fetchrow_hashref) {
336
        push @{ $mappings->{$result->{'set_id'}} }, {
337
            marcfield => $result->{'marcfield'},
338
            marcsubfield => $result->{'marcsubfield'},
339
            marcvalue => $result->{'marcvalue'}
340
        };
341
    }
342
343
    return $mappings;
344
}
345
346
=head2 GetOAISetMappings
347
348
    my $set_mappings = GetOAISetMappings($set_id);
349
350
Return mappings for the set with given set_id. It's an arrayref of hashrefs
351
352
=cut
353
354
sub GetOAISetMappings {
355
    my ($set_id) = @_;
356
357
    return unless $set_id;
358
359
    my $dbh = C4::Context->dbh;
360
    my $query = qq{
361
        SELECT *
362
        FROM oai_sets_mappings
363
        WHERE set_id = ?
364
    };
365
    my $sth = $dbh->prepare($query);
366
    $sth->execute($set_id);
367
368
    my @mappings;
369
    while(my $result = $sth->fetchrow_hashref) {
370
        push @mappings, {
371
            marcfield => $result->{'marcfield'},
372
            marcsubfield => $result->{'marcsubfield'},
373
            marcvalue => $result->{'marcvalue'}
374
        };
375
    }
376
377
    return \@mappings;
378
}
379
380
=head2 ModOAISetMappings {
381
382
    my $mappings = [
383
        {
384
            marcfield => 'XXX',
385
            marcsubfield => 'Y',
386
            marcvalue => 'zzzz'
387
        },
388
        ...
389
    ];
390
    ModOAISetMappings($set_id, $mappings);
391
392
ModOAISetMappings modifies mappings of a given set.
393
394
=cut
395
396
sub ModOAISetMappings {
397
    my ($set_id, $mappings) = @_;
398
399
    return unless $set_id;
400
401
    my $dbh = C4::Context->dbh;
402
    my $query = qq{
403
        DELETE FROM oai_sets_mappings
404
        WHERE set_id = ?
405
    };
406
    my $sth = $dbh->prepare($query);
407
    $sth->execute($set_id);
408
409
    if(scalar @$mappings > 0) {
410
        $query = qq{
411
            INSERT INTO oai_sets_mappings (set_id, marcfield, marcsubfield, marcvalue)
412
            VALUES (?,?,?,?)
413
        };
414
        $sth = $dbh->prepare($query);
415
        foreach (@$mappings) {
416
            $sth->execute($set_id, $_->{'marcfield'}, $_->{'marcsubfield'}, $_->{'marcvalue'});
417
        }
418
    }
419
}
420
421
=head2 GetOAISetsBiblio
422
423
    $oai_sets = GetOAISetsBiblio($biblionumber);
424
425
Return the OAI sets where biblio appears.
426
427
Return value is an arrayref of hashref where each element of the array is a set.
428
Keys of hash are id, spec and name
429
430
=cut
431
432
sub GetOAISetsBiblio {
433
    my ($biblionumber) = @_;
434
435
    my $dbh = C4::Context->dbh;
436
    my $query = qq{
437
        SELECT oai_sets.*
438
        FROM oai_sets
439
          LEFT JOIN oai_sets_biblios ON oai_sets_biblios.set_id = oai_sets.id
440
        WHERE biblionumber = ?
441
    };
442
    my $sth = $dbh->prepare($query);
443
444
    $sth->execute($biblionumber);
445
    return $sth->fetchall_arrayref({});
446
}
447
448
=head2 ModOAISetsBiblios
449
450
    my $oai_sets_biblios = {
451
        '1' => [1, 3, 4],   # key is the set_id, and value is an array ref of biblionumbers
452
        '2' => [],
453
        ...
454
    };
455
    ModOAISetsBiblios($oai_sets_biblios);
456
457
ModOAISetsBiblios fill oai_sets_biblios table with given infos.
458
This table is then used in opac/oai.pl.
459
460
=cut
461
462
sub ModOAISetsBiblios {
463
    my $oai_sets_biblios = shift;
464
465
    return unless ref($oai_sets_biblios) eq "HASH";
466
467
    my $dbh = C4::Context->dbh;
468
    my $query = qq{
469
        TRUNCATE TABLE oai_sets_biblios
470
    };
471
    my $sth = $dbh->prepare($query);
472
    $sth->execute;
473
    $query = qq{
474
        INSERT INTO oai_sets_biblios (set_id, biblionumber)
475
        VALUES (?,?)
476
    };
477
    $sth = $dbh->prepare($query);
478
    foreach my $set_id (keys %$oai_sets_biblios) {
479
        foreach my $biblionumber (@{$oai_sets_biblios->{$set_id}}) {
480
            $sth->execute($set_id, $biblionumber);
481
        }
482
    }
483
}
484
485
1;
(-)a/admin/oai_set_mappings.pl (+86 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011 BibLibre SARL
4
# This file is part of Koha.
5
#
6
# Koha is free software; you can redistribute it and/or modify it under the
7
# terms of the GNU General Public License as published by the Free Software
8
# Foundation; either version 2 of the License, or (at your option) any later
9
# version.
10
#
11
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License along
16
# with Koha; if not, write to the Free Software Foundation, Inc.,
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19
=head1 NAME
20
21
oai_set_mappings.pl
22
23
=head1 DESCRIPTION
24
25
Define mappings for a given set.
26
Mappings are conditions that define which biblio is included in which set.
27
A condition is in the form 200$a = 'abc'.
28
Multiple conditions can be defined for a given set. In this case,
29
the OR operator will be applied.
30
31
=cut
32
33
use Modern::Perl;
34
35
use CGI;
36
use C4::Auth;
37
use C4::Output;
38
use C4::OAI::Sets;
39
40
use Data::Dumper;
41
42
my $input = new CGI;
43
my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( {
44
    template_name   => 'admin/oai_set_mappings.tt',
45
    query           => $input,
46
    type            => 'intranet',
47
    authnotrequired => 0,
48
    flagsrequired   => { 'parameters' => '*' },
49
    debug           => 1,
50
} );
51
52
my $id = $input->param('id');
53
my $op = $input->param('op');
54
55
if($op && $op eq "save") {
56
    my @marcfields = $input->param('marcfield');
57
    my @marcsubfields = $input->param('marcsubfield');
58
    my @marcvalues = $input->param('marcvalue');
59
60
    my @mappings;
61
    my $i = 0;
62
    while($i < @marcfields and $i < @marcsubfields and $i < @marcvalues) {
63
        if($marcfields[$i] and $marcsubfields[$i] and $marcvalues[$i]) {
64
            push @mappings, {
65
                marcfield    => $marcfields[$i],
66
                marcsubfield => $marcsubfields[$i],
67
                marcvalue    => $marcvalues[$i]
68
            };
69
        }
70
        $i++;
71
    }
72
    ModOAISetMappings($id, \@mappings);
73
    $template->param(mappings_saved => 1);
74
}
75
76
my $set = GetOAISet($id);
77
my $mappings = GetOAISetMappings($id);
78
79
$template->param(
80
    id => $id,
81
    setName => $set->{'name'},
82
    setSpec => $set->{'spec'},
83
    mappings => $mappings,
84
);
85
86
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/admin/oai_sets.pl (+102 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011 BibLibre SARL
4
# This file is part of Koha.
5
#
6
# Koha is free software; you can redistribute it and/or modify it under the
7
# terms of the GNU General Public License as published by the Free Software
8
# Foundation; either version 2 of the License, or (at your option) any later
9
# version.
10
#
11
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License along
16
# with Koha; if not, write to the Free Software Foundation, Inc.,
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19
=head1 NAME
20
21
oai_sets.pl
22
23
=head1 DESCRIPTION
24
25
Admin page to describe OAI SETs
26
27
=cut
28
29
use Modern::Perl;
30
31
use CGI;
32
use C4::Auth;
33
use C4::Output;
34
use C4::OAI::Sets;
35
36
use Data::Dumper;
37
38
my $input = new CGI;
39
my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( {
40
    template_name   => 'admin/oai_sets.tt',
41
    query           => $input,
42
    type            => 'intranet',
43
    authnotrequired => 0,
44
    flagsrequired   => { 'parameters' => '*' },
45
    debug           => 1,
46
} );
47
48
my $op = $input->param('op');
49
50
if($op && $op eq "new") {
51
    $template->param( op_new => 1 );
52
} elsif($op && $op eq "savenew") {
53
    my $spec = $input->param('spec');
54
    my $name = $input->param('name');
55
    my @descriptions = $input->param('description');
56
    AddOAISet({
57
        spec => $spec,
58
        name => $name,
59
        descriptions => \@descriptions
60
    });
61
} elsif($op && $op eq "mod") {
62
    my $id = $input->param('id');
63
    my $set = GetOAISet($id);
64
    $template->param(
65
        op_mod => 1,
66
        id => $set->{'id'},
67
        spec => $set->{'spec'},
68
        name => $set->{'name'},
69
        descriptions => [ map { {description => $_} } @{ $set->{'descriptions'} } ],
70
    );
71
} elsif($op && $op eq "savemod") {
72
    my $id = $input->param('id');
73
    my $spec = $input->param('spec');
74
    my $name = $input->param('name');
75
    my @descriptions = $input->param('description');
76
    ModOAISet({
77
        id => $id,
78
        spec => $spec,
79
        name => $name,
80
        descriptions => \@descriptions
81
    });
82
} elsif($op && $op eq "del") {
83
    my $id = $input->param('id');
84
    DelOAISet($id);
85
}
86
87
my $OAISets = GetOAISets;
88
my @sets_loop;
89
foreach(@$OAISets) {
90
    push @sets_loop, {
91
        id => $_->{'id'},
92
        spec => $_->{'spec'},
93
        name => $_->{'name'},
94
        descriptions => [ map { {description => $_} } @{ $_->{'descriptions'} } ]
95
    };
96
}
97
98
$template->param(
99
    sets_loop => \@sets_loop,
100
);
101
102
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/installer/data/mysql/atomicupdate/oai_sets.sql (+32 lines)
Line 0 Link Here
1
DROP TABLE IF EXISTS `oai_sets`;
2
CREATE TABLE `oai_sets` (
3
  `id` int(11) NOT NULL auto_increment,
4
  `spec` varchar(80) NOT NULL UNIQUE,
5
  `name` varchar(80) NOT NULL,
6
  PRIMARY KEY (`id`)
7
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
8
9
DROP TABLE IF EXISTS `oai_sets_descriptions`;
10
CREATE TABLE `oai_sets_descriptions` (
11
  `set_id` int(11) NOT NULL,
12
  `description` varchar(255) NOT NULL,
13
  CONSTRAINT `oai_sets_descriptions_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
14
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
15
16
DROP TABLE IF EXISTS `oai_sets_mappings`;
17
CREATE TABLE `oai_sets_mappings` (
18
  `set_id` int(11) NOT NULL,
19
  `marcfield` char(3) NOT NULL,
20
  `marcsubfield` char(1) NOT NULL,
21
  `marcvalue` varchar(80) NOT NULL,
22
  CONSTRAINT `oai_sets_mappings_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
23
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
24
25
DROP TABLE IF EXISTS `oai_sets_biblios`;
26
CREATE TABLE `oai_sets_biblios` (
27
  `biblionumber` int(11) NOT NULL,
28
  `set_id` int(11) NOT NULL,
29
  PRIMARY KEY (`biblionumber`, `set_id`),
30
  CONSTRAINT `oai_sets_biblios_ibfk_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE,
31
  CONSTRAINT `oai_sets_biblios_ibfk_2` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
32
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(-)a/installer/data/mysql/kohastructure.sql (+49 lines)
Lines 1353-1358 CREATE TABLE `nozebra` ( Link Here
1353
  ENGINE=InnoDB DEFAULT CHARSET=utf8;
1353
  ENGINE=InnoDB DEFAULT CHARSET=utf8;
1354
1354
1355
--
1355
--
1356
-- Table structure for table `oai_sets`
1357
--
1358
1359
DROP TABLE IF EXISTS `oai_sets`;
1360
CREATE TABLE `oai_sets` (
1361
  `id` int(11) NOT NULL auto_increment,
1362
  `spec` varchar(80) NOT NULL UNIQUE,
1363
  `name` varchar(80) NOT NULL,
1364
  PRIMARY KEY (`id`)
1365
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1366
1367
--
1368
-- Table structure for table `oai_sets_descriptions`
1369
--
1370
1371
DROP TABLE IF EXISTS `oai_sets_descriptions`;
1372
CREATE TABLE `oai_sets_descriptions` (
1373
  `set_id` int(11) NOT NULL,
1374
  `description` varchar(255) NOT NULL,
1375
  CONSTRAINT `oai_sets_descriptions_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
1376
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1377
1378
--
1379
-- Table structure for table `oai_sets_mappings`
1380
--
1381
1382
DROP TABLE IF EXISTS `oai_sets_mappings`;
1383
CREATE TABLE `oai_sets_mappings` (
1384
  `set_id` int(11) NOT NULL,
1385
  `marcfield` char(3) NOT NULL,
1386
  `marcsubfield` char(1) NOT NULL,
1387
  `marcvalue` varchar(80) NOT NULL,
1388
  CONSTRAINT `oai_sets_mappings_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
1389
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1390
1391
--
1392
-- Table structure for table `oai_sets_biblios`
1393
--
1394
1395
DROP TABLE IF EXISTS `oai_sets_biblios`;
1396
CREATE TABLE `oai_sets_biblios` (
1397
  `biblionumber` int(11) NOT NULL,
1398
  `set_id` int(11) NOT NULL,
1399
  PRIMARY KEY (`biblionumber`, `set_id`),
1400
  CONSTRAINT `oai_sets_biblios_ibfk_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE,
1401
  CONSTRAINT `oai_sets_biblios_ibfk_2` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
1402
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1403
1404
--
1356
-- Table structure for table `old_issues`
1405
-- Table structure for table `old_issues`
1357
--
1406
--
1358
1407
(-)a/installer/data/mysql/updatedatabase.pl (+10 lines)
Lines 4626-4631 if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { Link Here
4626
    SetVersion($DBversion);
4626
    SetVersion($DBversion);
4627
}
4627
}
4628
4628
4629
$DBversion = "XXX";
4630
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
4631
    my $installer = C4::Installer->new();
4632
    my $full_path = C4::Context->config('intranetdir') . "/installer/data/$installer->{dbms}/atomicupdate/oai_sets.sql";
4633
    my $error     = $installer->load_sql($full_path);
4634
    warn $error if $error;
4635
    print "Upgrade to $DBversion done (Add OAI SETs tables)\n";
4636
    SetVersion($DBversion);
4637
}
4638
4629
=head1 FUNCTIONS
4639
=head1 FUNCTIONS
4630
4640
4631
=head2 DropAllForeignKeys($table)
4641
=head2 DropAllForeignKeys($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc (+1 lines)
Lines 43-48 Link Here
43
    <li><a href="/cgi-bin/koha/admin/authtypes.pl">Authority types</a></li>
43
    <li><a href="/cgi-bin/koha/admin/authtypes.pl">Authority types</a></li>
44
    <li><a href="/cgi-bin/koha/admin/classsources.pl">Classification sources</a></li>
44
    <li><a href="/cgi-bin/koha/admin/classsources.pl">Classification sources</a></li>
45
    <li><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></li>
45
    <li><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></li>
46
    <li><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI Sets configuration</a></li>
46
</ul>
47
</ul>
47
48
48
<h5>Acquisition parameters</h5>
49
<h5>Acquisition parameters</h5>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt (+2 lines)
Lines 74-79 Link Here
74
    <dd>Define classification sources (i.e., call number schemes) used by your collection.  Also define filing rules used for sorting call numbers.</dd>
74
    <dd>Define classification sources (i.e., call number schemes) used by your collection.  Also define filing rules used for sorting call numbers.</dd>
75
    <dt><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></dt>
75
    <dt><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></dt>
76
    <dd>Manage rules for automatically matching MARC records during record imports.</dd>
76
    <dd>Manage rules for automatically matching MARC records during record imports.</dd>
77
    <dt><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI Sets Configuration</a></dt>
78
    <dd>Manage OAI Sets</dd>
77
</dl>
79
</dl>
78
80
79
<h3>Acquisition parameters</h3>
81
<h3>Acquisition parameters</h3>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/oai_set_mappings.tt (+103 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Admin &rsaquo; OAI Set Mappings</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript">
5
//<![CDATA[
6
$(document).ready(function() {
7
    // Some JS
8
});
9
10
function newCondition() {
11
    var tr = $('#ORbutton').parents('tr');
12
    var clone = $(tr).clone();
13
    $("#ORbutton").parent('td').replaceWith('<td style="text-align:center">OR</td>');
14
    $(tr).parent('tbody').append(clone);
15
}
16
17
function hideDialogBox() {
18
    $('div.dialog').remove();
19
}
20
21
function returnToSetsPage() {
22
    window.location.href = "/cgi-bin/koha/admin/oai_sets.pl";
23
}
24
//]]>
25
</script>
26
</head>
27
28
<body>
29
[% INCLUDE 'header.inc' %]
30
[% INCLUDE 'cat-search.inc' %]
31
32
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Admin</a> &rsaquo; <a href="/cgi-bin/koha/admin/oai_set_mappings.pl?id=[% id %]">OAI Set Mappings</a></div>
33
34
<div id="doc3" class="yui-t2">
35
36
<div id="bd">
37
  <div id="yui-main">
38
    <div class="yui-b">
39
      [% IF ( mappings_saved ) %]
40
        <div class="dialog">
41
          <p>Mappings have been saved</p>
42
          <p><a href="/cgi-bin/koha/admin/oai_sets.pl">Return to sets management</a></p>
43
        </div>
44
      [% END %]
45
      <h1>Mappings for set '[% setName %]' ([% setSpec %])</h1>
46
      [% UNLESS ( mappings ) %]
47
        <p class="warning">Warning: no mappings defined for this set</p>
48
      [% END %]
49
      <form action="/cgi-bin/koha/admin/oai_set_mappings.pl" method="post" onsubmit="hideDialogBox();">
50
        <table id="mappings">
51
          <thead>
52
            <tr>
53
              <th>Field</th>
54
              <th>Subfield</th>
55
              <th>&nbsp;</th>
56
              <th>Value</th>
57
              <th>&nbsp;</th>
58
            </tr>
59
          </thead>
60
          <tbody>
61
            [% IF ( mappings ) %]
62
              [% FOREACH mapping IN mappings %]
63
                <tr>
64
                  <td><input type="text" name="marcfield" size="3" value="[% mapping.marcfield %]" /></td>
65
                  <td style="text-align:center"><input type="text" name="marcsubfield" size="1" value="[% mapping.marcsubfield %]" /></td>
66
                  <td>is equal to</td>
67
                  <td><input type="text" name="marcvalue" value="[% mapping.marcvalue %]" /></td>
68
                  <td style="text-align:center">
69
                    [% IF ( loop.last ) %]
70
                      <input type="button" id="ORbutton" value="OR" onclick="newCondition()"/>
71
                    [% ELSE %]
72
                      OR
73
                    [% END %]
74
                  </td>
75
                </tr>
76
              [% END %]
77
            [% ELSE %]
78
              <tr>
79
                <td><input type="text" name="marcfield" size="3" /></td>
80
                <td style="text-align:center"><input type="text" name="marcsubfield" size="1" /></td>
81
                <td>is equal to</td>
82
                <td><input type="text" name="marcvalue" /></td>
83
                <td><input type="button" id="ORbutton" value="OR" onclick="newCondition()"/></td>
84
              </tr>
85
            [% END %]
86
          </tbody>
87
        </table>
88
        <p class="hint">Hint: to delete a line, empty at least one of the text fields in this line</p>
89
        <input type="hidden" name="id" value="[% id %]" />
90
        <input type="hidden" name="op" value="save" />
91
        <fieldset class="action">
92
            <input type="submit" value="Save" />
93
            <input type="button" value="Cancel" onclick="returnToSetsPage();" />
94
        </fieldset>
95
      </form>
96
97
    </div>
98
  </div>
99
  <div class="yui-b">
100
    [% INCLUDE 'admin-menu.inc' %]
101
  </div>
102
</div>
103
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/oai_sets.tt (+140 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Admin &rsaquo; OAI Sets</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript">
5
//<![CDATA[
6
function newDescField() {
7
    $("#descriptionlist").append(
8
        '<li>' +
9
        '<textarea style="vertical-align:middle" name="description"></textarea>' +
10
        '<a style="cursor:pointer" onclick="delDescField(this)">&nbsp;&times;</a>' +
11
        '</li>'
12
    );
13
}
14
15
function delDescField(minusButton) {
16
    var li = $(minusButton).parent('li');
17
    $(li).remove();
18
}
19
20
$(document).ready(function() {
21
    // Some JS
22
});
23
//]]>
24
</script>
25
</head>
26
27
<body>
28
[% INCLUDE 'header.inc' %]
29
[% INCLUDE 'cat-search.inc' %]
30
31
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Admin</a> &rsaquo; OAI Sets</div>
32
33
<div id="doc3" class="yui-t2">
34
35
<div id="bd">
36
  <div id="yui-main">
37
    <div class="yui-b">
38
      <h1>OAI Sets Configuration</h1>
39
40
        [% IF op_new %]
41
            <h2>Add a new set</h2>
42
            <form method="post" action="/cgi-bin/koha/admin/oai_sets.pl">
43
                <input type="hidden" name="op" value="savenew" />
44
                <fieldset>
45
                    <label for="spec">setSpec</label>
46
                    <input type="text" id="spec" name="spec" />
47
                    <br />
48
                    <label for="name">setName</label>
49
                    <input type="text" id="name" name="name" />
50
                    <br />
51
                    <label>setDescriptions</label>
52
                    <ul id="descriptionlist">
53
                    </ul>
54
                    <a style="cursor:pointer" onclick='newDescField()'>Add description</a>
55
                </fieldset>
56
                <input type="submit" value="Save" />
57
                <input type="button" value="Cancel" onclick="window.location.href = '/cgi-bin/koha/admin/oai_sets.pl'" />
58
            </form>
59
        [% ELSE %][% IF op_mod %]
60
            <h2>Modify set '[% spec %]'</h2>
61
            <form method="post" action="/cgi-bin/koha/admin/oai_sets.pl">
62
                <input type="hidden" name="op" value="savemod" />
63
                <input type="hidden" name="id" value="[% id %]" />
64
                <fieldset>
65
                    <label for="spec">setSpec</label>
66
                    <input type="text" id="spec" name="spec" value="[% spec %]" />
67
                    <br />
68
                    <label for="name">setName</label>
69
                    <input type="text" id="name" name="name" value="[% name %]" />
70
                    <br />
71
                    <label>setDescriptions</label>
72
                    <ul id="descriptionlist">
73
                        [% FOREACH desc IN descriptions %]
74
                            <li>
75
                                <textarea style="vertical-align:middle" name="description">[% desc.description %]</textarea>
76
                                <a style="cursor:pointer" onclick="delDescField(this)">&nbsp;&times;</a>
77
                            </li>
78
                        [% END %]
79
                    </ul>
80
                    <a style="cursor:pointer" onclick='newDescField()'>Add description</a>
81
                </fieldset>
82
                <input type="submit" value="Save" />
83
                <input type="button" value="Cancel" onclick="window.location.href = '/cgi-bin/koha/admin/oai_sets.pl'" />
84
            </form>
85
        [% END %]
86
        [% END %]
87
88
        <h2>List of sets</h2>
89
        [% UNLESS ( op_new ) %]
90
            <a href="/cgi-bin/koha/admin/oai_sets.pl?op=new">Add a new set</a>
91
        [% END %]
92
        [% IF sets_loop %]
93
            <table>
94
                <thead>
95
                    <tr>
96
                        <th>setSpec</th>
97
                        <th>setName</th>
98
                        <th>setDescriptions</th>
99
                        <th>Action</th>
100
                    </tr>
101
                </thead>
102
                <tbody>
103
                    [% FOREACH set IN sets_loop %]
104
                        <tr>
105
                            <td>[% set.spec %]</td>
106
                            <td>[% set.name %]</td>
107
                            <td>
108
                                [% IF set.descriptions %]
109
                                    <ul>
110
                                        [% FOREACH desc IN set.descriptions %]
111
                                            <li>[% desc.description %]</li>
112
                                        [% END %]
113
                                    </ul>
114
                                [% ELSE %]
115
                                    <em>No descriptions</em>
116
                                [% END %]
117
                            </td>
118
                            <td>
119
                                <a href="/cgi-bin/koha/admin/oai_sets.pl?op=mod&id=[% set.id %]">Modify</a>
120
                                |
121
                                <a href="/cgi-bin/koha/admin/oai_sets.pl?op=del&id=[% setid %]">Delete</a>
122
                                |
123
                                <a href="/cgi-bin/koha/admin/oai_set_mappings.pl?id=[% set.id %]">Define mappings</a>
124
                            </td>
125
                        </tr>
126
                    [% END %]
127
                </tbody>
128
            </table>
129
        [% ELSE %]
130
            <p>There is no set defined.</p>
131
        [% END %]
132
133
134
    </div>
135
  </div>
136
  <div class="yui-b">
137
    [% INCLUDE 'admin-menu.inc' %]
138
  </div>
139
</div>
140
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/xslt/UNIMARCslim2OAIDC.xsl (-5 / +6 lines)
Lines 163-171 Link Here
163
      </dc:identifier>
163
      </dc:identifier>
164
    </xsl:for-each>
164
    </xsl:for-each>
165
    <xsl:for-each select="marc:datafield[@tag=090]">
165
    <xsl:for-each select="marc:datafield[@tag=090]">
166
       <dc:identifier>
166
      <dc:identifier>
167
      <xsl:text>http://opac.mylibrary.org/bib/</xsl:text>
167
        <xsl:value-of select="$OPACBaseURL" />
168
      <xsl:value-of select="marc:subfield[@code='a']"/>
168
        <xsl:text>/bib/</xsl:text>
169
        <xsl:value-of select="marc:subfield[@code='a']"/>
169
      </dc:identifier>
170
      </dc:identifier>
170
    </xsl:for-each>
171
    </xsl:for-each>
171
    <xsl:for-each select="marc:datafield[@tag=995]">
172
    <xsl:for-each select="marc:datafield[@tag=995]">
Lines 175-184 Link Here
175
        <xsl:when test="marc:subfield[@code='c']='MAIN'">Main Branch</xsl:when>
176
        <xsl:when test="marc:subfield[@code='c']='MAIN'">Main Branch</xsl:when>
176
        <xsl:when test="marc:subfield[@code='c']='BIB2'">Library 2</xsl:when>
177
        <xsl:when test="marc:subfield[@code='c']='BIB2'">Library 2</xsl:when>
177
      </xsl:choose>
178
      </xsl:choose>
178
      <xsl:foreach select="marc:subfield[@code='k']">
179
      <xsl:for-each select="marc:subfield[@code='k']">
179
        <xsl:text>:</xsl:text>
180
        <xsl:text>:</xsl:text>
180
        <xsl:value-of select="."/>
181
        <xsl:value-of select="."/>
181
      </xsl:foreach>
182
      </xsl:for-each>
182
      </dc:identifier>
183
      </dc:identifier>
183
    </xsl:for-each>
184
    </xsl:for-each>
184
  </xsl:template>
185
  </xsl:template>
(-)a/misc/migration_tools/build_oai_sets.pl (+106 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Turn on autoflush
4
$| = 1;
5
6
use Modern::Perl;
7
use MARC::Record;
8
use MARC::File::XML;
9
use List::MoreUtils qw/uniq/;
10
11
use C4::Context;
12
use C4::Charset qw/StripNonXmlChars/;
13
use C4::OAI::Sets qw/GetOAISets GetOAISetBySpec GetOAISetsMappings ModOAISetsBiblios GetOAISet/;
14
15
my $debug = $ENV{'DEBUG'};
16
17
my $dbh = C4::Context->dbh;
18
19
# Get OAI sets mappings
20
my $mappings = GetOAISetsMappings;
21
22
# Get all biblionumbers and marcxml
23
print "Retrieving all biblios... ";
24
my $query = qq{
25
    SELECT biblionumber, marcxml
26
    FROM biblioitems
27
};
28
my $sth = $dbh->prepare($query);
29
$sth->execute;
30
my $results = $sth->fetchall_arrayref({});
31
print "Done.\n";
32
33
# Build lists of parents sets
34
my $sets = GetOAISets;
35
my $parentsets;
36
foreach my $set (@$sets) {
37
    my $setSpec = $set->{'spec'};
38
    while($setSpec =~ /^(.+):(.+)$/) {
39
        my $parent = $1;
40
        my $parent_set = GetOAISetBySpec($parent);
41
        if($parent_set) {
42
            push @{ $parentsets->{$set->{'id'}} }, $parent_set->{'id'};
43
            $setSpec = $parent;
44
        } else {
45
            last;
46
        }
47
    }
48
}
49
50
my $num_biblios = scalar @$results;
51
my $i = 1;
52
my $sets_biblios = {};
53
foreach my $res (@$results) {
54
    my $biblionumber = $res->{'biblionumber'};
55
    my $marcxml = $res->{'marcxml'};
56
    if($i % 1000 == 0) {
57
        my $percent = ($i * 100) / $num_biblios;
58
        $percent = sprintf("%.2f", $percent);
59
        say "Progression: $i/$num_biblios ($percent %)";
60
    }
61
    # The following lines are copied from GetMarcBiblio
62
    # We don't call GetMarcBiblio to avoid a sql query to be executed each time
63
    $marcxml = StripNonXmlChars($marcxml);
64
    MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
65
    my $record;
66
    eval {
67
        $record = MARC::Record::new_from_xml($marcxml, "utf8", C4::Context->preference('marcflavour'));
68
    };
69
    if($@) {
70
        warn "(biblio $biblionumber) Error while creating record from marcxml: $@";
71
        next;
72
    }
73
74
    foreach my $set_id (keys %$mappings) {
75
        foreach my $mapping (@{ $mappings->{$set_id} }) {
76
            next if not $mapping;
77
            my $field = $mapping->{'marcfield'};
78
            my $subfield = $mapping->{'marcsubfield'};
79
            my $value = $mapping->{'marcvalue'};
80
81
            my @subfield_values = $record->subfield($field, $subfield);
82
            if(0 < grep /^$value$/, @subfield_values) {
83
                $debug and say "Biblio $biblionumber belong to set $set_id, $field\$$subfield = $value";
84
                push @{ $sets_biblios->{$set_id} }, $biblionumber;
85
                foreach my $parent_set_id ( @{ $parentsets->{$set_id} } ) {
86
                    push @{ $sets_biblios->{$parent_set_id} }, $biblionumber;
87
                }
88
                last;
89
            }
90
        }
91
    }
92
    $i++;
93
}
94
say "Progression: Done.";
95
96
say "Summary:";
97
foreach my $set_id (keys %$sets_biblios) {
98
    $sets_biblios->{$set_id} = [ uniq @{ $sets_biblios->{$set_id} } ];
99
    my $set = GetOAISet($set_id);
100
    my $setSpec = $set->{'spec'};
101
    say "Set '$setSpec': ". scalar(@{$sets_biblios->{$set_id}}) ." biblios";
102
}
103
104
print "Updating database... ";
105
ModOAISetsBiblios($sets_biblios);
106
print "Done.\n";
(-)a/opac/oai.pl (-52 / +182 lines)
Lines 2-8 Link Here
2
2
3
use strict;
3
use strict;
4
use warnings;
4
use warnings;
5
use diagnostics;
6
5
7
use CGI qw/:standard -oldstyle_urls/;
6
use CGI qw/:standard -oldstyle_urls/;
8
use vars qw( $GZIP );
7
use vars qw( $GZIP );
Lines 59-65 package C4::OAI::ResumptionToken; Link Here
59
58
60
use strict;
59
use strict;
61
use warnings;
60
use warnings;
62
use diagnostics;
63
use HTTP::OAI;
61
use HTTP::OAI;
64
62
65
use base ("HTTP::OAI::ResumptionToken");
63
use base ("HTTP::OAI::ResumptionToken");
Lines 70-78 sub new { Link Here
70
68
71
    my $self = $class->SUPER::new(%args);
69
    my $self = $class->SUPER::new(%args);
72
70
73
    my ($metadata_prefix, $offset, $from, $until);
71
    my ($metadata_prefix, $offset, $from, $until, $set);
74
    if ( $args{ resumptionToken } ) {
72
    if ( $args{ resumptionToken } ) {
75
        ($metadata_prefix, $offset, $from, $until)
73
        ($metadata_prefix, $offset, $from, $until, $set)
76
            = split( ':', $args{resumptionToken} );
74
            = split( ':', $args{resumptionToken} );
77
    }
75
    }
78
    else {
76
    else {
Lines 84-98 sub new { Link Here
84
            $until = sprintf( "%.4d-%.2d-%.2d", $year+1900, $mon+1,$mday );
82
            $until = sprintf( "%.4d-%.2d-%.2d", $year+1900, $mon+1,$mday );
85
        }
83
        }
86
        $offset = $args{ offset } || 0;
84
        $offset = $args{ offset } || 0;
85
        $set = $args{set};
87
    }
86
    }
88
87
89
    $self->{ metadata_prefix } = $metadata_prefix;
88
    $self->{ metadata_prefix } = $metadata_prefix;
90
    $self->{ offset          } = $offset;
89
    $self->{ offset          } = $offset;
91
    $self->{ from            } = $from;
90
    $self->{ from            } = $from;
92
    $self->{ until           } = $until;
91
    $self->{ until           } = $until;
92
    $self->{ set             } = $set;
93
93
94
    $self->resumptionToken(
94
    $self->resumptionToken(
95
        join( ':', $metadata_prefix, $offset, $from, $until ) );
95
        join( ':', $metadata_prefix, $offset, $from, $until, $set ) );
96
    $self->cursor( $offset );
96
    $self->cursor( $offset );
97
97
98
    return $self;
98
    return $self;
Lines 106-112 package C4::OAI::Identify; Link Here
106
106
107
use strict;
107
use strict;
108
use warnings;
108
use warnings;
109
use diagnostics;
110
use HTTP::OAI;
109
use HTTP::OAI;
111
use C4::Context;
110
use C4::Context;
112
111
Lines 145-151 package C4::OAI::ListMetadataFormats; Link Here
145
144
146
use strict;
145
use strict;
147
use warnings;
146
use warnings;
148
use diagnostics;
149
use HTTP::OAI;
147
use HTTP::OAI;
150
148
151
use base ("HTTP::OAI::ListMetadataFormats");
149
use base ("HTTP::OAI::ListMetadataFormats");
Lines 188-201 package C4::OAI::Record; Link Here
188
186
189
use strict;
187
use strict;
190
use warnings;
188
use warnings;
191
use diagnostics;
192
use HTTP::OAI;
189
use HTTP::OAI;
193
use HTTP::OAI::Metadata::OAI_DC;
190
use HTTP::OAI::Metadata::OAI_DC;
194
191
195
use base ("HTTP::OAI::Record");
192
use base ("HTTP::OAI::Record");
196
193
197
sub new {
194
sub new {
198
    my ($class, $repository, $marcxml, $timestamp, %args) = @_;
195
    my ($class, $repository, $marcxml, $timestamp, $setSpecs, %args) = @_;
199
196
200
    my $self = $class->SUPER::new(%args);
197
    my $self = $class->SUPER::new(%args);
201
198
Lines 205-215 sub new { Link Here
205
        datestamp   => $timestamp,
202
        datestamp   => $timestamp,
206
    ) );
203
    ) );
207
204
205
    foreach my $setSpec (@$setSpecs) {
206
        $self->header->setSpec($setSpec);
207
    }
208
208
    my $parser = XML::LibXML->new();
209
    my $parser = XML::LibXML->new();
209
    my $record_dom = $parser->parse_string( $marcxml );
210
    my $record_dom = $parser->parse_string( $marcxml );
210
    my $format =  $args{metadataPrefix};
211
    my $format =  $args{metadataPrefix};
211
    if ( $format ne 'marcxml' ) {
212
    if ( $format ne 'marcxml' ) {
212
        $record_dom = $repository->stylesheet($format)->transform( $record_dom );
213
        my %args = (
214
            OPACBaseURL => "'" . C4::Context->preference('OPACBaseURL') . "'"
215
        );
216
        $record_dom = $repository->stylesheet($format)->transform($record_dom, %args);
213
    }
217
    }
214
    $self->metadata( HTTP::OAI::Metadata->new( dom => $record_dom ) );
218
    $self->metadata( HTTP::OAI::Metadata->new( dom => $record_dom ) );
215
219
Lines 224-231 package C4::OAI::GetRecord; Link Here
224
228
225
use strict;
229
use strict;
226
use warnings;
230
use warnings;
227
use diagnostics;
228
use HTTP::OAI;
231
use HTTP::OAI;
232
use C4::OAI::Sets;
229
233
230
use base ("HTTP::OAI::GetRecord");
234
use base ("HTTP::OAI::GetRecord");
231
235
Lines 254-262 sub new { Link Here
254
        );
258
        );
255
    }
259
    }
256
260
261
    my $oai_sets = GetOAISetsBiblio($biblionumber);
262
    my @setSpecs;
263
    foreach (@$oai_sets) {
264
        push @setSpecs, $_->{spec};
265
    }
266
257
    #$self->header( HTTP::OAI::Header->new( identifier  => $args{identifier} ) );
267
    #$self->header( HTTP::OAI::Header->new( identifier  => $args{identifier} ) );
258
    $self->record( C4::OAI::Record->new(
268
    $self->record( C4::OAI::Record->new(
259
        $repository, $marcxml, $timestamp, %args ) );
269
        $repository, $marcxml, $timestamp, \@setSpecs, %args ) );
260
270
261
    return $self;
271
    return $self;
262
}
272
}
Lines 269-276 package C4::OAI::ListIdentifiers; Link Here
269
279
270
use strict;
280
use strict;
271
use warnings;
281
use warnings;
272
use diagnostics;
273
use HTTP::OAI;
282
use HTTP::OAI;
283
use C4::OAI::Sets;
274
284
275
use base ("HTTP::OAI::ListIdentifiers");
285
use base ("HTTP::OAI::ListIdentifiers");
276
286
Lines 282-323 sub new { Link Here
282
292
283
    my $token = new C4::OAI::ResumptionToken( %args );
293
    my $token = new C4::OAI::ResumptionToken( %args );
284
    my $dbh = C4::Context->dbh;
294
    my $dbh = C4::Context->dbh;
285
    my $sql = "SELECT biblionumber, timestamp
295
    my $set;
286
               FROM   biblioitems
296
    if(defined $token->{'set'}) {
287
               WHERE  timestamp >= ? AND timestamp <= ?
297
        $set = GetOAISetBySpec($token->{'set'});
288
               LIMIT  " . $repository->{koha_max_count} . "
298
    }
289
               OFFSET " . $token->{offset};
299
    my $sql = "
300
        SELECT biblioitems.biblionumber, biblioitems.timestamp
301
        FROM biblioitems
302
    ";
303
    $sql .= " JOIN oai_sets_biblios ON biblioitems.biblionumber = oai_sets_biblios.biblionumber " if defined $set;
304
    $sql .= " WHERE DATE(timestamp) >= ? AND DATE(timestamp) <= ? ";
305
    $sql .= " AND oai_sets_biblios.set_id = ? " if defined $set;
306
    $sql .= "
307
        LIMIT $repository->{'koha_max_count'}
308
        OFFSET $token->{'offset'}
309
    ";
290
    my $sth = $dbh->prepare( $sql );
310
    my $sth = $dbh->prepare( $sql );
291
   	$sth->execute( $token->{from}, $token->{until} );
311
    my @bind_params = ($token->{'from'}, $token->{'until'});
312
    push @bind_params, $set->{'id'} if defined $set;
313
    $sth->execute( @bind_params );
292
314
293
    my $pos = $token->{offset};
315
    my $pos = $token->{offset};
294
 	while ( my ($biblionumber, $timestamp) = $sth->fetchrow ) {
316
    while ( my ($biblionumber, $timestamp) = $sth->fetchrow ) {
295
 	    $timestamp =~ s/ /T/, $timestamp .= 'Z';
317
        $timestamp =~ s/ /T/, $timestamp .= 'Z';
296
        $self->identifier( new HTTP::OAI::Header(
318
        $self->identifier( new HTTP::OAI::Header(
297
            identifier => $repository->{ koha_identifier} . ':' . $biblionumber,
319
            identifier => $repository->{ koha_identifier} . ':' . $biblionumber,
298
            datestamp  => $timestamp,
320
            datestamp  => $timestamp,
299
        ) );
321
        ) );
300
        $pos++;
322
        $pos++;
301
 	}
323
    }
302
 	$self->resumptionToken( new C4::OAI::ResumptionToken(
324
    $self->resumptionToken(
303
        metadataPrefix  => $token->{metadata_prefix},
325
        new C4::OAI::ResumptionToken(
304
        from            => $token->{from},
326
            metadataPrefix  => $token->{metadata_prefix},
305
        until           => $token->{until},
327
            from            => $token->{from},
306
        offset          => $pos ) ) if ($pos > $token->{offset});
328
            until           => $token->{until},
329
            offset          => $pos,
330
            set             => $token->{set}
331
        )
332
    ) if ($pos > $token->{offset});
307
333
308
    return $self;
334
    return $self;
309
}
335
}
310
336
311
# __END__ C4::OAI::ListIdentifiers
337
# __END__ C4::OAI::ListIdentifiers
312
338
339
package C4::OAI::Description;
340
341
use strict;
342
use warnings;
343
use HTTP::OAI;
344
use HTTP::OAI::SAXHandler qw/ :SAX /;
345
346
sub new {
347
    my ( $class, %args ) = @_;
348
349
    my $self = {};
350
351
    if(my $setDescription = $args{setDescription}) {
352
        $self->{setDescription} = $setDescription;
353
    }
354
    if(my $handler = $args{handler}) {
355
        $self->{handler} = $handler;
356
    }
357
358
    bless $self, $class;
359
    return $self;
360
}
361
362
sub set_handler {
363
    my ( $self, $handler ) = @_;
364
365
    $self->{handler} = $handler if $handler;
366
367
    return $self;
368
}
369
370
sub generate {
371
    my ( $self ) = @_;
372
373
    g_data_element($self->{handler}, 'http://www.openarchives.org/OAI/2.0/', 'setDescription', {}, $self->{setDescription});
374
375
    return $self;
376
}
377
378
# __END__ C4::OAI::Description
379
380
package C4::OAI::ListSets;
381
382
use strict;
383
use warnings;
384
use HTTP::OAI;
385
use C4::OAI::Sets;
386
387
use base ("HTTP::OAI::ListSets");
388
389
sub new {
390
    my ( $class, $repository, %args ) = @_;
391
392
    my $self = HTTP::OAI::ListSets->new(%args);
393
394
    my $token = C4::OAI::ResumptionToken->new(%args);
395
    my $sets = GetOAISets;
396
    my $pos = 0;
397
    foreach my $set (@$sets) {
398
        if ($pos < $token->{offset}) {
399
            $pos++;
400
            next;
401
        }
402
        my @descriptions;
403
        foreach my $desc (@{$set->{'descriptions'}}) {
404
            push @descriptions, C4::OAI::Description->new(
405
                setDescription => $desc,
406
            );
407
        }
408
        $self->set(
409
            HTTP::OAI::Set->new(
410
                setSpec => $set->{'spec'},
411
                setName => $set->{'name'},
412
                setDescription => \@descriptions,
413
            )
414
        );
415
        $pos++;
416
        last if ($pos + 1 - $token->{offset}) > $repository->{koha_max_count};
417
    }
313
418
419
    $self->resumptionToken(
420
        new C4::OAI::ResumptionToken(
421
            metadataPrefix => $token->{metadata_prefix},
422
            offset         => $pos
423
        )
424
    ) if ( $pos > $token->{offset} );
425
426
    return $self;
427
}
428
429
# __END__ C4::OAI::ListSets;
314
430
315
package C4::OAI::ListRecords;
431
package C4::OAI::ListRecords;
316
432
317
use strict;
433
use strict;
318
use warnings;
434
use warnings;
319
use diagnostics;
320
use HTTP::OAI;
435
use HTTP::OAI;
436
use C4::OAI::Sets;
321
437
322
use base ("HTTP::OAI::ListRecords");
438
use base ("HTTP::OAI::ListRecords");
323
439
Lines 329-356 sub new { Link Here
329
445
330
    my $token = new C4::OAI::ResumptionToken( %args );
446
    my $token = new C4::OAI::ResumptionToken( %args );
331
    my $dbh = C4::Context->dbh;
447
    my $dbh = C4::Context->dbh;
332
    my $sql = "SELECT biblionumber, marcxml, timestamp
448
    my $set;
333
               FROM   biblioitems
449
    if(defined $token->{'set'}) {
334
               WHERE  timestamp >= ? AND timestamp <= ?
450
        $set = GetOAISetBySpec($token->{'set'});
335
               LIMIT  " . $repository->{koha_max_count} . "
451
    }
336
               OFFSET " . $token->{offset};
452
    my $sql = "
453
        SELECT biblioitems.biblionumber, biblioitems.marcxml, biblioitems.timestamp
454
        FROM biblioitems
455
    ";
456
    $sql .= " JOIN oai_sets_biblios ON biblioitems.biblionumber = oai_sets_biblios.biblionumber " if defined $set;
457
    $sql .= " WHERE DATE(timestamp) >= ? AND DATE(timestamp) <= ? ";
458
    $sql .= " AND oai_sets_biblios.set_id = ? " if defined $set;
459
    $sql .= "
460
        LIMIT $repository->{'koha_max_count'}
461
        OFFSET $token->{'offset'}
462
    ";
463
337
    my $sth = $dbh->prepare( $sql );
464
    my $sth = $dbh->prepare( $sql );
338
   	$sth->execute( $token->{from}, $token->{until} );
465
    my @bind_params = ($token->{'from'}, $token->{'until'});
466
    push @bind_params, $set->{'id'} if defined $set;
467
    $sth->execute( @bind_params );
339
468
340
    my $pos = $token->{offset};
469
    my $pos = $token->{offset};
341
 	while ( my ($biblionumber, $marcxml, $timestamp) = $sth->fetchrow ) {
470
    while ( my ($biblionumber, $marcxml, $timestamp) = $sth->fetchrow ) {
471
        my $oai_sets = GetOAISetsBiblio($biblionumber);
472
        my @setSpecs;
473
        foreach (@$oai_sets) {
474
            push @setSpecs, $_->{spec};
475
        }
342
        $self->record( C4::OAI::Record->new(
476
        $self->record( C4::OAI::Record->new(
343
            $repository, $marcxml, $timestamp,
477
            $repository, $marcxml, $timestamp, \@setSpecs,
344
            identifier      => $repository->{ koha_identifier } . ':' . $biblionumber,
478
            identifier      => $repository->{ koha_identifier } . ':' . $biblionumber,
345
            metadataPrefix  => $token->{metadata_prefix}
479
            metadataPrefix  => $token->{metadata_prefix}
346
        ) );
480
        ) );
347
        $pos++;
481
        $pos++;
348
 	}
482
    }
349
 	$self->resumptionToken( new C4::OAI::ResumptionToken(
483
    $self->resumptionToken(
350
        metadataPrefix  => $token->{metadata_prefix},
484
        new C4::OAI::ResumptionToken(
351
        from            => $token->{from},
485
            metadataPrefix  => $token->{metadata_prefix},
352
        until           => $token->{until},
486
            from            => $token->{from},
353
        offset          => $pos ) ) if ($pos > $token->{offset});
487
            until           => $token->{until},
488
            offset          => $pos,
489
            set             => $token->{set}
490
        )
491
    ) if ($pos > $token->{offset});
354
492
355
    return $self;
493
    return $self;
356
}
494
}
Lines 365-371 use base ("HTTP::OAI::Repository"); Link Here
365
503
366
use strict;
504
use strict;
367
use warnings;
505
use warnings;
368
use diagnostics;
369
506
370
use HTTP::OAI;
507
use HTTP::OAI;
371
use HTTP::OAI::Repository qw/:validate/;
508
use HTTP::OAI::Repository qw/:validate/;
Lines 418-431 sub new { Link Here
418
    else {
555
    else {
419
        my %attr = CGI::Vars();
556
        my %attr = CGI::Vars();
420
        my $verb = delete( $attr{verb} );
557
        my $verb = delete( $attr{verb} );
421
        if ( grep { $_ eq $verb } qw( ListSets ) ) {
558
        if ( $verb eq 'ListSets' ) {
422
            $response = HTTP::OAI::Response->new(
559
            $response = C4::OAI::ListSets->new($self, %attr);
423
                requestURL  => $self->self_url(),
424
                errors      => [ new HTTP::OAI::Error(
425
                    code    => 'noSetHierarchy',
426
                    message => "Koha repository doesn't have sets",
427
                    ) ] ,
428
            );
429
        }
560
        }
430
        elsif ( $verb eq 'Identify' ) {
561
        elsif ( $verb eq 'Identify' ) {
431
            $response = C4::OAI::Identify->new( $self );
562
            $response = C4::OAI::Identify->new( $self );
432
- 

Return to bug 6440