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

(-)a/C4/Biblio.pm (+12 lines)
Lines 35-40 use C4::Log; # logaction Link Here
35
use C4::ClassSource;
35
use C4::ClassSource;
36
use C4::Charset;
36
use C4::Charset;
37
use C4::Linker;
37
use C4::Linker;
38
use C4::OAI::Sets;
38
39
39
use vars qw($VERSION @ISA @EXPORT);
40
use vars qw($VERSION @ISA @EXPORT);
40
41
Lines 268-273 sub AddBiblio { Link Here
268
    # now add the record
269
    # now add the record
269
    ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
270
    ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
270
271
272
    # update OAI-PMH sets
273
    if(C4::Context->preference("OAI-PMH:AutoUpdateSets")) {
274
        C4::OAI::Sets::UpdateOAISetsBiblio($biblionumber, $record);
275
    }
276
271
    logaction( "CATALOGUING", "ADD", $biblionumber, "biblio" ) if C4::Context->preference("CataloguingLog");
277
    logaction( "CATALOGUING", "ADD", $biblionumber, "biblio" ) if C4::Context->preference("CataloguingLog");
272
    return ( $biblionumber, $biblioitemnumber );
278
    return ( $biblionumber, $biblioitemnumber );
273
}
279
}
Lines 339-344 sub ModBiblio { Link Here
339
    # modify the other koha tables
345
    # modify the other koha tables
340
    _koha_modify_biblio( $dbh, $oldbiblio, $frameworkcode );
346
    _koha_modify_biblio( $dbh, $oldbiblio, $frameworkcode );
341
    _koha_modify_biblioitem_nonmarc( $dbh, $oldbiblio );
347
    _koha_modify_biblioitem_nonmarc( $dbh, $oldbiblio );
348
349
    # update OAI-PMH sets
350
    if(C4::Context->preference("OAI-PMH:AutoUpdateSets")) {
351
        C4::OAI::Sets::UpdateOAISetsBiblio($biblionumber, $record);
352
    }
353
342
    return 1;
354
    return 1;
343
}
355
}
344
356
(-)a/C4/OAI/Sets.pm (+589 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 &AddOAISetsBiblios
44
        &CalcOAISetsBiblio &UpdateOAISetsBiblio
45
    );
46
}
47
48
=head1 FUNCTIONS
49
50
=head2 GetOAISets
51
52
    $oai_sets = GetOAISets;
53
54
GetOAISets return a array reference of hash references describing the sets.
55
The hash references looks like this:
56
57
    {
58
        'name'         => 'set name',
59
        'spec'         => 'set spec',
60
        'descriptions' => [
61
            'description 1',
62
            'description 2',
63
            ...
64
        ]
65
    }
66
67
=cut
68
69
sub GetOAISets {
70
    my $dbh = C4::Context->dbh;
71
    my $query = qq{
72
        SELECT * FROM oai_sets
73
    };
74
    my $sth = $dbh->prepare($query);
75
    $sth->execute;
76
    my $results = $sth->fetchall_arrayref({});
77
78
    $query = qq{
79
        SELECT description
80
        FROM oai_sets_descriptions
81
        WHERE set_id = ?
82
    };
83
    $sth = $dbh->prepare($query);
84
    foreach my $set (@$results) {
85
        $sth->execute($set->{'id'});
86
        my $desc = $sth->fetchall_arrayref({});
87
        foreach (@$desc) {
88
            push @{$set->{'descriptions'}}, $_->{'description'};
89
        }
90
    }
91
92
    return $results;
93
}
94
95
=head2 GetOAISet
96
97
    $set = GetOAISet($set_id);
98
99
GetOAISet returns a hash reference describing the set with the given set_id.
100
101
See GetOAISets to see what the hash looks like.
102
103
=cut
104
105
sub GetOAISet {
106
    my ($set_id) = @_;
107
108
    return unless $set_id;
109
110
    my $dbh = C4::Context->dbh;
111
    my $query = qq{
112
        SELECT *
113
        FROM oai_sets
114
        WHERE id = ?
115
    };
116
    my $sth = $dbh->prepare($query);
117
    $sth->execute($set_id);
118
    my $set = $sth->fetchrow_hashref;
119
120
    $query = qq{
121
        SELECT description
122
        FROM oai_sets_descriptions
123
        WHERE set_id = ?
124
    };
125
    $sth = $dbh->prepare($query);
126
    $sth->execute($set->{'id'});
127
    my $desc = $sth->fetchall_arrayref({});
128
    foreach (@$desc) {
129
        push @{$set->{'descriptions'}}, $_->{'description'};
130
    }
131
132
    return $set;
133
}
134
135
=head2 GetOAISetBySpec
136
137
    my $set = GetOAISetBySpec($setSpec);
138
139
Returns a hash describing the set whose spec is $setSpec
140
141
=cut
142
143
sub GetOAISetBySpec {
144
    my $setSpec = shift;
145
146
    return unless defined $setSpec;
147
148
    my $dbh = C4::Context->dbh;
149
    my $query = qq{
150
        SELECT *
151
        FROM oai_sets
152
        WHERE spec = ?
153
        LIMIT 1
154
    };
155
    my $sth = $dbh->prepare($query);
156
    $sth->execute($setSpec);
157
158
    return $sth->fetchrow_hashref;
159
}
160
161
=head2 ModOAISet
162
163
    my $set = {
164
        'id' => $set_id,                 # mandatory
165
        'spec' => $spec,                 # mandatory
166
        'name' => $name,                 # mandatory
167
        'descriptions => \@descriptions, # optional, [] to remove descriptions
168
    };
169
    ModOAISet($set);
170
171
ModOAISet modify a set in the database.
172
173
=cut
174
175
sub ModOAISet {
176
    my ($set) = @_;
177
178
    return unless($set && $set->{'spec'} && $set->{'name'});
179
180
    if(!defined $set->{'id'}) {
181
        warn "Set ID not defined, can't modify the set";
182
        return;
183
    }
184
185
    my $dbh = C4::Context->dbh;
186
    my $query = qq{
187
        UPDATE oai_sets
188
        SET spec = ?,
189
            name = ?
190
        WHERE id = ?
191
    };
192
    my $sth = $dbh->prepare($query);
193
    $sth->execute($set->{'spec'}, $set->{'name'}, $set->{'id'});
194
195
    if($set->{'descriptions'}) {
196
        $query = qq{
197
            DELETE FROM oai_sets_descriptions
198
            WHERE set_id = ?
199
        };
200
        $sth = $dbh->prepare($query);
201
        $sth->execute($set->{'id'});
202
203
        if(scalar @{$set->{'descriptions'}} > 0) {
204
            $query = qq{
205
                INSERT INTO oai_sets_descriptions (set_id, description)
206
                VALUES (?,?)
207
            };
208
            $sth = $dbh->prepare($query);
209
            foreach (@{ $set->{'descriptions'} }) {
210
                $sth->execute($set->{'id'}, $_) if $_;
211
            }
212
        }
213
    }
214
}
215
216
=head2 DelOAISet
217
218
    DelOAISet($set_id);
219
220
DelOAISet remove the set with the given set_id
221
222
=cut
223
224
sub DelOAISet {
225
    my ($set_id) = @_;
226
227
    return unless $set_id;
228
229
    my $dbh = C4::Context->dbh;
230
    my $query = qq{
231
        DELETE oai_sets, oai_sets_descriptions, oai_sets_mappings
232
        FROM oai_sets
233
          LEFT JOIN oai_sets_descriptions ON oai_sets_descriptions.set_id = oai_sets.id
234
          LEFT JOIN oai_sets_mappings ON oai_sets_mappings.set_id = oai_sets.id
235
        WHERE oai_sets.id = ?
236
    };
237
    my $sth = $dbh->prepare($query);
238
    $sth->execute($set_id);
239
}
240
241
=head2 AddOAISet
242
243
    my $set = {
244
        'id' => $set_id,                 # mandatory
245
        'spec' => $spec,                 # mandatory
246
        'name' => $name,                 # mandatory
247
        'descriptions => \@descriptions, # optional
248
    };
249
    my $set_id = AddOAISet($set);
250
251
AddOAISet adds a new set and returns its id, or undef if something went wrong.
252
253
=cut
254
255
sub AddOAISet {
256
    my ($set) = @_;
257
258
    return unless($set && $set->{'spec'} && $set->{'name'});
259
260
    my $set_id;
261
    my $dbh = C4::Context->dbh;
262
    my $query = qq{
263
        INSERT INTO oai_sets (spec, name)
264
        VALUES (?,?)
265
    };
266
    my $sth = $dbh->prepare($query);
267
    if( $sth->execute($set->{'spec'}, $set->{'name'}) ) {
268
        $set_id = $dbh->last_insert_id(undef, undef, 'oai_sets', undef);
269
        if($set->{'descriptions'}) {
270
            $query = qq{
271
                INSERT INTO oai_sets_descriptions (set_id, description)
272
                VALUES (?,?)
273
            };
274
            $sth = $dbh->prepare($query);
275
            foreach( @{ $set->{'descriptions'} } ) {
276
                $sth->execute($set_id, $_) if $_;
277
            }
278
        }
279
    } else {
280
        warn "AddOAISet failed";
281
    }
282
283
    return $set_id;
284
}
285
286
=head2 GetOAISetsMappings
287
288
    my $mappings = GetOAISetsMappings;
289
290
GetOAISetsMappings returns mappings for all OAI Sets.
291
292
Mappings define how biblios are categorized in sets.
293
A mapping is defined by three properties:
294
295
    {
296
        marcfield => 'XXX',     # the MARC field to check
297
        marcsubfield => 'Y',    # the MARC subfield to check
298
        marcvalue => 'zzzz',    # the value to check
299
    }
300
301
If defined in a set mapping, a biblio which have at least one 'Y' subfield of
302
one 'XXX' field equal to 'zzzz' will belong to this set.
303
If multiple mappings are defined in a set, the biblio will belong to this set
304
if at least one condition is matched.
305
306
GetOAISetsMappings returns a hashref of arrayrefs of hashrefs.
307
The first hashref keys are the sets IDs, so it looks like this:
308
309
    $mappings = {
310
        '1' => [
311
            {
312
                marcfield => 'XXX',
313
                marcsubfield => 'Y',
314
                marcvalue => 'zzzz'
315
            },
316
            {
317
                ...
318
            },
319
            ...
320
        ],
321
        '2' => [...],
322
        ...
323
    };
324
325
=cut
326
327
sub GetOAISetsMappings {
328
    my $dbh = C4::Context->dbh;
329
    my $query = qq{
330
        SELECT * FROM oai_sets_mappings
331
    };
332
    my $sth = $dbh->prepare($query);
333
    $sth->execute;
334
335
    my $mappings = {};
336
    while(my $result = $sth->fetchrow_hashref) {
337
        push @{ $mappings->{$result->{'set_id'}} }, {
338
            marcfield => $result->{'marcfield'},
339
            marcsubfield => $result->{'marcsubfield'},
340
            marcvalue => $result->{'marcvalue'}
341
        };
342
    }
343
344
    return $mappings;
345
}
346
347
=head2 GetOAISetMappings
348
349
    my $set_mappings = GetOAISetMappings($set_id);
350
351
Return mappings for the set with given set_id. It's an arrayref of hashrefs
352
353
=cut
354
355
sub GetOAISetMappings {
356
    my ($set_id) = @_;
357
358
    return unless $set_id;
359
360
    my $dbh = C4::Context->dbh;
361
    my $query = qq{
362
        SELECT *
363
        FROM oai_sets_mappings
364
        WHERE set_id = ?
365
    };
366
    my $sth = $dbh->prepare($query);
367
    $sth->execute($set_id);
368
369
    my @mappings;
370
    while(my $result = $sth->fetchrow_hashref) {
371
        push @mappings, {
372
            marcfield => $result->{'marcfield'},
373
            marcsubfield => $result->{'marcsubfield'},
374
            marcvalue => $result->{'marcvalue'}
375
        };
376
    }
377
378
    return \@mappings;
379
}
380
381
=head2 ModOAISetMappings {
382
383
    my $mappings = [
384
        {
385
            marcfield => 'XXX',
386
            marcsubfield => 'Y',
387
            marcvalue => 'zzzz'
388
        },
389
        ...
390
    ];
391
    ModOAISetMappings($set_id, $mappings);
392
393
ModOAISetMappings modifies mappings of a given set.
394
395
=cut
396
397
sub ModOAISetMappings {
398
    my ($set_id, $mappings) = @_;
399
400
    return unless $set_id;
401
402
    my $dbh = C4::Context->dbh;
403
    my $query = qq{
404
        DELETE FROM oai_sets_mappings
405
        WHERE set_id = ?
406
    };
407
    my $sth = $dbh->prepare($query);
408
    $sth->execute($set_id);
409
410
    if(scalar @$mappings > 0) {
411
        $query = qq{
412
            INSERT INTO oai_sets_mappings (set_id, marcfield, marcsubfield, marcvalue)
413
            VALUES (?,?,?,?)
414
        };
415
        $sth = $dbh->prepare($query);
416
        foreach (@$mappings) {
417
            $sth->execute($set_id, $_->{'marcfield'}, $_->{'marcsubfield'}, $_->{'marcvalue'});
418
        }
419
    }
420
}
421
422
=head2 GetOAISetsBiblio
423
424
    $oai_sets = GetOAISetsBiblio($biblionumber);
425
426
Return the OAI sets where biblio appears.
427
428
Return value is an arrayref of hashref where each element of the array is a set.
429
Keys of hash are id, spec and name
430
431
=cut
432
433
sub GetOAISetsBiblio {
434
    my ($biblionumber) = @_;
435
436
    my $dbh = C4::Context->dbh;
437
    my $query = qq{
438
        SELECT oai_sets.*
439
        FROM oai_sets
440
          LEFT JOIN oai_sets_biblios ON oai_sets_biblios.set_id = oai_sets.id
441
        WHERE biblionumber = ?
442
    };
443
    my $sth = $dbh->prepare($query);
444
445
    $sth->execute($biblionumber);
446
    return $sth->fetchall_arrayref({});
447
}
448
449
=head2 DelOAISetsBiblio
450
451
    DelOAISetsBiblio($biblionumber);
452
453
Remove a biblio from all sets
454
455
=cut
456
457
sub DelOAISetsBiblio {
458
    my ($biblionumber) = @_;
459
460
    return unless $biblionumber;
461
462
    my $dbh = C4::Context->dbh;
463
    my $query = qq{
464
        DELETE FROM oai_sets_biblios
465
        WHERE biblionumber = ?
466
    };
467
    my $sth = $dbh->prepare($query);
468
    return $sth->execute($biblionumber);
469
}
470
471
=head2 CalcOAISetsBiblio
472
473
    my @sets = CalcOAISetsBiblio($record, $oai_sets_mappings);
474
475
Return a list of set ids the record belongs to. $record must be a MARC::Record
476
and $oai_sets_mappings (optional) must be a hashref returned by
477
GetOAISetsMappings
478
479
=cut
480
481
sub CalcOAISetsBiblio {
482
    my ($record, $oai_sets_mappings) = @_;
483
484
    return unless $record;
485
486
    $oai_sets_mappings ||= GetOAISetsMappings;
487
488
    my @biblio_sets;
489
    foreach my $set_id (keys %$oai_sets_mappings) {
490
        foreach my $mapping (@{ $oai_sets_mappings->{$set_id} }) {
491
            next if not $mapping;
492
            my $field = $mapping->{'marcfield'};
493
            my $subfield = $mapping->{'marcsubfield'};
494
            my $value = $mapping->{'marcvalue'};
495
496
            my @subfield_values = $record->subfield($field, $subfield);
497
            if(0 < grep /^$value$/, @subfield_values) {
498
                push @biblio_sets, $set_id;
499
                last;
500
            }
501
        }
502
    }
503
    return @biblio_sets;
504
}
505
506
=head2 ModOAISetsBiblios
507
508
    my $oai_sets_biblios = {
509
        '1' => [1, 3, 4],   # key is the set_id, and value is an array ref of biblionumbers
510
        '2' => [],
511
        ...
512
    };
513
    ModOAISetsBiblios($oai_sets_biblios);
514
515
ModOAISetsBiblios truncate oai_sets_biblios table and call AddOAISetsBiblios.
516
This table is then used in opac/oai.pl.
517
518
=cut
519
520
sub ModOAISetsBiblios {
521
    my $oai_sets_biblios = shift;
522
523
    return unless ref($oai_sets_biblios) eq "HASH";
524
525
    my $dbh = C4::Context->dbh;
526
    my $query = qq{
527
        TRUNCATE TABLE oai_sets_biblios
528
    };
529
    my $sth = $dbh->prepare($query);
530
    $sth->execute;
531
    AddOAISetsBiblios($oai_sets_biblios);
532
}
533
534
=head2 UpdateOAISetsBiblio
535
536
    UpdateOAISetsBiblio($biblionumber, $record);
537
538
Update OAI sets for one biblio. The two parameters are mandatory.
539
$record is a MARC::Record.
540
541
=cut
542
543
sub UpdateOAISetsBiblio {
544
    my ($biblionumber, $record) = @_;
545
546
    return unless($biblionumber and $record);
547
548
    my $sets_biblios;
549
    my @sets = CalcOAISetsBiblio($record);
550
    foreach (@sets) {
551
        push @{ $sets_biblios->{$_} }, $biblionumber;
552
    }
553
    DelOAISetsBiblio($biblionumber);
554
    AddOAISetsBiblios($sets_biblios);
555
}
556
557
=head2 AddOAISetsBiblios
558
559
    my $oai_sets_biblios = {
560
        '1' => [1, 3, 4],   # key is the set_id, and value is an array ref of biblionumbers
561
        '2' => [],
562
        ...
563
    };
564
    ModOAISetsBiblios($oai_sets_biblios);
565
566
AddOAISetsBiblios insert given infos in oai_sets_biblios table.
567
This table is then used in opac/oai.pl.
568
569
=cut
570
571
sub AddOAISetsBiblios {
572
    my $oai_sets_biblios = shift;
573
574
    return unless ref($oai_sets_biblios) eq "HASH";
575
576
    my $dbh = C4::Context->dbh;
577
    my $query = qq{
578
        INSERT INTO oai_sets_biblios (set_id, biblionumber)
579
        VALUES (?,?)
580
    };
581
    my $sth = $dbh->prepare($query);
582
    foreach my $set_id (keys %$oai_sets_biblios) {
583
        foreach my $biblionumber (@{$oai_sets_biblios->{$set_id}}) {
584
            $sth->execute($set_id, $biblionumber);
585
        }
586
    }
587
}
588
589
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 (+35 lines)
Line 0 Link Here
1
DROP TABLE IF EXISTS `oai_sets_descriptions`;
2
DROP TABLE IF EXISTS `oai_sets_mappings`;
3
DROP TABLE IF EXISTS `oai_sets_biblios`;
4
DROP TABLE IF EXISTS `oai_sets`;
5
6
CREATE TABLE `oai_sets` (
7
  `id` int(11) NOT NULL auto_increment,
8
  `spec` varchar(80) NOT NULL UNIQUE,
9
  `name` varchar(80) NOT NULL,
10
  PRIMARY KEY (`id`)
11
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
12
13
CREATE TABLE `oai_sets_descriptions` (
14
  `set_id` int(11) NOT NULL,
15
  `description` varchar(255) NOT NULL,
16
  CONSTRAINT `oai_sets_descriptions_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
17
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
18
19
CREATE TABLE `oai_sets_mappings` (
20
  `set_id` int(11) NOT NULL,
21
  `marcfield` char(3) NOT NULL,
22
  `marcsubfield` char(1) NOT NULL,
23
  `marcvalue` varchar(80) NOT NULL,
24
  CONSTRAINT `oai_sets_mappings_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
25
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
26
27
CREATE TABLE `oai_sets_biblios` (
28
  `biblionumber` int(11) NOT NULL,
29
  `set_id` int(11) NOT NULL,
30
  PRIMARY KEY (`biblionumber`, `set_id`),
31
  CONSTRAINT `oai_sets_biblios_ibfk_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE,
32
  CONSTRAINT `oai_sets_biblios_ibfk_2` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
33
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
34
35
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OAI-PMH:AutoUpdateSets','0','Automatically update OAI sets when a bibliographic record is created or updated','','YesNo');
(-)a/installer/data/mysql/kohastructure.sql (+49 lines)
Lines 1354-1359 CREATE TABLE `nozebra` ( Link Here
1354
  ENGINE=InnoDB DEFAULT CHARSET=utf8;
1354
  ENGINE=InnoDB DEFAULT CHARSET=utf8;
1355
1355
1356
--
1356
--
1357
-- Table structure for table `oai_sets`
1358
--
1359
1360
DROP TABLE IF EXISTS `oai_sets`;
1361
CREATE TABLE `oai_sets` (
1362
  `id` int(11) NOT NULL auto_increment,
1363
  `spec` varchar(80) NOT NULL UNIQUE,
1364
  `name` varchar(80) NOT NULL,
1365
  PRIMARY KEY (`id`)
1366
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1367
1368
--
1369
-- Table structure for table `oai_sets_descriptions`
1370
--
1371
1372
DROP TABLE IF EXISTS `oai_sets_descriptions`;
1373
CREATE TABLE `oai_sets_descriptions` (
1374
  `set_id` int(11) NOT NULL,
1375
  `description` varchar(255) NOT NULL,
1376
  CONSTRAINT `oai_sets_descriptions_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
1377
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1378
1379
--
1380
-- Table structure for table `oai_sets_mappings`
1381
--
1382
1383
DROP TABLE IF EXISTS `oai_sets_mappings`;
1384
CREATE TABLE `oai_sets_mappings` (
1385
  `set_id` int(11) NOT NULL,
1386
  `marcfield` char(3) NOT NULL,
1387
  `marcsubfield` char(1) NOT NULL,
1388
  `marcvalue` varchar(80) NOT NULL,
1389
  CONSTRAINT `oai_sets_mappings_ibfk_1` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
1390
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1391
1392
--
1393
-- Table structure for table `oai_sets_biblios`
1394
--
1395
1396
DROP TABLE IF EXISTS `oai_sets_biblios`;
1397
CREATE TABLE `oai_sets_biblios` (
1398
  `biblionumber` int(11) NOT NULL,
1399
  `set_id` int(11) NOT NULL,
1400
  PRIMARY KEY (`biblionumber`, `set_id`),
1401
  CONSTRAINT `oai_sets_biblios_ibfk_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE,
1402
  CONSTRAINT `oai_sets_biblios_ibfk_2` FOREIGN KEY (`set_id`) REFERENCES `oai_sets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
1403
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1404
1405
--
1357
-- Table structure for table `old_issues`
1406
-- Table structure for table `old_issues`
1358
--
1407
--
1359
1408
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 344-346 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES(' Link Here
344
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerRelink',1,'If ON the authority linker will relink headings that have previously been linked every time it runs.',NULL,'YesNo');
344
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerRelink',1,'If ON the authority linker will relink headings that have previously been linked every time it runs.',NULL,'YesNo');
345
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerKeepStale',0,'If ON the authority linker will keep existing authority links for headings where it is unable to find a match.',NULL,'YesNo');
345
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerKeepStale',0,'If ON the authority linker will keep existing authority links for headings where it is unable to find a match.',NULL,'YesNo');
346
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo');
346
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo');
347
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OAI-PMH:AutoUpdateSets','0','Automatically update OAI sets when a bibliographic record is created or updated','','YesNo');
(-)a/installer/data/mysql/updatedatabase.pl (+10 lines)
Lines 4765-4770 if (C4::Context->preference("Version") < TransformToNum($DBversion)) { Link Here
4765
    SetVersion($DBversion);
4765
    SetVersion($DBversion);
4766
}
4766
}
4767
4767
4768
$DBversion = "XXX";
4769
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
4770
    my $installer = C4::Installer->new();
4771
    my $full_path = C4::Context->config('intranetdir') . "/installer/data/$installer->{dbms}/atomicupdate/oai_sets.sql";
4772
    my $error     = $installer->load_sql($full_path);
4773
    warn $error if $error;
4774
    print "Upgrade to $DBversion done (Atomic update for OAI-PMH sets management)\n";
4775
    SetVersion($DBversion);
4776
}
4777
4768
=head1 FUNCTIONS
4778
=head1 FUNCTIONS
4769
4779
4770
=head2 DropAllForeignKeys($table)
4780
=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=[% set.id %]">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/modules/admin/preferences/web_services.pref (+6 lines)
Lines 21-26 Web Services: Link Here
21
            - pref: "OAI-PMH:ConfFile"
21
            - pref: "OAI-PMH:ConfFile"
22
              class: file
22
              class: file
23
            - . If empty, Koha OAI Server operates in normal mode, otherwise it operates in extended mode. In extended mode, it's possible to parameter other formats than marcxml or Dublin Core. OAI-PMH:ConfFile specify a YAML configuration file which list available metadata formats and XSL file used to create them from marcxml records.
23
            - . If empty, Koha OAI Server operates in normal mode, otherwise it operates in extended mode. In extended mode, it's possible to parameter other formats than marcxml or Dublin Core. OAI-PMH:ConfFile specify a YAML configuration file which list available metadata formats and XSL file used to create them from marcxml records.
24
        -
25
            - pref: "OAI-PMH:AutoUpdateSets"
26
              choices:
27
                  yes: Enable
28
                  no: Disable
29
            - automatic update of OAI-PMH sets when a bibliographic record is created or updated
24
    ILS-DI:
30
    ILS-DI:
25
        -
31
        -
26
            - pref: ILS-DI
32
            - pref: ILS-DI
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/oai_set_mappings.tt (+40 lines)
Line 0 Link Here
1
[% INCLUDE 'help-top.inc' %]
2
3
<h1>OAI-PMH Sets Mappings Configuration</h1>
4
5
<p>
6
    Here you can define how a set will be build (what records will belong to
7
    this set) by defining mappings. Mappings are a list of conditions on record
8
    content. A record only need to match one condition to belong to the set.
9
<p>
10
11
<h2>Defining a mapping</h2>
12
<ol>
13
    <li>
14
        Fill the fields 'Field', 'Subfield' and 'Value'. For example if you
15
        want to include in this set all records that have a 999$9 equal to
16
        'XXX'. Fill 'Field' with 999, 'Subfield' with 9 and 'Value' with XXX.
17
    </li>
18
    <li>
19
        If you want to add another condition, click on 'OR' button and repeat
20
        step 1.
21
    </li>
22
    <li>Click on 'Save'</li>
23
</ol>
24
25
<p>
26
    To delete a condition, just leave at least one of 'Field', 'Subfield' or
27
    'Value' empty and click on 'Save'.
28
</p>
29
30
<p>
31
    Note: Actually, a condition is true if value in the corresponding subfield
32
    is strictly equal to what is defined if 'Value'. A record having
33
    999$9 = 'XXX YYY' will not belong to a set where condition is
34
    999$9 = 'XXX'.
35
    <br />
36
    And it is case sensitive : a record having 999$9 = 'xxx' will not belong
37
    to a set where condition is 999$9 = 'XXX'.
38
</p>
39
40
[% INCLUDE 'help-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/oai_sets.tt (+49 lines)
Line 0 Link Here
1
[% INCLUDE 'help-top.inc' %]
2
3
<h1>OAI-PMH Sets Configuration</h1>
4
5
<p>On this page you can create, modify and delete OAI-PMH sets<p>
6
7
<h2>Create a set</h2>
8
9
<ol>
10
    <li>Click on the link 'Add a new set'</li>
11
    <li>Fill the mandatory fields 'setSpec' and 'setName'</li>
12
    <li>
13
        Then you can add descriptions for this set. To do this click on
14
        'Add description' and fill the newly created text box. You can add as
15
        many descriptions as you want.
16
    </li>
17
    <li>Click on 'Save' button'</li>
18
</ol>
19
20
<h2>Modify a set</h2>
21
22
<p>
23
    To modify a set, just click on the link 'Modify' on the same line of the
24
    set you want to modify. A form similar to set creation form will appear and
25
    allow you to modify the setSpec, setName and descriptions.
26
<p>
27
28
<h2>Delete a set</h2>
29
30
<p>
31
    To delete a set, just click on the link 'Delete' on the same line of the
32
    set you want to delete.
33
</p>
34
35
<h2>Define mappings</h2>
36
37
<p>
38
    The 'Define mappings' link allow you to tell how the set will be build
39
    (what records will belong to this set)
40
</p>
41
42
<h2>Build sets</h2>
43
44
<p>
45
    Once you have configured all your sets, you have to build the sets. This is
46
    done by calling the script misc/migration_tools/build_oai_sets.pl.
47
</p>
48
49
[% INCLUDE 'help-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 (+165 lines)
Line 0 Link Here
1
#!/usr/bin/perl
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 DESCRIPTION
21
22
This script build OAI-PMH sets (to be used by opac/oai.pl) according to sets
23
and mappings defined in Koha. It reads informations from oai_sets and
24
oai_sets_mappings, and then fill table oai_sets_biblios with builded infos.
25
26
=head1 USAGE
27
28
    build_oai_sets.pl [-h] [-v] [-r] [-i] [-l LENGTH [-o OFFSET]]
29
        -h          Print help message;
30
        -v          Be verbose
31
        -r          Truncate table oai_sets_biblios before inserting new rows
32
        -i          Embed items informations, mandatory if you defined mappings
33
                    on item fields
34
        -l LENGTH   Process LENGTH biblios
35
        -o OFFSET   If LENGTH is defined, start processing from OFFSET
36
37
=cut
38
39
use Modern::Perl;
40
use MARC::Record;
41
use MARC::File::XML;
42
use List::MoreUtils qw/uniq/;
43
use Getopt::Std;
44
45
use C4::Context;
46
use C4::Charset qw/StripNonXmlChars/;
47
use C4::Biblio;
48
use C4::OAI::Sets;
49
50
my %opts;
51
$Getopt::Std::STANDARD_HELP_VERSION = 1;
52
my $go = getopts('vo:l:ihr', \%opts);
53
54
if(!$go or $opts{h}){
55
    &print_usage;
56
    exit;
57
}
58
59
my $verbose = $opts{v};
60
my $offset = $opts{o};
61
my $length = $opts{l};
62
my $embed_items = $opts{i};
63
my $reset = $opts{r};
64
65
my $dbh = C4::Context->dbh;
66
67
# Get OAI sets mappings
68
my $mappings = GetOAISetsMappings;
69
70
# Get all biblionumbers and marcxml
71
print "Retrieving biblios... " if $verbose;
72
my $query = qq{
73
    SELECT biblionumber, marcxml
74
    FROM biblioitems
75
};
76
if($length) {
77
    $query .= "LIMIT $length";
78
    if($offset) {
79
        $query .= " OFFSET $offset";
80
    }
81
}
82
my $sth = $dbh->prepare($query);
83
$sth->execute;
84
my $results = $sth->fetchall_arrayref({});
85
print "done.\n" if $verbose;
86
87
# Build lists of parents sets
88
my $sets = GetOAISets;
89
my $parentsets;
90
foreach my $set (@$sets) {
91
    my $setSpec = $set->{'spec'};
92
    while($setSpec =~ /^(.+):(.+)$/) {
93
        my $parent = $1;
94
        my $parent_set = GetOAISetBySpec($parent);
95
        if($parent_set) {
96
            push @{ $parentsets->{$set->{'id'}} }, $parent_set->{'id'};
97
            $setSpec = $parent;
98
        } else {
99
            last;
100
        }
101
    }
102
}
103
104
my $num_biblios = scalar @$results;
105
my $i = 1;
106
my $sets_biblios = {};
107
foreach my $res (@$results) {
108
    my $biblionumber = $res->{'biblionumber'};
109
    my $marcxml = $res->{'marcxml'};
110
    if($verbose and $i % 1000 == 0) {
111
        my $percent = ($i * 100) / $num_biblios;
112
        $percent = sprintf("%.2f", $percent);
113
        say "Progression: $i/$num_biblios ($percent %)";
114
    }
115
    # The following lines are copied from GetMarcBiblio
116
    # We don't call GetMarcBiblio to avoid a sql query to be executed each time
117
    $marcxml = StripNonXmlChars($marcxml);
118
    MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
119
    my $record;
120
    eval {
121
        $record = MARC::Record::new_from_xml($marcxml, "utf8", C4::Context->preference('marcflavour'));
122
    };
123
    if($@) {
124
        warn "(biblio $biblionumber) Error while creating record from marcxml: $@";
125
        next;
126
    }
127
    if($embed_items) {
128
        C4::Biblio::EmbedItemsInMarcBiblio($record, $biblionumber);
129
    }
130
131
    my @biblio_sets = CalcOAISetsBiblio($record, $mappings);
132
    foreach my $set_id (@biblio_sets) {
133
        push @{ $sets_biblios->{$set_id} }, $biblionumber;
134
        foreach my $parent_set_id ( @{ $parentsets->{$set_id} } ) {
135
            push @{ $sets_biblios->{$parent_set_id} }, $biblionumber;
136
        }
137
    }
138
    $i++;
139
}
140
say "Progression: done." if $verbose;
141
142
say "Summary:";
143
foreach my $set_id (keys %$sets_biblios) {
144
    $sets_biblios->{$set_id} = [ uniq @{ $sets_biblios->{$set_id} } ];
145
    my $set = GetOAISet($set_id);
146
    my $setSpec = $set->{'spec'};
147
    say "Set '$setSpec': ". scalar(@{$sets_biblios->{$set_id}}) ." biblios";
148
}
149
150
print "Updating database... ";
151
if($reset) {
152
    ModOAISetsBiblios( {} );
153
}
154
AddOAISetsBiblios($sets_biblios);
155
print "done.\n";
156
157
sub print_usage {
158
    print "build_oai_sets.pl: Build OAI-PMH sets, according to mappings defined in Koha\n";
159
    print "Usage: build_oai_sets.pl [-h] [-v] [-i] [-l LENGTH [-o OFFSET]]\n\n";
160
    print "\t-h\t\tPrint this help and exit\n";
161
    print "\t-v\t\tBe verbose\n";
162
    print "\t-i\t\tEmbed items informations, mandatory if you defined mappings on item fields\n";
163
    print "\t-l LENGTH\tProcess LENGTH biblios\n";
164
    print "\t-o OFFSET\tIf LENGTH is defined, start processing from OFFSET\n\n";
165
}
(-)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