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

(-)a/Koha/Daemon.pm (+58 lines)
Lines 22-27 use Modern::Perl; Link Here
22
use POSIX; #For daemonizing
22
use POSIX; #For daemonizing
23
use Fcntl qw(:flock); #For pidfile
23
use Fcntl qw(:flock); #For pidfile
24
24
25
=head1 NAME
26
27
Koha::Daemon
28
29
=head1 SYNOPSIS
30
31
  use Koha::Daemon;
32
  my $daemon = Koha::Daemon->new({
33
    pidfile => "/path/to/file.pid",
34
    logfile => "/path/to/file.log",
35
    daemonize => 1,
36
  });
37
  $daemon->run();
38
39
=head1 METHODS
40
41
=head2 new
42
43
Create object
44
45
=head2 run
46
47
Run the daemon.
48
49
This method calls all the internal methods which
50
are do everything necessary to run the daemon.
51
52
=head1 INTERNAL METHODS
53
54
=head2 daemonize
55
56
Internal function for setting object up as a proper daemon
57
(e.g. forking, setting permissions, changing directories,
58
 closing file handles, etc.)
59
60
=head2 get_pidfile
61
62
Internal function to get a filehandle for the pidfile
63
64
=head2 lock_pidfile
65
66
Internal function to lock the pidfile, so that only one daemon
67
can run against this pidfile
68
69
=head2 log_to_file
70
71
Internal function to log to a file
72
73
=head2 make_pidfilehandle
74
75
Internal function to make a filehandle for pidfile
76
77
=head2 write_pidfile
78
79
Internal function to write pid to pidfile
80
81
=cut
82
25
sub new {
83
sub new {
26
    my ($class, $args) = @_;
84
    my ($class, $args) = @_;
27
    $args = {} unless defined $args;
85
    $args = {} unless defined $args;
(-)a/Koha/OAI/Harvester.pm (-27 / +90 lines)
Lines 30-40 use DateTime; Link Here
30
use DateTime::Format::Strptime;
30
use DateTime::Format::Strptime;
31
31
32
use C4::Context;
32
use C4::Context;
33
use Koha::Database;
33
use Koha::OAI::Harvester::ImportQueues;
34
34
35
=head1 API
35
=head1 NAME
36
36
37
=head2 Class Methods
37
Koha::OAI::Harvester
38
39
=head1 SYNOPSIS
40
41
my $harvester = Koha::OAI::Harvester->spawn({
42
    Downloader => $downloader,
43
    DownloaderWorkers => $download_workers,
44
    Importer => $importer,
45
    ImporterWorkers => $import_workers,
46
    ImportQueuePoll => $import_poll,
47
    logger => $logger,
48
    state_file => $statefile,
49
    spooldir => $spooldir,
50
});
51
52
=head2 METHODS
38
53
39
=cut
54
=cut
40
55
Lines 45-56 my $seconds_granularity = DateTime::Format::Strptime->new( Link Here
45
    pattern   => '%FT%TZ',
60
    pattern   => '%FT%TZ',
46
);
61
);
47
62
63
=head2 new
64
65
Create object
66
67
=cut
68
48
sub new {
69
sub new {
49
    my ($class, $args) = @_;
70
    my ($class, $args) = @_;
50
    $args = {} unless defined $args;
71
    $args = {} unless defined $args;
51
    return bless ($args, $class);
72
    return bless ($args, $class);
52
}
73
}
53
74
75
=head2 spawn
76
77
    Creates POE sessions for handling tasks, downloading, and importing
78
79
=cut
80
54
sub spawn {
81
sub spawn {
55
    my ($class, $args) = @_;
82
    my ($class, $args) = @_;
56
    my $self = $class->new($args);
83
    my $self = $class->new($args);
Lines 114-128 sub spawn { Link Here
114
            my $active_tasks = $poe_kernel->call("harvester","list_tasks","active");
141
            my $active_tasks = $poe_kernel->call("harvester","list_tasks","active");
115
            my @active_uuids = map { $_->{uuid} } @$active_tasks;
142
            my @active_uuids = map { $_->{uuid} } @$active_tasks;
116
143
117
            my $schema = Koha::Database->new()->schema();
144
            my $rs = Koha::OAI::Harvester::ImportQueues->new->search({
118
            my $rs = $schema->resultset('OaiHarvesterImportQueue')->search({
119
                uuid => \@active_uuids,
145
                uuid => \@active_uuids,
120
                status => "new"
146
                status => "new"
121
            },{
147
            },{
122
                order_by => { -asc => 'id' },
148
                order_by => { -asc => 'id' },
123
                rows => 1,
149
                rows => 1,
124
            });
150
            });
125
            my $result = $rs->first;
151
            my $result = $rs->single;
126
            if ($result){
152
            if ($result){
127
                $result->status("wip");
153
                $result->status("wip");
128
                $result->update;
154
                $result->update;
Lines 149-154 sub spawn { Link Here
149
    return;
175
    return;
150
}
176
}
151
177
178
=head2 on_start
179
180
    Internal method that starts the harvester
181
182
=cut
183
152
sub on_start {
184
sub on_start {
153
    my ($self, $kernel, $heap) = @_[OBJECT, KERNEL,HEAP];
185
    my ($self, $kernel, $heap) = @_[OBJECT, KERNEL,HEAP];
154
    $kernel->alias_set('harvester');
186
    $kernel->alias_set('harvester');
Lines 161-173 sub on_start { Link Here
161
    $kernel->call("harvester","restore_state");
193
    $kernel->call("harvester","restore_state");
162
}
194
}
163
195
196
=head2 download_postback
197
198
    Internal method
199
200
=cut
201
164
#NOTE: This isn't really implemented at the moment, as it's not really necessary.
202
#NOTE: This isn't really implemented at the moment, as it's not really necessary.
165
sub download_postback {
203
sub download_postback {
166
    my ($kernel, $request_packet, $response_packet) = @_[KERNEL, ARG0, ARG1];
204
    my ($kernel, $request_packet, $response_packet) = @_[KERNEL, ARG0, ARG1];
167
    my $message = $response_packet->[0];
205
    my $message = $response_packet->[0];
168
}
206
}
169
207
170
=head3 deregister
208
=head2 deregister
171
209
172
    Remove the worker session from the harvester's in-memory scoreboard,
210
    Remove the worker session from the harvester's in-memory scoreboard,
173
    unset the downloading flag if downloading is completed.
211
    unset the downloading flag if downloading is completed.
Lines 218-224 sub deregister { Link Here
218
}
256
}
219
257
220
258
221
=head3 is_task_finished
259
=head2 is_task_finished
222
260
223
    This event handler checks if the task has finished downloading and importing record.
261
    This event handler checks if the task has finished downloading and importing record.
224
    If it is finished downloading and importing, the task is deleted from the harvester.
262
    If it is finished downloading and importing, the task is deleted from the harvester.
Lines 241-246 sub is_task_finished { Link Here
241
    return 0;
279
    return 0;
242
}
280
}
243
281
282
=head2 register
283
284
    Internal method for registering a task on the harvester's scoreboard
285
286
=cut
287
244
sub register {
288
sub register {
245
    my ($self, $kernel, $heap, $session, $sender, $type, $task_uuid) = @_[OBJECT, KERNEL,HEAP,SESSION,SENDER,ARG0,ARG1];
289
    my ($self, $kernel, $heap, $session, $sender, $type, $task_uuid) = @_[OBJECT, KERNEL,HEAP,SESSION,SENDER,ARG0,ARG1];
246
    my $logger = $self->{logger};
290
    my $logger = $self->{logger};
Lines 288-293 sub register { Link Here
288
    }
332
    }
289
}
333
}
290
334
335
=head2 does_task_repeat
336
337
    Internal method for checking if a task is supposed to repeat after it finishes
338
339
=cut
340
291
sub does_task_repeat {
341
sub does_task_repeat {
292
    my ($self, $kernel, $heap, $session, $uuid) = @_[OBJECT, KERNEL,HEAP,SESSION,ARG0];
342
    my ($self, $kernel, $heap, $session, $uuid) = @_[OBJECT, KERNEL,HEAP,SESSION,ARG0];
293
    my $task = $kernel->call("harvester","get_task",$uuid);
343
    my $task = $kernel->call("harvester","get_task",$uuid);
Lines 306-318 sub does_task_repeat { Link Here
306
    return 0;
356
    return 0;
307
}
357
}
308
358
359
=head2 reset_imports_status
309
360
361
    Internal method that resets the import queue from wip to new
362
363
=cut
310
364
311
sub reset_imports_status {
365
sub reset_imports_status {
312
    my ($self, $kernel, $heap, $session) = @_[OBJECT, KERNEL,HEAP,SESSION];
366
    my ($self, $kernel, $heap, $session) = @_[OBJECT, KERNEL,HEAP,SESSION];
313
367
314
    my $schema = Koha::Database->new()->schema();
368
    my $rs = Koha::OAI::Harvester::ImportQueues->new->search({
315
    my $rs = $schema->resultset('OaiHarvesterImportQueue')->search({
316
                status => "wip",
369
                status => "wip",
317
    });
370
    });
318
    $rs->update({
371
    $rs->update({
Lines 320-325 sub reset_imports_status { Link Here
320
    });
373
    });
321
}
374
}
322
375
376
=head2 restore_state
377
378
    Method to restore the harvester to a pre-existing state.
379
380
=cut
381
323
sub restore_state {
382
sub restore_state {
324
    my ($self, $kernel, $heap, $session) = @_[OBJECT, KERNEL,HEAP,SESSION];
383
    my ($self, $kernel, $heap, $session) = @_[OBJECT, KERNEL,HEAP,SESSION];
325
384
Lines 357-362 sub restore_state { Link Here
357
    }
416
    }
358
}
417
}
359
418
419
=head2 save_state
420
421
    Method to save the existing state of the harvester
422
423
=cut
424
360
sub save_state {
425
sub save_state {
361
    my ($self, $kernel, $heap, $session) = @_[OBJECT, KERNEL,HEAP,SESSION];
426
    my ($self, $kernel, $heap, $session) = @_[OBJECT, KERNEL,HEAP,SESSION];
362
    my $state_file = $self->{state_file};
427
    my $state_file = $self->{state_file};
Lines 385-391 sub save_state { Link Here
385
    return 0;
450
    return 0;
386
}
451
}
387
452
388
=head3 get_task
453
=head2 get_task
389
454
390
    This event handler returns a task from a harvester using the task's
455
    This event handler returns a task from a harvester using the task's
391
    uuid as an argument.
456
    uuid as an argument.
Lines 413-419 sub get_task { Link Here
413
    return 0;
478
    return 0;
414
}
479
}
415
480
416
=head3 get_import_count_for_task
481
=head2 get_import_count_for_task
482
483
    This gets the count of the number of imports exist for a certain task
417
484
418
=cut
485
=cut
419
486
Lines 421-428 sub get_import_count_for_task { Link Here
421
    my ($self,$uuid) = @_;
488
    my ($self,$uuid) = @_;
422
    my $count = undef;
489
    my $count = undef;
423
    if ($uuid){
490
    if ($uuid){
424
        my $schema = Koha::Database->new()->schema();
491
        my $items = Koha::OAI::Harvester::ImportQueues->new->search({
425
        my $items = $schema->resultset('OaiHarvesterImportQueue')->search({
426
            uuid => $uuid,
492
            uuid => $uuid,
427
        });
493
        });
428
        $count = $items->count;
494
        $count = $items->count;
Lines 430-436 sub get_import_count_for_task { Link Here
430
    return $count;
496
    return $count;
431
}
497
}
432
498
433
=head3 list_tasks
499
=head2 list_tasks
434
500
435
    This event handler returns a list of tasks that have been submitted
501
    This event handler returns a list of tasks that have been submitted
436
    to the harvester. It returns data like uuid, status, parameters,
502
    to the harvester. It returns data like uuid, status, parameters,
Lines 440-450 sub get_import_count_for_task { Link Here
440
506
441
sub list_tasks {
507
sub list_tasks {
442
    my ($self, $kernel, $heap, $session, $status) = @_[OBJECT, KERNEL,HEAP,SESSION, ARG0];
508
    my ($self, $kernel, $heap, $session, $status) = @_[OBJECT, KERNEL,HEAP,SESSION, ARG0];
443
    my $schema = Koha::Database->new()->schema();
444
    my @tasks = ();
509
    my @tasks = ();
445
    foreach my $uuid (sort keys %{$heap->{tasks}}){
510
    foreach my $uuid (sort keys %{$heap->{tasks}}){
446
        my $task = $heap->{tasks}->{$uuid};
511
        my $task = $heap->{tasks}->{$uuid};
447
        my $items = $schema->resultset('OaiHarvesterImportQueue')->search({
512
        my $items = Koha::OAI::Harvester::ImportQueues->new->search({
448
            uuid => $uuid,
513
            uuid => $uuid,
449
        });
514
        });
450
        my $count = $items->count // 0;
515
        my $count = $items->count // 0;
Lines 457-463 sub list_tasks { Link Here
457
    return \@tasks;
522
    return \@tasks;
458
}
523
}
459
524
460
=head3 create_task
525
=head2 create_task
461
526
462
    This event handler creates a spool directory for the task's imports.
527
    This event handler creates a spool directory for the task's imports.
463
    It also adds it to the harvester's memory and then saves memory to
528
    It also adds it to the harvester's memory and then saves memory to
Lines 502-508 sub create_task { Link Here
502
    return 0;
567
    return 0;
503
}
568
}
504
569
505
=head3 start_task
570
=head2 start_task
506
571
507
    This event handler marks a task as active in the harvester's memory,
572
    This event handler marks a task as active in the harvester's memory,
508
    save the memory to a persistent datastore, then enqueues the task,
573
    save the memory to a persistent datastore, then enqueues the task,
Lines 536-544 sub start_task { Link Here
536
    return 0;
601
    return 0;
537
}
602
}
538
603
539
=head3 repeat_task
604
=head2 repeat_task
540
541
605
606
    This method re-queues a task for downloading
542
607
543
=cut
608
=cut
544
609
Lines 553-559 sub repeat_task { Link Here
553
    }
618
    }
554
}
619
}
555
620
556
=head3 stop_task
621
=head2 stop_task
557
622
558
    This event handler prevents new workers from spawning, kills
623
    This event handler prevents new workers from spawning, kills
559
    existing workers, and stops pending imports from being imported.
624
    existing workers, and stops pending imports from being imported.
Lines 594-601 sub stop_task { Link Here
594
        }
659
        }
595
660
596
        #Step Three: stop pending imports for this task
661
        #Step Three: stop pending imports for this task
597
        my $schema = Koha::Database->new()->schema();
662
        my $items = Koha::OAI::Harvester::ImportQueues->new->search({
598
        my $items = $schema->resultset('OaiHarvesterImportQueue')->search({
599
            uuid => $task_uuid,
663
            uuid => $task_uuid,
600
        });
664
        });
601
        my $rows_updated = $items->update({
665
        my $rows_updated = $items->update({
Lines 609-615 sub stop_task { Link Here
609
    return 0;
673
    return 0;
610
}
674
}
611
675
612
=head3 delete_task
676
=head2 delete_task
613
677
614
    Deleted tasks are stopped, pending imports are deleted from the
678
    Deleted tasks are stopped, pending imports are deleted from the
615
    database and file system, and then the task is removed from the harvester.
679
    database and file system, and then the task is removed from the harvester.
Lines 625-632 sub delete_task { Link Here
625
        $kernel->call($session,"stop_task",$task_uuid);
689
        $kernel->call($session,"stop_task",$task_uuid);
626
690
627
        #Step Two: delete pending imports in database
691
        #Step Two: delete pending imports in database
628
        my $schema = Koha::Database->new()->schema();
692
        my $items = Koha::OAI::Harvester::ImportQueues->new->search({
629
        my $items = $schema->resultset('OaiHarvesterImportQueue')->search({
630
            uuid => $task_uuid,
693
            uuid => $task_uuid,
631
        });
694
        });
632
        if ($items){
695
        if ($items){
(-)a/Koha/OAI/Harvester/Biblio.pm (+49 lines)
Line 0 Link Here
1
package Koha::OAI::Harvester::Biblio;
2
3
# Copyright Prosentient Systems 2018
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use base qw(Koha::Object);
25
26
=head1 NAME
27
28
Koha::OAI::Harvester::Biblio
29
30
=head1 SYNOPSIS
31
32
    use Koha::OAI::Harvester::Biblio;
33
    my $biblio = Koha::OAI::Harvester::Biblios->find($id);
34
35
=head1 METHODS
36
37
=cut
38
39
sub _type {
40
    return 'OaiHarvesterBiblio';
41
}
42
43
=head1 AUTHOR
44
45
David Cook <dcook@prosentient.com.au>
46
47
=cut
48
49
1;
(-)a/Koha/OAI/Harvester/Biblios.pm (+60 lines)
Line 0 Link Here
1
package Koha::OAI::Harvester::Biblios;
2
3
# Copyright Prosentient Systems 2018
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use Koha::Database;
25
26
use Koha::OAI::Harvester::Biblio;
27
28
use base qw(Koha::Objects);
29
30
=head1 NAME
31
32
Koha::OAI::Harvester::Biblios
33
34
=head2 METHODS
35
36
=cut
37
38
=head3 _type
39
40
=cut
41
42
sub _type {
43
    return 'OaiHarvesterBiblio';
44
}
45
46
=head3 object_class
47
48
=cut
49
50
sub object_class {
51
    return 'Koha::OAI::Harvester::Biblio';
52
}
53
54
=head1 AUTHOR
55
56
David Cook <dcook@prosentient.com.au>
57
58
=cut
59
60
1;
(-)a/Koha/OAI/Harvester/Client.pm (-1 / +54 lines)
Lines 23-34 use IO::Socket::UNIX; Link Here
23
use IO::Select;
23
use IO::Select;
24
use JSON;
24
use JSON;
25
25
26
=head1 NAME
27
28
Koha::OAI::Harvester::Client
29
30
=head1 SYNOPSIS
31
32
  use Koha::OAI::Harvester::Client;
33
  my $client = Koha::OAI::Harvester::Client->new($client_config);
34
35
=head1 METHODS
36
37
=head2 new
38
39
Create object
40
41
=cut
42
26
sub new {
43
sub new {
27
    my ($class, $args) = @_;
44
    my ($class, $args) = @_;
28
    $args = {} unless defined $args;
45
    $args = {} unless defined $args;
29
    return bless ($args, $class);
46
    return bless ($args, $class);
30
}
47
}
31
48
49
=head2 connect
50
51
Connect to Koha::OAI::Harvester::Listener via a Unix socket
52
53
=cut
54
32
sub connect {
55
sub connect {
33
    my ($self) =  @_;
56
    my ($self) =  @_;
34
    my $socket_uri = $self->{socket_uri};
57
    my $socket_uri = $self->{socket_uri};
Lines 62-67 sub connect { Link Here
62
    return 0;
85
    return 0;
63
}
86
}
64
87
88
=head2 create
89
90
    Create a task on the harvester
91
92
=cut
93
65
sub create {
94
sub create {
66
    my ($self,$task) = @_;
95
    my ($self,$task) = @_;
67
    my $message = {
96
    my $message = {
Lines 74-79 sub create { Link Here
74
    return $status;
103
    return $status;
75
}
104
}
76
105
106
=head2 start
107
108
    Start a task on the harvester
109
110
=cut
111
77
sub start {
112
sub start {
78
    my ($self,$uuid) = @_;
113
    my ($self,$uuid) = @_;
79
    my $message = {
114
    my $message = {
Lines 88-93 sub start { Link Here
88
    return $status;
123
    return $status;
89
}
124
}
90
125
126
=head2 stop
127
128
    Stop a task on the harvester
129
130
=cut
131
91
sub stop {
132
sub stop {
92
    my ($self,$uuid) = @_;
133
    my ($self,$uuid) = @_;
93
    my $message = {
134
    my $message = {
Lines 102-107 sub stop { Link Here
102
    return $status;
143
    return $status;
103
}
144
}
104
145
146
=head2 delete
147
148
    Delete a task on the harvester
149
150
=cut
151
105
sub delete {
152
sub delete {
106
    my ($self,$uuid) = @_;
153
    my ($self,$uuid) = @_;
107
    my $message = {
154
    my $message = {
Lines 116-121 sub delete { Link Here
116
    return $status;
163
    return $status;
117
}
164
}
118
165
166
=head2 list
167
168
    List all tasks on the harvester
169
170
=cut
171
119
sub list {
172
sub list {
120
    my ($self) = @_;
173
    my ($self) = @_;
121
    my $message = {
174
    my $message = {
Lines 174-177 sub _read { Link Here
174
    }
227
    }
175
}
228
}
176
229
177
1;
230
1;
(-)a/Koha/OAI/Harvester/Downloader.pm (-3 / +30 lines)
Lines 23-31 use XML::LibXML::Reader; Link Here
23
use IO::Handle;
23
use IO::Handle;
24
use JSON;
24
use JSON;
25
25
26
=head1 API
26
=head1 NAME
27
27
28
=head2 Class Methods
28
Koha::OAI::Harvester::Downloader
29
30
=head1 SYNOPSIS
31
32
    use Koha::OAI::Harvester::Downloader;
33
    my $oai_downloader = Koha::OAI::Harvester::Downloader->new();
34
35
    This class is used within a Koha::OAI::Harvester::Work::Download:: module.
36
37
=head1 METHODS
38
39
=head2 new
40
41
    Create object
29
42
30
=cut
43
=cut
31
44
Lines 96-102 sub BuildURL { Link Here
96
    }
109
    }
97
}
110
}
98
111
99
=head2 OpenXMLStream
112
=head2 GetXMLStream
100
113
101
    Fork a child process to send the HTTP request, which sends chunks
114
    Fork a child process to send the HTTP request, which sends chunks
102
    of XML via a pipe to the parent process.
115
    of XML via a pipe to the parent process.
Lines 168-173 sub _request { Link Here
168
    }
181
    }
169
}
182
}
170
183
184
=head2 ParseXMLStream
185
186
    Parse XML using XML::LibXML::Reader from a file handle (e.g. a stream)
187
188
=cut
189
190
171
sub ParseXMLStream {
191
sub ParseXMLStream {
172
    my ($self, $args) = @_;
192
    my ($self, $args) = @_;
173
193
Lines 245-250 sub ParseXMLStream { Link Here
245
    }
265
    }
246
}
266
}
247
267
268
=head2 harvest
269
270
    Given a URL and a user-agent, start downloading OAI-PMH records from
271
    that URL.
272
273
=cut
274
248
sub harvest {
275
sub harvest {
249
    my ($self,$args) = @_;
276
    my ($self,$args) = @_;
250
    my $url = $args->{url};
277
    my $url = $args->{url};
(-)a/Koha/OAI/Harvester/Histories.pm (+60 lines)
Line 0 Link Here
1
package Koha::OAI::Harvester::Histories;
2
3
# Copyright Prosentient Systems 2018
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use Koha::Database;
25
26
use Koha::OAI::Harvester::History;
27
28
use base qw(Koha::Objects);
29
30
=head1 NAME
31
32
Koha::OAI::Harvester::Histories
33
34
=head2 METHODS
35
36
=cut
37
38
=head3 _type
39
40
=cut
41
42
sub _type {
43
    return 'OaiHarvesterHistory';
44
}
45
46
=head3 object_class
47
48
=cut
49
50
sub object_class {
51
    return 'Koha::OAI::Harvester::History';
52
}
53
54
=head1 AUTHOR
55
56
David Cook <dcook@prosentient.com.au>
57
58
=cut
59
60
1;
(-)a/Koha/OAI/Harvester/History.pm (+49 lines)
Line 0 Link Here
1
package Koha::OAI::Harvester::History;
2
3
# Copyright Prosentient Systems 2018
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use base qw(Koha::Object);
25
26
=head1 NAME
27
28
Koha::OAI::Harvester::History
29
30
=head1 SYNOPSIS
31
32
    use Koha::OAI::Harvester::History;
33
    my $request = Koha::OAI::Harvester::History->find($id);
34
35
=head1 METHODS
36
37
=cut
38
39
sub _type {
40
    return 'OaiHarvesterHistory';
41
}
42
43
=head1 AUTHOR
44
45
David Cook <dcook@prosentient.com.au>
46
47
=cut
48
49
1;
(-)a/Koha/OAI/Harvester/Import/MARCXML.pm (+23 lines)
Lines 26-31 use C4::Biblio; Link Here
26
26
27
use constant MAX_MATCHES => 99999; #NOTE: This is an arbitrary value. We want to get all matches.
27
use constant MAX_MATCHES => 99999; #NOTE: This is an arbitrary value. We want to get all matches.
28
28
29
=head1 NAME
30
31
Koha::OAI::Harvester::Import::MARCXML
32
33
=head1 SYNOPSIS
34
35
    use Koha::OAI::Harvester::Import::MARCXML;
36
    my $marcxml = eval { Koha::OAI::Harvester::Import::MARCXML->new({ dom => $results, }) };
37
38
=head1 METHODS
39
40
=head2 new
41
42
    Create object
43
44
=cut
45
29
sub new {
46
sub new {
30
    my ($class, $args) = @_;
47
    my ($class, $args) = @_;
31
    $args = {} unless defined $args;
48
    $args = {} unless defined $args;
Lines 47-52 sub new { Link Here
47
    return bless ($args, $class);
64
    return bless ($args, $class);
48
}
65
}
49
66
67
=head2 import_record
68
69
    Import a record into Koha
70
71
=cut
72
50
sub import_record {
73
sub import_record {
51
    my ($self,$args) = @_;
74
    my ($self,$args) = @_;
52
    my $framework = $args->{framework};
75
    my $framework = $args->{framework};
(-)a/Koha/OAI/Harvester/Import/Record.pm (-11 / +58 lines)
Lines 27-42 use File::Basename; Link Here
27
use C4::Context;
27
use C4::Context;
28
use C4::Biblio;
28
use C4::Biblio;
29
29
30
use Koha::Database;
31
use Koha::OAI::Harvester::Import::MARCXML;
30
use Koha::OAI::Harvester::Import::MARCXML;
31
use Koha::OAI::Harvester::Biblios;
32
use Koha::OAI::Harvester::History;
32
33
33
=head1 API
34
=head1 NAME
34
35
35
=head2 Class Methods
36
Koha::OAI::Harvester::Import::Record
36
37
37
=cut
38
=head1 SYNOPSIS
39
40
    use Koha::OAI::Harvester::Import::Record;
41
    my $oai_record = Koha::OAI::Harvester::Import::Record->new({
42
        doc => $dom,
43
        repository => $repository,
44
    });
45
46
=head1 METHODS
38
47
39
my $schema = Koha::Database->new()->schema();
48
=head2 new
49
50
    Create object
51
52
=cut
40
53
41
sub new {
54
sub new {
42
    my ($class, $args) = @_;
55
    my ($class, $args) = @_;
Lines 70-75 sub new { Link Here
70
    return bless ($args, $class);
83
    return bless ($args, $class);
71
}
84
}
72
85
86
=head2 is_deleted_upstream
87
88
    Returns true if OAI-PMH record is deleted upstream
89
90
=cut
91
73
sub is_deleted_upstream {
92
sub is_deleted_upstream {
74
    my ($self, $args) = @_;
93
    my ($self, $args) = @_;
75
    if ($self->{header_status}){
94
    if ($self->{header_status}){
Lines 80-85 sub is_deleted_upstream { Link Here
80
    return 0;
99
    return 0;
81
}
100
}
82
101
102
=head2 set_filter
103
104
    $self->set_filter("/path/to/filter.xsl");
105
106
    Set a XSLT to use to filter records on import. This
107
    takes a full filepath as an argument.
108
109
=cut
110
83
sub set_filter {
111
sub set_filter {
84
    my ($self, $filter_definition) = @_;
112
    my ($self, $filter_definition) = @_;
85
113
Lines 121-126 sub _parse_filter { Link Here
121
    return ($type,$filter);
149
    return ($type,$filter);
122
}
150
}
123
151
152
=head2 filter
153
154
    Filters the OAI-PMH record using a filter
155
156
=cut
157
124
sub filter {
158
sub filter {
125
    my ($self) = @_;
159
    my ($self) = @_;
126
    my $filtered = 0;
160
    my $filtered = 0;
Lines 165-171 sub _find_koha_link { Link Here
165
    my $record_type = $args->{record_type} // "biblio";
199
    my $record_type = $args->{record_type} // "biblio";
166
    my $link_id;
200
    my $link_id;
167
    if ($record_type eq "biblio"){
201
    if ($record_type eq "biblio"){
168
        my $link = $schema->resultset('OaiHarvesterBiblio')->find(
202
        my $link = Koha::OAI::Harvester::Biblios->new->find(
169
            {
203
            {
170
                oai_repository => $self->{repository},
204
                oai_repository => $self->{repository},
171
                oai_identifier => $self->{header_identifier},
205
                oai_identifier => $self->{header_identifier},
Lines 173-185 sub _find_koha_link { Link Here
173
            { key => "oai_record",}
207
            { key => "oai_record",}
174
        );
208
        );
175
        if ($link && $link->biblionumber){
209
        if ($link && $link->biblionumber){
176
            $link_id = $link->biblionumber->id;
210
            $link_id = $link->biblionumber;
177
        }
211
        }
178
    }
212
    }
179
    return $link_id;
213
    return $link_id;
180
}
214
}
181
215
182
=head3 import_record
216
=head2 import_record
183
217
184
    my ($action,$record_id) = $oai_record->import_record({
218
    my ($action,$record_id) = $oai_record->import_record({
185
        filter => $filter,
219
        filter => $filter,
Lines 246-252 sub import_record { Link Here
246
    }
280
    }
247
281
248
    #Log record details to database
282
    #Log record details to database
249
    my $importer = $schema->resultset('OaiHarvesterHistory')->create({
283
    Koha::OAI::Harvester::History->new({
250
        header_identifier => $self->{header_identifier},
284
        header_identifier => $self->{header_identifier},
251
        header_datestamp => $self->{header_datestamp},
285
        header_datestamp => $self->{header_datestamp},
252
        header_status => $self->{header_status},
286
        header_status => $self->{header_status},
Lines 257-274 sub import_record { Link Here
257
        framework => $framework,
291
        framework => $framework,
258
        record_type => $record_type,
292
        record_type => $record_type,
259
        matcher_code => $matcher ? $matcher->code : undef,
293
        matcher_code => $matcher ? $matcher->code : undef,
260
    });
294
    })->store();
261
295
262
    return ($action,$linked_id);
296
    return ($action,$linked_id);
263
}
297
}
264
298
299
=head2 link_koha_record
300
301
    Link an OAI-PMH record with a Koha record using
302
    the OAI-PMH repository and OAI-PMH identifier
303
304
=cut
305
265
sub link_koha_record {
306
sub link_koha_record {
266
    my ($self, $args) = @_;
307
    my ($self, $args) = @_;
267
    my $record_type = $args->{record_type} // "biblio";
308
    my $record_type = $args->{record_type} // "biblio";
268
    my $koha_id = $args->{koha_id};
309
    my $koha_id = $args->{koha_id};
269
    if ($koha_id){
310
    if ($koha_id){
270
        if ($record_type eq "biblio"){
311
        if ($record_type eq "biblio"){
271
            my $import_oai_biblio = $schema->resultset('OaiHarvesterBiblio')->find_or_create({
312
            my $import_oai_biblio = Koha::OAI::Harvester::Biblios->new->find_or_create({
272
                oai_repository => $self->{repository},
313
                oai_repository => $self->{repository},
273
                oai_identifier => $self->{header_identifier},
314
                oai_identifier => $self->{header_identifier},
274
                biblionumber => $koha_id,
315
                biblionumber => $koha_id,
Lines 280-285 sub link_koha_record { Link Here
280
    }
321
    }
281
}
322
}
282
323
324
=head2 delete_koha_record
325
326
    Delete a Koha record
327
328
=cut
329
283
sub delete_koha_record {
330
sub delete_koha_record {
284
    my ($self, $args) = @_;
331
    my ($self, $args) = @_;
285
    my $record_type = $args->{record_type} // "biblio";
332
    my $record_type = $args->{record_type} // "biblio";
(-)a/Koha/OAI/Harvester/ImportQueue.pm (+49 lines)
Line 0 Link Here
1
package Koha::OAI::Harvester::ImportQueue;
2
3
# Copyright Prosentient Systems 2018
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use base qw(Koha::Object);
25
26
=head1 NAME
27
28
Koha::OAI::Harvester::ImportQueue
29
30
=head1 SYNOPSIS
31
32
    use Koha::OAI::Harvester::ImportQueue;
33
    my $request = Koha::OAI::Harvester::ImportQueue->find($id);
34
35
=head1 METHODS
36
37
=cut
38
39
sub _type {
40
    return 'OaiHarvesterImportQueue';
41
}
42
43
=head1 AUTHOR
44
45
David Cook <dcook@prosentient.com.au>
46
47
=cut
48
49
1;
(-)a/Koha/OAI/Harvester/ImportQueues.pm (+60 lines)
Line 0 Link Here
1
package Koha::OAI::Harvester::ImportQueues;
2
3
# Copyright Prosentient Systems 2018
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use Koha::Database;
25
26
use Koha::OAI::Harvester::ImportQueue;
27
28
use base qw(Koha::Objects);
29
30
=head1 NAME
31
32
Koha::OAI::Harvester::ImportQueues
33
34
=head2 METHODS
35
36
=cut
37
38
=head3 _type
39
40
=cut
41
42
sub _type {
43
    return 'OaiHarvesterImportQueue';
44
}
45
46
=head3 object_class
47
48
=cut
49
50
sub object_class {
51
    return 'Koha::OAI::Harvester::ImportQueue';
52
}
53
54
=head1 AUTHOR
55
56
David Cook <dcook@prosentient.com.au>
57
58
=cut
59
60
1;
(-)a/Koha/OAI/Harvester/Listener.pm (+56 lines)
Lines 24-35 use IO::Socket qw(AF_UNIX); Link Here
24
use JSON;
24
use JSON;
25
use URI;
25
use URI;
26
26
27
=head1 NAME
28
29
Koha::OAI::Harvester::Listener
30
31
=head1 SYNOPSIS
32
33
    use Koha::OAI::Harvester::Listener;
34
    my $listener = Koha::OAI::Harvester::Listener->spawn({
35
        logger => $logger,
36
        socket => $socket_addr,
37
    });
38
39
=head1 METHODS
40
41
=head2 new
42
43
    Create object
44
45
=cut
46
27
sub new {
47
sub new {
28
    my ($class, $args) = @_;
48
    my ($class, $args) = @_;
29
    $args = {} unless defined $args;
49
    $args = {} unless defined $args;
30
    return bless ($args, $class);
50
    return bless ($args, $class);
31
}
51
}
32
52
53
=head2 spawn
54
55
    Create POE session for listener
56
57
=cut
58
33
sub spawn {
59
sub spawn {
34
    my ($class, $args) = @_;
60
    my ($class, $args) = @_;
35
    my $self = $class->new($args);
61
    my $self = $class->new($args);
Lines 50-55 sub spawn { Link Here
50
    );
76
    );
51
}
77
}
52
78
79
=head2 on_start
80
81
    Internal method for starting listener
82
83
=cut
84
53
sub on_start {
85
sub on_start {
54
    my ($kernel,$heap,$socket_uri) = @_[KERNEL,HEAP,ARG0];
86
    my ($kernel,$heap,$socket_uri) = @_[KERNEL,HEAP,ARG0];
55
87
Lines 69-74 sub on_start { Link Here
69
    }
101
    }
70
}
102
}
71
103
104
=head2 on_server_success
105
106
    Internal event handler for successful connection to server
107
108
=cut
109
72
sub on_server_success {
110
sub on_server_success {
73
    my ($self, $client_socket, $server_wheel_id, $heap, $session) = @_[OBJECT, ARG0, ARG3, HEAP,SESSION];
111
    my ($self, $client_socket, $server_wheel_id, $heap, $session) = @_[OBJECT, ARG0, ARG3, HEAP,SESSION];
74
    my $logger = $self->{logger};
112
    my $logger = $self->{logger};
Lines 88-93 sub on_server_success { Link Here
88
    $client_wheel->put("HELLO");
126
    $client_wheel->put("HELLO");
89
}
127
}
90
128
129
=head2 on_server_error
130
131
    Internal event handler for server errors
132
133
=cut
134
91
sub on_server_error {
135
sub on_server_error {
92
    my ($self, $operation, $errnum, $errstr, $heap, $session) = @_[OBJECT, ARG0, ARG1, ARG2,HEAP, SESSION];
136
    my ($self, $operation, $errnum, $errstr, $heap, $session) = @_[OBJECT, ARG0, ARG1, ARG2,HEAP, SESSION];
93
    my $logger = $self->{logger};
137
    my $logger = $self->{logger};
Lines 95-100 sub on_server_error { Link Here
95
    delete $heap->{server};
139
    delete $heap->{server};
96
}
140
}
97
141
142
=head2 on_client_error
143
144
    Internal event handler for errors relating to the client connection
145
146
=cut
147
98
sub on_client_error {
148
sub on_client_error {
99
    my ($self, $wheel_id,$heap,$session) = @_[OBJECT, ARG3,HEAP,SESSION];
149
    my ($self, $wheel_id,$heap,$session) = @_[OBJECT, ARG3,HEAP,SESSION];
100
    my $logger = $self->{logger};
150
    my $logger = $self->{logger};
Lines 102-107 sub on_client_error { Link Here
102
    delete $heap->{client}->{$wheel_id};
152
    delete $heap->{client}->{$wheel_id};
103
}
153
}
104
154
155
=head2 on_client_input
156
157
    Internal event handler for input from clients
158
159
=cut
160
105
sub on_client_input {
161
sub on_client_input {
106
    my ($self, $input, $wheel_id, $session, $kernel, $heap) = @_[OBJECT, ARG0, ARG1, SESSION, KERNEL, HEAP];
162
    my ($self, $input, $wheel_id, $session, $kernel, $heap) = @_[OBJECT, ARG0, ARG1, SESSION, KERNEL, HEAP];
107
    my $logger = $self->{logger};
163
    my $logger = $self->{logger};
(-)a/Koha/OAI/Harvester/Request.pm (-8 / +11 lines)
Lines 29-45 use HTTP::OAI; Link Here
29
29
30
=head1 NAME
30
=head1 NAME
31
31
32
Koha::OAI::Harvester::Request -
32
Koha::OAI::Harvester::Request
33
33
34
=head1 API
34
=head1 SYNOPSIS
35
35
36
=head2 Class Methods
36
    use Koha::OAI::Harvester::Request;
37
    my $request = Koha::OAI::Harvester::Requests->find($id);
37
38
38
=cut
39
=head1 METHODS
39
40
41
42
=head3 _type
43
40
44
=cut
41
=cut
45
42
Lines 47-52 sub _type { Link Here
47
    return 'OaiHarvesterRequest';
44
    return 'OaiHarvesterRequest';
48
}
45
}
49
46
47
=head2 validate
48
49
    Method to validate the parameters of an OAI-PMH request
50
51
=cut
52
50
sub validate {
53
sub validate {
51
    my ($self) = @_;
54
    my ($self) = @_;
52
    my $errors = {};
55
    my $errors = {};
(-)a/Koha/OAI/Harvester/Worker.pm (+59 lines)
Lines 22-27 use POE; Link Here
22
use DateTime;
22
use DateTime;
23
use JSON;
23
use JSON;
24
24
25
=head1 NAME
26
27
Koha::OAI::Harvester::Worker
28
29
=head1 SYNOPSIS
30
31
    This is just a base class to use when writing workers for
32
    the OAI-PMH harvester.
33
34
=head1 METHODS
35
36
=head2 new
37
38
    Create object
39
40
=cut
41
25
sub new {
42
sub new {
26
    my ($class, $args) = @_;
43
    my ($class, $args) = @_;
27
    $args = {} unless defined $args;
44
    $args = {} unless defined $args;
Lines 29-34 sub new { Link Here
29
    return bless ($args, $class);
46
    return bless ($args, $class);
30
}
47
}
31
48
49
=head2 run
50
51
    The entry point to getting a worker to process a task
52
53
=cut
54
32
sub run {
55
sub run {
33
    my ($self,$args) = @_;
56
    my ($self,$args) = @_;
34
    my $postback = $args->{postback};
57
    my $postback = $args->{postback};
Lines 53-58 sub run { Link Here
53
    );
76
    );
54
}
77
}
55
78
79
=head2 stop_worker
80
81
    Internal method for killing this worker's child processes
82
83
=cut
84
56
sub stop_worker {
85
sub stop_worker {
57
    my ($self,$heap) = @_[OBJECT,HEAP];
86
    my ($self,$heap) = @_[OBJECT,HEAP];
58
    if (my $child_processes = $heap->{children_by_pid}){
87
    if (my $child_processes = $heap->{children_by_pid}){
Lines 63-68 sub stop_worker { Link Here
63
    }
92
    }
64
}
93
}
65
94
95
=head2 on_stop
96
97
    Internal event handler for deregistering the worker session
98
    from the harvester's roster of workers
99
100
=cut
66
101
67
sub on_stop {
102
sub on_stop {
68
    my ($self,$kernel) = @_[OBJECT,KERNEL];
103
    my ($self,$kernel) = @_[OBJECT,KERNEL];
Lines 71-76 sub on_stop { Link Here
71
    $kernel->call("harvester","deregister",$self->{type});
106
    $kernel->call("harvester","deregister",$self->{type});
72
}
107
}
73
108
109
=head2 on_child_stdout
110
111
    Internal event handler for reading output from a child process
112
113
=cut
114
74
# Wheel event, including the wheel's ID.
115
# Wheel event, including the wheel's ID.
75
sub on_child_stdout {
116
sub on_child_stdout {
76
    my ($self, $stdout_line, $wheel_id) = @_[OBJECT, ARG0, ARG1];
117
    my ($self, $stdout_line, $wheel_id) = @_[OBJECT, ARG0, ARG1];
Lines 92-97 sub on_child_stdout { Link Here
92
    }
133
    }
93
}
134
}
94
135
136
=head2 on_child_stderr
137
138
    Internal event handler for reading errors from a child process
139
140
=cut
141
95
# Wheel event, including the wheel's ID.
142
# Wheel event, including the wheel's ID.
96
sub on_child_stderr {
143
sub on_child_stderr {
97
    my ($self,$stderr_line, $wheel_id) = @_[OBJECT, ARG0, ARG1];
144
    my ($self,$stderr_line, $wheel_id) = @_[OBJECT, ARG0, ARG1];
Lines 103-108 sub on_child_stderr { Link Here
103
    }
150
    }
104
}
151
}
105
152
153
=head2 on_child_close
154
155
    Internal event handler for when a child closes its pipes
156
157
=cut
158
106
# Wheel event, including the wheel's ID.
159
# Wheel event, including the wheel's ID.
107
sub on_child_close {
160
sub on_child_close {
108
    my ($self,$heap,$wheel_id) = @_[OBJECT,HEAP,ARG0];
161
    my ($self,$heap,$wheel_id) = @_[OBJECT,HEAP,ARG0];
Lines 124-129 sub on_child_close { Link Here
124
    delete $heap->{children_by_pid}->{$child->PID};
177
    delete $heap->{children_by_pid}->{$child->PID};
125
}
178
}
126
179
180
=head2 on_child_signal
181
182
    Internal event handler for when a child exits
183
184
=cut
185
127
sub on_child_signal {
186
sub on_child_signal {
128
    my ($self,$kernel,$pid,$status) = @_[OBJECT,KERNEL,ARG1,ARG2];
187
    my ($self,$kernel,$pid,$status) = @_[OBJECT,KERNEL,ARG1,ARG2];
129
    my $type = $self->{type};
188
    my $type = $self->{type};
(-)a/Koha/OAI/Harvester/Worker/Download/Stream.pm (+30 lines)
Lines 28-33 use C4::Context; Link Here
28
use Koha::OAI::Harvester::Downloader;
28
use Koha::OAI::Harvester::Downloader;
29
use parent 'Koha::OAI::Harvester::Worker';
29
use parent 'Koha::OAI::Harvester::Worker';
30
30
31
=head1 NAME
32
33
Koha::OAI::Harvester::Worker::Download::Stream
34
35
=head1 SYNOPSIS
36
37
    This is a module used by the OAI-PMH harvester internally.
38
39
    As a bare minimum, it must define an "on_start" method.
40
41
=head1 METHODS
42
43
=head2 new
44
45
    Create object
46
47
=cut
48
31
sub new {
49
sub new {
32
    my ($class, $args) = @_;
50
    my ($class, $args) = @_;
33
    $args = {} unless defined $args;
51
    $args = {} unless defined $args;
Lines 35-40 sub new { Link Here
35
    return bless ($args, $class);
53
    return bless ($args, $class);
36
}
54
}
37
55
56
=head2 on_start
57
58
    Internal event handler for starting the processing of a task
59
60
=cut
61
38
sub on_start {
62
sub on_start {
39
    my ($self, $kernel, $heap, $postback,$task,$session) = @_[OBJECT, KERNEL, HEAP, ARG0,ARG1,SESSION];
63
    my ($self, $kernel, $heap, $postback,$task,$session) = @_[OBJECT, KERNEL, HEAP, ARG0,ARG1,SESSION];
40
    #Save postback into heap so other event handlers can use it
64
    #Save postback into heap so other event handlers can use it
Lines 71-76 sub on_start { Link Here
71
    }
95
    }
72
}
96
}
73
97
98
=head2 do_work
99
100
    Internal method for processing a download task
101
102
=cut
103
74
sub do_work {
104
sub do_work {
75
    my ($self, $task) = @_;
105
    my ($self, $task) = @_;
76
    my $batch = ( $self->{batch} && int($self->{batch}) ) ? $self->{batch} : 100;
106
    my $batch = ( $self->{batch} && int($self->{batch}) ) ? $self->{batch} : 100;
(-)a/Koha/OAI/Harvester/Worker/Import.pm (+24 lines)
Lines 28-33 use Koha::OAI::Harvester::Import::Record; Link Here
28
28
29
use parent 'Koha::OAI::Harvester::Worker';
29
use parent 'Koha::OAI::Harvester::Worker';
30
30
31
=head1 NAME
32
33
Koha::OAI::Harvester::Worker::Import
34
35
=head1 SYNOPSIS
36
37
    This is a module used by the OAI-PMH harvester internally.
38
39
    As a bare minimum, it must define an "on_start" method.
40
41
=head1 METHODS
42
43
=head2 new
44
45
     Create object
46
47
=cut
48
31
sub new {
49
sub new {
32
    my ($class, $args) = @_;
50
    my ($class, $args) = @_;
33
    $args = {} unless defined $args;
51
    $args = {} unless defined $args;
Lines 36-41 sub new { Link Here
36
    return bless ($args, $class);
54
    return bless ($args, $class);
37
}
55
}
38
56
57
=head2 on_start
58
59
    Internal event handler for starting the processing of a task
60
61
=cut
62
39
sub on_start {
63
sub on_start {
40
    my ($self, $kernel, $heap, $postback,$task) = @_[OBJECT, KERNEL, HEAP, ARG0,ARG1];
64
    my ($self, $kernel, $heap, $postback,$task) = @_[OBJECT, KERNEL, HEAP, ARG0,ARG1];
41
65
(-)a/Koha/Schema/Result/Biblio.pm (-2 / +17 lines)
Lines 242-247 __PACKAGE__->has_many( Link Here
242
  { cascade_copy => 0, cascade_delete => 0 },
242
  { cascade_copy => 0, cascade_delete => 0 },
243
);
243
);
244
244
245
=head2 oai_harvester_biblios
246
247
Type: has_many
248
249
Related object: L<Koha::Schema::Result::OaiHarvesterBiblio>
250
251
=cut
252
253
__PACKAGE__->has_many(
254
  "oai_harvester_biblios",
255
  "Koha::Schema::Result::OaiHarvesterBiblio",
256
  { "foreign.biblionumber" => "self.biblionumber" },
257
  { cascade_copy => 0, cascade_delete => 0 },
258
);
259
245
=head2 old_reserves
260
=head2 old_reserves
246
261
247
Type: has_many
262
Type: has_many
Lines 348-354 __PACKAGE__->has_many( Link Here
348
);
363
);
349
364
350
365
351
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-02-16 17:54:53
366
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-10-31 05:45:15
352
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:bUv00JjY09Hj2Zj4klqyxA
367
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ptt942qUu2GcGqOTRePNWQ
353
368
354
1;
369
1;
(-)a/Koha/Schema/Result/OaiHarvesterBiblio.pm (-2 / +2 lines)
Lines 112-119 __PACKAGE__->belongs_to( Link Here
112
);
112
);
113
113
114
114
115
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-29 12:23:43
115
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-10-31 05:53:48
116
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2URn8tPABMKC+JuIMfGeYw
116
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:awQgyVvOqnfBrOhl6tecBQ
117
117
118
118
119
# You can replace this text with custom code or comments, and it will be preserved on regeneration
119
# You can replace this text with custom code or comments, and it will be preserved on regeneration
(-)a/Koha/Schema/Result/OaiHarvesterHistory.pm (-2 / +2 lines)
Lines 155-162 __PACKAGE__->add_columns( Link Here
155
__PACKAGE__->set_primary_key("import_oai_id");
155
__PACKAGE__->set_primary_key("import_oai_id");
156
156
157
157
158
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-29 12:23:43
158
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-10-31 05:53:48
159
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Rp/ZEZsKVlLo2vaM3M37ow
159
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:C/ETSPdx0O4xfQnu09kGeQ
160
160
161
161
162
# You can replace this text with custom code or comments, and it will be preserved on regeneration
162
# You can replace this text with custom code or comments, and it will be preserved on regeneration
(-)a/Koha/Schema/Result/OaiHarvesterImportQueue.pm (-2 / +2 lines)
Lines 98-105 __PACKAGE__->add_columns( Link Here
98
__PACKAGE__->set_primary_key("id");
98
__PACKAGE__->set_primary_key("id");
99
99
100
100
101
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-29 12:23:43
101
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-10-31 05:53:48
102
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:zBD+hMawbvu7sonuLRHnCA
102
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1+ziAxPsvC8ftKLEAJ2keA
103
103
104
104
105
# You can replace this text with custom code or comments, and it will be preserved on regeneration
105
# You can replace this text with custom code or comments, and it will be preserved on regeneration
(-)a/Koha/Schema/Result/OaiHarvesterRequest.pm (-2 / +2 lines)
Lines 201-208 __PACKAGE__->add_columns( Link Here
201
__PACKAGE__->set_primary_key("id");
201
__PACKAGE__->set_primary_key("id");
202
202
203
203
204
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-04-07 11:26:24
204
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-10-31 05:53:48
205
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Vm/b4yurmr8WF7z+Fo6KEw
205
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:adGx1Jo2gvt5PH1eX31y2Q
206
206
207
207
208
# You can replace this text with custom code or comments, and it will be preserved on regeneration
208
# You can replace this text with custom code or comments, and it will be preserved on regeneration
(-)a/admin/columns_settings.yml (+59 lines)
Lines 675-680 modules: Link Here
675
          columnname: spent
675
          columnname: spent
676
676
677
  tools:
677
  tools:
678
    oai-pmh-harvester-dashboard:
679
      saved-table:
680
        -
681
          columnname: name
682
        -
683
          columnname: url
684
        -
685
          columnname: set
686
        -
687
          columnname: from
688
        -
689
          columnname: until
690
        -
691
          columnname: interval
692
693
      submitted-table:
694
        -
695
          columnname: name
696
        -
697
          columnname: url
698
        -
699
          columnname: set
700
        -
701
          columnname: from
702
        -
703
          columnname: until
704
        -
705
          columnname: interval
706
        -
707
          columnname: "effective from"
708
        -
709
          columnname: "effective until"
710
        -
711
          columnname: "pending imports"
712
        -
713
          columnname: status
714
        -
715
          columnname: error
716
717
      history-table:
718
        -
719
          columnname: id
720
        -
721
          columnname: repository
722
        -
723
          columnname: identifier
724
        -
725
          columnname: datestamp
726
        -
727
          columnname: "upstream status"
728
        -
729
          columnname: "import status"
730
        -
731
          columnname: "import timestamp"
732
        -
733
          columnname: "imported record"
734
        -
735
          columnname: "downloaded record"
736
678
    notices:
737
    notices:
679
      lettert:
738
      lettert:
680
        -
739
        -
(-)a/installer/data/mysql/atomicupdate/bug_10662.sql (-4 / +4 lines)
Lines 11-17 CREATE TABLE IF NOT EXISTS `oai_harvester_biblios` ( Link Here
11
  UNIQUE KEY `oai_record` (`oai_identifier`,`oai_repository`) USING BTREE,
11
  UNIQUE KEY `oai_record` (`oai_identifier`,`oai_repository`) USING BTREE,
12
  KEY `FK_import_oai_biblio_1` (`biblionumber`),
12
  KEY `FK_import_oai_biblio_1` (`biblionumber`),
13
  CONSTRAINT `FK_import_oai_biblio_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE NO ACTION
13
  CONSTRAINT `FK_import_oai_biblio_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE NO ACTION
14
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
14
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
15
15
16
--
16
--
17
-- Table structure for table 'oai_harvester_history'
17
-- Table structure for table 'oai_harvester_history'
Lines 31-37 CREATE TABLE IF NOT EXISTS `oai_harvester_history` ( Link Here
31
  `record_type` enum('biblio','auth','holdings') COLLATE utf8_unicode_ci NOT NULL,
31
  `record_type` enum('biblio','auth','holdings') COLLATE utf8_unicode_ci NOT NULL,
32
  `matcher_code` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
32
  `matcher_code` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
33
  PRIMARY KEY (`import_oai_id`)
33
  PRIMARY KEY (`import_oai_id`)
34
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
34
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
35
35
36
--
36
--
37
-- Table structure for table 'oai_harvester_import_queue'
37
-- Table structure for table 'oai_harvester_import_queue'
Lines 44-50 CREATE TABLE IF NOT EXISTS `oai_harvester_import_queue` ( Link Here
44
  `result` text CHARACTER SET utf8 NOT NULL,
44
  `result` text CHARACTER SET utf8 NOT NULL,
45
  `result_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
45
  `result_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
46
  PRIMARY KEY (`id`)
46
  PRIMARY KEY (`id`)
47
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
47
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
48
48
49
--
49
--
50
-- Table structure for table 'oai_harvester_requests'
50
-- Table structure for table 'oai_harvester_requests'
Lines 70-73 CREATE TABLE IF NOT EXISTS `oai_harvester_requests` ( Link Here
70
  `interval` int(10) unsigned NOT NULL,
70
  `interval` int(10) unsigned NOT NULL,
71
  `name` varchar(45) NOT NULL,
71
  `name` varchar(45) NOT NULL,
72
  PRIMARY KEY (`id`)
72
  PRIMARY KEY (`id`)
73
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
73
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
(-)a/installer/data/mysql/kohastructure.sql (-4 / +4 lines)
Lines 4331-4337 CREATE TABLE IF NOT EXISTS `oai_harvester_biblios` ( Link Here
4331
  UNIQUE KEY `oai_record` (`oai_identifier`,`oai_repository`) USING BTREE,
4331
  UNIQUE KEY `oai_record` (`oai_identifier`,`oai_repository`) USING BTREE,
4332
  KEY `FK_import_oai_biblio_1` (`biblionumber`),
4332
  KEY `FK_import_oai_biblio_1` (`biblionumber`),
4333
  CONSTRAINT `FK_import_oai_biblio_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE NO ACTION
4333
  CONSTRAINT `FK_import_oai_biblio_1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE NO ACTION
4334
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
4334
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4335
4335
4336
--
4336
--
4337
-- Table structure for table 'oai_harvester_history'
4337
-- Table structure for table 'oai_harvester_history'
Lines 4351-4357 CREATE TABLE IF NOT EXISTS `oai_harvester_history` ( Link Here
4351
  `record_type` enum('biblio','auth','holdings') COLLATE utf8_unicode_ci NOT NULL,
4351
  `record_type` enum('biblio','auth','holdings') COLLATE utf8_unicode_ci NOT NULL,
4352
  `matcher_code` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
4352
  `matcher_code` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
4353
  PRIMARY KEY (`import_oai_id`)
4353
  PRIMARY KEY (`import_oai_id`)
4354
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
4354
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4355
4355
4356
--
4356
--
4357
-- Table structure for table 'oai_harvester_import_queue'
4357
-- Table structure for table 'oai_harvester_import_queue'
Lines 4364-4370 CREATE TABLE IF NOT EXISTS `oai_harvester_import_queue` ( Link Here
4364
  `result` text CHARACTER SET utf8 NOT NULL,
4364
  `result` text CHARACTER SET utf8 NOT NULL,
4365
  `result_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
4365
  `result_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
4366
  PRIMARY KEY (`id`)
4366
  PRIMARY KEY (`id`)
4367
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
4367
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4368
4368
4369
--
4369
--
4370
-- Table structure for table 'oai_harvester_requests'
4370
-- Table structure for table 'oai_harvester_requests'
Lines 4390-4396 CREATE TABLE IF NOT EXISTS `oai_harvester_requests` ( Link Here
4390
  `interval` int(10) unsigned NOT NULL,
4390
  `interval` int(10) unsigned NOT NULL,
4391
  `name` varchar(45) NOT NULL,
4391
  `name` varchar(45) NOT NULL,
4392
  PRIMARY KEY (`id`)
4392
  PRIMARY KEY (`id`)
4393
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
4393
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4394
4394
4395
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
4395
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
4396
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
4396
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/dashboard.tt (-133 / +142 lines)
Lines 1-107 Link Here
1
[% USE ColumnsSettings %]
2
[% SET footerjs = 1 %]
1
[% INCLUDE 'doc-head-open.inc' %]
3
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Tools &rsaquo; OAI-PMH harvester</title>
4
<title>Koha &rsaquo; Tools &rsaquo; OAI-PMH harvester</title>
3
[% INCLUDE 'doc-head-close.inc' %]
5
[% INCLUDE 'doc-head-close.inc' %]
4
[% INCLUDE 'datatables.inc' %]
5
[% dashboard_page = '/cgi-bin/koha/tools/oai-pmh-harvester/dashboard.pl' %]
6
[% dashboard_page = '/cgi-bin/koha/tools/oai-pmh-harvester/dashboard.pl' %]
6
[% request_page = '/cgi-bin/koha/tools/oai-pmh-harvester/request.pl' %]
7
[% request_page = '/cgi-bin/koha/tools/oai-pmh-harvester/request.pl' %]
7
<script type="text/javascript">
8
//<![CDATA[
9
    $(document).ready(function() {
10
        $('#dashboard-items').tabs();
11
        [% IF ( result.start.defined || result.stop.defined || result.delete.defined ) %]
12
            $('#dashboard-items').tabs("option","active",1);
13
        [% END %]
14
15
        var saved_table = $('#saved-table').DataTable({});
16
        var submitted_table = $('#submitted-table').DataTable({});
17
        var history_table = $('#history-table').DataTable({
18
            serverSide: true,
19
            searching: true,
20
            processing: true,
21
            ajax: {
22
                "url": '/cgi-bin/koha/svc/oai-pmh-harvester/history',
23
                contentType: 'application/json',
24
                type: 'POST',
25
                data: function ( d ) {
26
                    return JSON.stringify( d );
27
                },
28
                dataSrc: function (json){
29
                    var recordsTotal = json.recordsTotal;
30
                    if(recordsTotal){
31
                        $('#import_count').text( "("+recordsTotal+")" );
32
                    }
33
                    return json.data;
34
                }
35
            },
36
            columns: [
37
                { data: 'import_oai_id', },
38
                { data: 'repository', },
39
                { data: 'header_identifier', },
40
                { data: 'header_datestamp', },
41
                {
42
                    data: 'header_status', render: function (data, type, full, meta){
43
                        var display_string = _("Active");
44
                        if (data == "deleted"){
45
                            display_string = _("Deleted");
46
                        }
47
                        return display_string;
48
                    }
49
                },
50
                {
51
                    data: 'status', render: function (data, type, full, meta){
52
                        var display_string = data;
53
                        if (data == "added"){
54
                            display_string = _("Added");
55
                        }
56
                        else if (data == "error"){
57
                            display_string = _("Error");
58
                        }
59
                        else if (data == "not_found"){
60
                            display_string = _("Not found");
61
                        }
62
                        else if (data == "updated"){
63
                            display_string = _("Updated");
64
                        }
65
                        return display_string;
66
                    }
67
                },
68
                { data: 'upload_timestamp', },
69
                {
70
                    data: 'imported_record', render: function (data, type, full, meta){
71
                        var display_string = data;
72
                        var record_type = (full.record_type) ? full.record_type : 'biblio';
73
                        if (data && record_type == 'biblio'){
74
                            var link_text = _("View biblio record");
75
                            var link = '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber='+data+'">'+link_text+'</a>';
76
                            display_string = link;
77
                        }
78
                        return display_string;
79
                    }, searchable: false
80
81
                },
82
                {
83
                    data: 'import_oai_id', render: function (data, type, full, meta){
84
                        var display_string = data;
85
                        var link_text = _("View record");
86
                        var link = '<a href="/cgi-bin/koha/tools/oai-pmh-harvester/record.pl?import_oai_id='+data+'">'+link_text+'</a>';
87
                        display_string = link;
88
                        return display_string;
89
                    }, searchable: false
90
                },
91
            ],
92
            //In theory, it would be nice to sort in descending order, but
93
            //it causes severe paging issues the data is frequently updated.
94
            //Caching would make the paging more stable, but the results would be stale.
95
            order: [
96
                [ 0, 'asc' ],
97
            ]
98
        });
99
        $('#refresh-button').click(function(){
100
            history_table.ajax.reload( null, false );
101
        });
102
    });
103
//]]>
104
</script>
105
<style type="text/css">
8
<style type="text/css">
106
    a.paginate_button {
9
    a.paginate_button {
107
        padding: 2px;
10
        padding: 2px;
Lines 118-124 Link Here
118
                <div class="yui-b">
21
                <div class="yui-b">
119
                    <h1>OAI-PMH harvester</h1>
22
                    <h1>OAI-PMH harvester</h1>
120
                    <div id="toolbar" class="btn-toolbar">
23
                    <div id="toolbar" class="btn-toolbar">
121
                        <a id="new-request" class="btn btn-default btn-sm" href="[% request_page %]?op=new"><i class="fa fa-plus"></i> New request</a>
24
                        <a id="new-request" class="btn btn-default btn-sm" href="[% request_page | url %]?op=new"><i class="fa fa-plus"></i> New request</a>
122
                    </div>
25
                    </div>
123
                    [% IF ( harvester.offline ) %]
26
                    [% IF ( harvester.offline ) %]
124
                        <div class="alert">
27
                        <div class="alert">
Lines 128-137 Link Here
128
                    <div id="dashboard-items" class="toptabs">
31
                    <div id="dashboard-items" class="toptabs">
129
                        <ul>
32
                        <ul>
130
                            <li>
33
                            <li>
131
                                <a href="#saved_requests">Saved requests <span id="saved_count">([% saved_requests.size %])</span></a>
34
                                <a href="#saved_requests">Saved requests <span id="saved_count">([% saved_requests.size | html %])</span></a>
132
                            </li>
35
                            </li>
133
                            <li>
36
                            <li>
134
                                <a href="#submitted_requests">Submitted requests <span id="submitted_count">([% submitted_requests.size %])</span></a>
37
                                <a href="#submitted_requests">Submitted requests <span id="submitted_count">([% submitted_requests.size | html %])</span></a>
135
                            </li>
38
                            </li>
136
                            <li>
39
                            <li>
137
                                <a href="#imports">Import history <span id="import_count">(0)</span></a>
40
                                <a href="#imports">Import history <span id="import_count">(0)</span></a>
Lines 184-198 Link Here
184
                                [% IF ( submitted_requests ) %]
87
                                [% IF ( submitted_requests ) %]
185
                                    [% FOREACH submitted_request IN submitted_requests %]
88
                                    [% FOREACH submitted_request IN submitted_requests %]
186
                                        <tr>
89
                                        <tr>
187
                                            <td>[% submitted_request.name %]</td>
90
                                            <td>[% submitted_request.name | html %]</td>
188
                                            <td>[% submitted_request.parameters.oai_pmh.baseURL %]</td>
91
                                            <td>[% submitted_request.parameters.oai_pmh.baseURL | html %]</td>
189
                                            <td>[% submitted_request.parameters.oai_pmh.set %]</td>
92
                                            <td>[% submitted_request.parameters.oai_pmh.set | html %]</td>
190
                                            <td>[% submitted_request.parameters.oai_pmh.from %]</td>
93
                                            <td>[% submitted_request.parameters.oai_pmh.from | html %]</td>
191
                                            <td>[% submitted_request.parameters.oai_pmh.until %]</td>
94
                                            <td>[% submitted_request.parameters.oai_pmh.until | html %]</td>
192
                                            <td>[% submitted_request.interval %]</td>
95
                                            <td>[% submitted_request.interval | html %]</td>
193
                                            <td>[% submitted_request.effective_from %]</td>
96
                                            <td>[% submitted_request.effective_from | html %]</td>
194
                                            <td>[% submitted_request.effective_until %]</td>
97
                                            <td>[% submitted_request.effective_until | html %]</td>
195
                                            <td>[% submitted_request.pending_imports %]</td>
98
                                            <td>[% submitted_request.pending_imports |html %]</td>
196
                                            <td>
99
                                            <td>
197
                                                [% IF ( submitted_status = submitted_request.status ) %]
100
                                                [% IF ( submitted_status = submitted_request.status ) %]
198
                                                    [% IF ( submitted_status == "new" ) %]
101
                                                    [% IF ( submitted_status == "new" ) %]
Lines 214-226 Link Here
214
                                                    <a class="btn btn-default btn-xs dropdown-toggle" role="button" data-toggle="dropdown" href="#">Actions <span class="caret"></span></a>
117
                                                    <a class="btn btn-default btn-xs dropdown-toggle" role="button" data-toggle="dropdown" href="#">Actions <span class="caret"></span></a>
215
                                                    <ul class="dropdown-menu pull-right" role="menu">
118
                                                    <ul class="dropdown-menu pull-right" role="menu">
216
                                                          <li>
119
                                                          <li>
217
                                                              <a href="[% dashboard_page %]?op=start&uuid=[% submitted_request.uuid %]"><i class="fa fa-play"></i> Start</a>
120
                                                              <a href="[% dashboard_page | url %]?op=start&uuid=[% submitted_request.uuid | url %]"><i class="fa fa-play"></i> Start</a>
218
                                                          </li>
121
                                                          </li>
219
                                                          <li>
122
                                                          <li>
220
                                                              <a href="[% dashboard_page %]?op=stop&uuid=[% submitted_request.uuid %]"><i class="fa fa-stop"></i> Stop</a>
123
                                                              <a href="[% dashboard_page | url %]?op=stop&uuid=[% submitted_request.uuid | url %]"><i class="fa fa-stop"></i> Stop</a>
221
                                                          </li>
124
                                                          </li>
222
                                                          <li>
125
                                                          <li>
223
                                                              <a href="[% dashboard_page %]?op=delete&uuid=[% submitted_request.uuid %]"><i class="fa fa-trash"></i> Delete</a>
126
                                                              <a href="[% dashboard_page | url %]?op=delete&uuid=[% submitted_request.uuid | url %]"><i class="fa fa-trash"></i> Delete</a>
224
                                                          </li>
127
                                                          </li>
225
                                                    </ul>
128
                                                    </ul>
226
                                                </div>
129
                                                </div>
Lines 264-283 Link Here
264
                                [% IF ( saved_requests ) %]
167
                                [% IF ( saved_requests ) %]
265
                                    [% FOREACH saved_request IN saved_requests %]
168
                                    [% FOREACH saved_request IN saved_requests %]
266
                                        <tr>
169
                                        <tr>
267
                                            <td>[% saved_request.name %]</td>
170
                                            <td>[% saved_request.name | html %]</td>
268
                                            <td>[% saved_request.http_url %]</td>
171
                                            <td>[% saved_request.http_url | html %]</td>
269
                                       <!-- <td>[% saved_request.oai_verb %]</td>
172
                                       <!-- <td>[% saved_request.oai_verb | html %]</td>
270
                                            <td>[% saved_request.oai_metadataPrefix %]</td>
173
                                            <td>[% saved_request.oai_metadataPrefix | html %]</td>
271
                                            <td>[% saved_request.oai_identifier %]</td> -->
174
                                            <td>[% saved_request.oai_identifier | html %]</td> -->
272
                                            <td>[% saved_request.oai_set %]</td>
175
                                            <td>[% saved_request.oai_set | html %]</td>
273
                                            <td>[% saved_request.oai_from %]</td>
176
                                            <td>[% saved_request.oai_from | html %]</td>
274
                                            <td>[% saved_request.oai_until %]</td>
177
                                            <td>[% saved_request.oai_until | html %]</td>
275
                                            <td>[% saved_request.interval %]</td>
178
                                            <td>[% saved_request.interval | html %]</td>
276
                                       <!-- <td>
179
                                       <!-- <td>
277
                                                [% IF ( saved_request.import_filter == "default" ) %]
180
                                                [% IF ( saved_request.import_filter == "default" ) %]
278
                                                    <span>Default</span>
181
                                                    <span>Default</span>
279
                                                [% ELSE %]
182
                                                [% ELSE %]
280
                                                    [% saved_request.import_filter %]
183
                                                    [% saved_request.import_filter | html %]
281
                                                [% END %]
184
                                                [% END %]
282
                                            </td>
185
                                            </td>
283
                                            <td>
186
                                            <td>
Lines 288-303 Link Here
288
                                                    [% END %]
191
                                                    [% END %]
289
                                                [% END %]
192
                                                [% END %]
290
                                                [% IF ( display_framework ) %]
193
                                                [% IF ( display_framework ) %]
291
                                                    [% display_framework.frameworktext %]
194
                                                    [% display_framework.frameworktext | html %]
292
                                                [% ELSE %]
195
                                                [% ELSE %]
293
                                                    [% saved_request.import_framework_code %]
196
                                                    [% saved_request.import_framework_code | html %]
294
                                                [% END %]
197
                                                [% END %]
295
                                            </td>
198
                                            </td>
296
                                            <td>
199
                                            <td>
297
                                                [% IF ( saved_request.import_record_type == "biblio" ) %]
200
                                                [% IF ( saved_request.import_record_type == "biblio" ) %]
298
                                                    <span>Bibliographic</span>
201
                                                    <span>Bibliographic</span>
299
                                                [% ELSE %]
202
                                                [% ELSE %]
300
                                                    [% saved_request.import_record_type %]
203
                                                    [% saved_request.import_record_type | html %]
301
                                                [% END %]
204
                                                [% END %]
302
                                            </td>
205
                                            </td>
303
                                            <td>
206
                                            <td>
Lines 308-316 Link Here
308
                                                    [% END %]
211
                                                    [% END %]
309
                                                [% END %]
212
                                                [% END %]
310
                                                [% IF ( display_matcher ) %]
213
                                                [% IF ( display_matcher ) %]
311
                                                    [% display_matcher.description %]
214
                                                    [% display_matcher.description | html %]
312
                                                [% ELSE %]
215
                                                [% ELSE %]
313
                                                    [% saved_request.import_matcher_code %]
216
                                                    [% saved_request.import_matcher_code | html %]
314
                                                [% END %]
217
                                                [% END %]
315
                                            </td> -->
218
                                            </td> -->
316
                                            <td>
219
                                            <td>
Lines 318-333 Link Here
318
                                                    <a class="btn btn-default btn-xs dropdown-toggle" role="button" data-toggle="dropdown" href="#">Actions <span class="caret"></span></a>
221
                                                    <a class="btn btn-default btn-xs dropdown-toggle" role="button" data-toggle="dropdown" href="#">Actions <span class="caret"></span></a>
319
                                                    <ul class="dropdown-menu pull-right" role="menu">
222
                                                    <ul class="dropdown-menu pull-right" role="menu">
320
                                                          <li>
223
                                                          <li>
321
                                                              <a href="[% request_page %]?op=edit&id=[% saved_request.id %]"><i class="fa fa-pencil"></i> Edit</a>
224
                                                              <a href="[% request_page | url %]?op=edit&id=[% saved_request.id | url %]"><i class="fa fa-pencil"></i> Edit</a>
322
                                                          </li>
225
                                                          </li>
323
                                                          <li>
226
                                                          <li>
324
                                                              <a href="[% request_page %]?op=new&id=[% saved_request.id %]"><i class="fa fa-copy"></i> Copy</a>
227
                                                              <a href="[% request_page | url %]?op=new&id=[% saved_request.id | url %]"><i class="fa fa-copy"></i> Copy</a>
325
                                                          </li>
228
                                                          </li>
326
                                                          <li>
229
                                                          <li>
327
                                                              <a href="[% dashboard_page %]?op=send&id=[% saved_request.id %]"><i class="fa fa-send"></i> Submit</a>
230
                                                              <a href="[% dashboard_page | url %]?op=send&id=[% saved_request.id | url %]"><i class="fa fa-send"></i> Submit</a>
328
                                                          </li>
231
                                                          </li>
329
                                                          <li>
232
                                                          <li>
330
                                                            <a href="[% request_page %]?op=delete&id=[% saved_request.id %]"><i class="fa fa-trash"></i> Delete</a>
233
                                                            <a href="[% request_page | url %]?op=delete&id=[% saved_request.id | url %]"><i class="fa fa-trash"></i> Delete</a>
331
                                                          </li>
234
                                                          </li>
332
                                                    </ul>
235
                                                    </ul>
333
                                                </div>
236
                                                </div>
Lines 366-369 Link Here
366
                [% INCLUDE 'tools-menu.inc' %]
269
                [% INCLUDE 'tools-menu.inc' %]
367
            </div>
270
            </div>
368
        </div>
271
        </div>
272
273
[% MACRO jsinclude BLOCK %]
274
    [% INCLUDE 'datatables.inc' %]
275
    [% INCLUDE 'columns_settings.inc' %]
276
    <script type="text/javascript">
277
        $(document).ready(function() {
278
            $('#dashboard-items').tabs();
279
            [% IF ( result.start.defined || result.stop.defined || result.delete.defined ) %]
280
                $('#dashboard-items').tabs("option","active",1);
281
            [% END %]
282
283
            var saved_table_columns_settings = [% ColumnsSettings.GetColumns( 'tools','oai-pmh-harvester-dashboard', 'saved-table', 'json' ) | $raw %];
284
            var saved_table = KohaTable("saved-table",{},saved_table_columns_settings);
285
286
            var submitted_table_columns_settings = [% ColumnsSettings.GetColumns( 'tools','oai-pmh-harvester-dashboard', 'submitted-table', 'json' ) | $raw %];
287
            var submitted_table = KohaTable("submitted-table",{},submitted_table_columns_settings);
288
289
            var history_table_columns_settings = [% ColumnsSettings.GetColumns( 'tools','oai-pmh-harvester-dashboard', 'history-table', 'json' ) | $raw %];
290
            var history_table = KohaTable("history-table",{
291
                serverSide: true,
292
                searching: true,
293
                processing: true,
294
                ajax: {
295
                    "url": '/cgi-bin/koha/svc/oai-pmh-harvester/history',
296
                    contentType: 'application/json',
297
                    type: 'POST',
298
                    data: function ( d ) {
299
                        return JSON.stringify( d );
300
                    },
301
                    dataSrc: function (json){
302
                        var recordsTotal = json.recordsTotal;
303
                        if(recordsTotal){
304
                            $('#import_count').text( "("+recordsTotal+")" );
305
                        }
306
                        return json.data;
307
                    }
308
                },
309
                columns: [
310
                    { data: 'import_oai_id', },
311
                    { data: 'repository', },
312
                    { data: 'header_identifier', },
313
                    { data: 'header_datestamp', },
314
                    {
315
                        data: 'header_status', render: function (data, type, full, meta){
316
                            var display_string = _("Active");
317
                            if (data == "deleted"){
318
                                display_string = _("Deleted");
319
                            }
320
                            return display_string;
321
                        }
322
                    },
323
                    {
324
                        data: 'status', render: function (data, type, full, meta){
325
                            var display_string = data;
326
                            if (data == "added"){
327
                                display_string = _("Added");
328
                            }
329
                            else if (data == "error"){
330
                                display_string = _("Error");
331
                            }
332
                            else if (data == "not_found"){
333
                                display_string = _("Not found");
334
                            }
335
                            else if (data == "updated"){
336
                                display_string = _("Updated");
337
                            }
338
                            return display_string;
339
                        }
340
                    },
341
                    { data: 'upload_timestamp', },
342
                    {
343
                        data: 'imported_record', render: function (data, type, full, meta){
344
                            var display_string = data;
345
                            var record_type = (full.record_type) ? full.record_type : 'biblio';
346
                            if (data && record_type == 'biblio'){
347
                                var link_text = _("View biblio record");
348
                                var link = '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber='+data+'">'+link_text+'</a>';
349
                                display_string = link;
350
                            }
351
                            return display_string;
352
                        }, searchable: false
353
354
                    },
355
                    {
356
                        data: 'import_oai_id', render: function (data, type, full, meta){
357
                            var display_string = data;
358
                            var link_text = _("View record");
359
                            var link = '<a href="/cgi-bin/koha/tools/oai-pmh-harvester/record.pl?import_oai_id='+data+'">'+link_text+'</a>';
360
                            display_string = link;
361
                            return display_string;
362
                        }, searchable: false
363
                    },
364
                ],
365
                //In theory, it would be nice to sort in descending order, but
366
                //it causes severe paging issues the data is frequently updated.
367
                //Caching would make the paging more stable, but the results would be stale.
368
                order: [
369
                    [ 0, 'asc' ],
370
                ]
371
            },history_table_columns_settings);
372
            $('#refresh-button').click(function(){
373
                history_table.ajax.reload( null, false );
374
            });
375
        });
376
    </script>
377
[% END %]
369
[% INCLUDE 'intranet-bottom.inc' %]
378
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/request.tt (-60 / +63 lines)
Lines 1-48 Link Here
1
[% USE Asset %]
2
[% USE raw %]
3
[% SET footerjs = 1 %]
1
[% INCLUDE 'doc-head-open.inc' %]
4
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Tools &rsaquo; OAI-PMH harvester &rsaquo; Request</title>
5
<title>Koha &rsaquo; Tools &rsaquo; OAI-PMH harvester &rsaquo; Request</title>
3
[% INCLUDE 'doc-head-close.inc' %]
6
[% INCLUDE 'doc-head-close.inc' %]
4
[% INCLUDE 'calendar.inc' %]
5
<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery-ui-timepicker-addon.min.js"></script>
6
[% INCLUDE 'timepicker.inc' %]
7
<script type="text/javascript">
8
//<![CDATA[
9
    $(document).ready(function() {
10
        toggle_identifier();
11
        $("#oai_verb").on("click",toggle_identifier);
12
        $(".datetime_utc").datetimepicker({
13
            separator: "T",
14
            timeSuffix: 'Z',
15
            dateFormat: "yy-mm-dd",
16
            timeFormat: "HH:mm:ss",
17
            hour: 0,
18
            minute: 0,
19
            second: 0,
20
            showSecond: 1,
21
            // timezone doesn't work with the "Now" button in v1.4.3 although it appears to in v1.6.1
22
            // timezone: '+000'
23
        });
24
    });
25
    function toggle_identifier (){
26
        var verb = $("#oai_verb").find(":selected").val();
27
        var oai_identifier = $("#oai_identifier");
28
        var oai_set = $("#oai_set");
29
        var oai_from = $("#oai_from");
30
        var oai_until = $("#oai_until");
31
        if (verb == 'ListRecords'){
32
            oai_identifier.prop('disabled', true);
33
            oai_set.prop('disabled', false);
34
            oai_from.prop('disabled', false);
35
            oai_until.prop('disabled', false);
36
        }
37
        else if (verb == 'GetRecord'){
38
            oai_identifier.prop('disabled', false);
39
            oai_set.prop('disabled', true);
40
            oai_from.prop('disabled', true);
41
            oai_until.prop('disabled', true);
42
        }
43
    }
44
//]]>
45
</script>
46
<style type="text/css">
7
<style type="text/css">
47
    /* Override staff-global.css which hides second, millisecond, and microsecond sliders */
8
    /* Override staff-global.css which hides second, millisecond, and microsecond sliders */
48
    .ui_tpicker_second {
9
    .ui_tpicker_second {
Lines 76-91 Link Here
76
                        [% ELSIF ( op == "edit" ) %]
37
                        [% ELSIF ( op == "edit" ) %]
77
                             <input type="hidden" name="op" value="update" />
38
                             <input type="hidden" name="op" value="update" />
78
                        [% ELSE %]
39
                        [% ELSE %]
79
                            <input type="hidden" name="op" value="[% op %]" />
40
                            <input type="hidden" name="op" value="[% op | html %]" />
80
                        [% END %]
41
                        [% END %]
81
                        [% IF ( id ) %]
42
                        [% IF ( id ) %]
82
                            <input type="hidden" name="id" value="[% id %]" />
43
                            <input type="hidden" name="id" value="[% id | html %]" />
83
                        [% END %]
44
                        [% END %]
84
                        <fieldset class="rows">
45
                        <fieldset class="rows">
85
                            <ol>
46
                            <ol>
86
                                <li>
47
                                <li>
87
                                    <label for="name">Name:</label>
48
                                    <label for="name">Name:</label>
88
                                    <input type="text" size="30" id="name" name="name" value="[% oai_pmh_request.name %]"/>
49
                                    <input type="text" size="30" id="name" name="name" value="[% oai_pmh_request.name | html %]"/>
89
                                    <span class="help">This is just a short name to help in managing requests.</span>
50
                                    <span class="help">This is just a short name to help in managing requests.</span>
90
                                </li>
51
                                </li>
91
                            </ol>
52
                            </ol>
Lines 95-101 Link Here
95
                            <ol>
56
                            <ol>
96
                                <li>
57
                                <li>
97
                                    <label for="http_url">URL:</label>
58
                                    <label for="http_url">URL:</label>
98
                                    <input type="text" size="30" id="http_url" name="http_url" value="[% oai_pmh_request.http_url %]">
59
                                    <input type="text" size="30" id="http_url" name="http_url" value="[% oai_pmh_request.http_url | html %]">
99
                                    [% IF (errors.http_url.malformed) %]<span class="error">[This must be a properly formatted HTTP or HTTPS URL.]</span>[% END %]
60
                                    [% IF (errors.http_url.malformed) %]<span class="error">[This must be a properly formatted HTTP or HTTPS URL.]</span>[% END %]
100
                                    [% IF (errors.http.404) %]<span class="error">[Cannot find address specified by this URL.]</span>[% END %]
61
                                    [% IF (errors.http.404) %]<span class="error">[Cannot find address specified by this URL.]</span>[% END %]
101
                                    [% IF (errors.http.401) %]<span class="error">[Permission denied to access this URL.]</span>[% END %]
62
                                    [% IF (errors.http.401) %]<span class="error">[Permission denied to access this URL.]</span>[% END %]
Lines 106-120 Link Here
106
                            <ol>
67
                            <ol>
107
                                <li>
68
                                <li>
108
                                    <label for="http_username">Username:</label>
69
                                    <label for="http_username">Username:</label>
109
                                    <input type="text" size="30" id="http_username" name="http_username" value="[% oai_pmh_request.http_username %]">
70
                                    <input type="text" size="30" id="http_username" name="http_username" value="[% oai_pmh_request.http_username | html %]">
110
                                </li>
71
                                </li>
111
                                <li>
72
                                <li>
112
                                    <label for="http_password">Password:</label>
73
                                    <label for="http_password">Password:</label>
113
                                    <input type="text" size="30" id="http_password" name="http_password" value="[% oai_pmh_request.http_password %]">
74
                                    <input type="text" size="30" id="http_password" name="http_password" value="[% oai_pmh_request.http_password | html %]">
114
                                </li>
75
                                </li>
115
                                <li>
76
                                <li>
116
                                    <label for="http_realm">Realm:</label>
77
                                    <label for="http_realm">Realm:</label>
117
                                    <input type="text" size="30" id="http_realm" name="http_realm" value="[% oai_pmh_request.http_realm %]">
78
                                    <input type="text" size="30" id="http_realm" name="http_realm" value="[% oai_pmh_request.http_realm | html %]">
118
                                </li>
79
                                </li>
119
                            </ol>
80
                            </ol>
120
                        </fieldset>
81
                        </fieldset>
Lines 138-168 Link Here
138
                                </li>
99
                                </li>
139
                                <li>
100
                                <li>
140
                                    <label for="oai_metadataPrefix">Metadata prefix:</label>
101
                                    <label for="oai_metadataPrefix">Metadata prefix:</label>
141
                                    <input type="text" size="30" id="oai_metadataPrefix" name="oai_metadataPrefix" value="[% oai_pmh_request.oai_metadataPrefix %]">
102
                                    <input type="text" size="30" id="oai_metadataPrefix" name="oai_metadataPrefix" value="[% oai_pmh_request.oai_metadataPrefix | html %]">
142
                                    [% IF (errors.oai_metadataPrefix.unavailable) %]<span class="error">[This metadataPrefix is unavailable from this OAI-PMH provider.]</span>[% END %]
103
                                    [% IF (errors.oai_metadataPrefix.unavailable) %]<span class="error">[This metadataPrefix is unavailable from this OAI-PMH provider.]</span>[% END %]
143
                                    [% IF (errors.oai_metadataPrefix.missing) %]<span class="error">[metadataPrefix is a required field for an OAI-PMH request.]</span>[% END %]
104
                                    [% IF (errors.oai_metadataPrefix.missing) %]<span class="error">[metadataPrefix is a required field for an OAI-PMH request.]</span>[% END %]
144
                                </li>
105
                                </li>
145
                                <li>
106
                                <li>
146
                                    <label for="oai_identifier">Identifier:</label>
107
                                    <label for="oai_identifier">Identifier:</label>
147
                                    <input type="text" size="30" id="oai_identifier" name="oai_identifier" value="[% oai_pmh_request.oai_identifier %]">
108
                                    <input type="text" size="30" id="oai_identifier" name="oai_identifier" value="[% oai_pmh_request.oai_identifier | html %]">
148
                                    [% IF (errors.oai_identifier.missing) %]<span class="error">[Identifier is a required field when using GetRecord for an OAI-PMH request.]</span>[% END %]
109
                                    [% IF (errors.oai_identifier.missing) %]<span class="error">[Identifier is a required field when using GetRecord for an OAI-PMH request.]</span>[% END %]
149
                                </li>
110
                                </li>
150
                                <li>
111
                                <li>
151
                                    <label for="oai_set">Set:</label>
112
                                    <label for="oai_set">Set:</label>
152
                                    <input type="text" size="30" id="oai_set" name="oai_set" value="[% oai_pmh_request.oai_set %]">
113
                                    <input type="text" size="30" id="oai_set" name="oai_set" value="[% oai_pmh_request.oai_set | html %]">
153
                                    [% IF (errors.oai_set.unavailable) %]<span class="error">[This set is unavailable from this OAI-PMH provider.]</span>[% END %]
114
                                    [% IF (errors.oai_set.unavailable) %]<span class="error">[This set is unavailable from this OAI-PMH provider.]</span>[% END %]
154
                                </li>
115
                                </li>
155
                                [% IF (errors.oai.granularity_mismatch) %]<span class="error">[You must specify the same granularity for both From and Until.]</span>[% END %]
116
                                [% IF (errors.oai.granularity_mismatch) %]<span class="error">[You must specify the same granularity for both From and Until.]</span>[% END %]
156
                                <li>
117
                                <li>
157
                                    <label for="oai_from">From:</label>
118
                                    <label for="oai_from">From:</label>
158
                                    <input type="text" size="30" class="datetime_utc" id="oai_from" name="oai_from" value="[% oai_pmh_request.oai_from %]">
119
                                    <input type="text" size="30" class="datetime_utc" id="oai_from" name="oai_from" value="[% oai_pmh_request.oai_from | html %]">
159
                                    <span class="help">This value will be treated as UTC time. Note that some repositories only support YYYY-MM-DD datestamps.</span>
120
                                    <span class="help">This value will be treated as UTC time. Note that some repositories only support YYYY-MM-DD datestamps.</span>
160
                                    [% IF (errors.oai_from.malformed) %]<span class="error">[This must be in YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ format.]</span>[% END %]
121
                                    [% IF (errors.oai_from.malformed) %]<span class="error">[This must be in YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ format.]</span>[% END %]
161
                                    [% IF (errors.oai_from.unavailable) %]<span class="error">[This granularity is unsupported by this OAI-PMH provider.]</span>[% END %]
122
                                    [% IF (errors.oai_from.unavailable) %]<span class="error">[This granularity is unsupported by this OAI-PMH provider.]</span>[% END %]
162
                                </li>
123
                                </li>
163
                                <li>
124
                                <li>
164
                                    <label for="oai_until">Until:</label>
125
                                    <label for="oai_until">Until:</label>
165
                                    <input type="text" size="30" class="datetime_utc" id="oai_until" name="oai_until" value="[% oai_pmh_request.oai_until %]">
126
                                    <input type="text" size="30" class="datetime_utc" id="oai_until" name="oai_until" value="[% oai_pmh_request.oai_until | html %]">
166
                                    <span class="help">This value will be treated as UTC time. Note that some repositories only support YYYY-MM-DD datestamps.</span>
127
                                    <span class="help">This value will be treated as UTC time. Note that some repositories only support YYYY-MM-DD datestamps.</span>
167
                                    [% IF (errors.oai_until.malformed) %]<span class="error">[This must be in YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ format.]</span>[% END %]
128
                                    [% IF (errors.oai_until.malformed) %]<span class="error">[This must be in YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ format.]</span>[% END %]
168
                                    [% IF (errors.oai_until.unavailable) %]<span class="error">[This granularity is unsupported by this OAI-PMH provider.]</span>[% END %]
129
                                    [% IF (errors.oai_until.unavailable) %]<span class="error">[This granularity is unsupported by this OAI-PMH provider.]</span>[% END %]
Lines 177-183 Link Here
177
                                    [% IF ( oai_pmh_request.import_filter == "default" ) %]
138
                                    [% IF ( oai_pmh_request.import_filter == "default" ) %]
178
                                        <input type="text" size="30" id="import_filter" name="import_filter" value="default">
139
                                        <input type="text" size="30" id="import_filter" name="import_filter" value="default">
179
                                    [% ELSE %]
140
                                    [% ELSE %]
180
                                        <input type="text" size="30" id="import_filter" name="import_filter" value="[% oai_pmh_request.import_filter %]">
141
                                        <input type="text" size="30" id="import_filter" name="import_filter" value="[% oai_pmh_request.import_filter | html %]">
181
                                    [% END %]
142
                                    [% END %]
182
                                    <span class="help">If no filter is entered, the default filter will be used.</span>
143
                                    <span class="help">If no filter is entered, the default filter will be used.</span>
183
                                </li>
144
                                </li>
Lines 187-195 Link Here
187
                                        <option value="">Default framework</option>
148
                                        <option value="">Default framework</option>
188
                                        [% FOREACH framework IN frameworks %]
149
                                        [% FOREACH framework IN frameworks %]
189
                                            [% IF ( oai_pmh_request.import_framework_code == framework.frameworkcode ) %]
150
                                            [% IF ( oai_pmh_request.import_framework_code == framework.frameworkcode ) %]
190
                                                <option selected="selected" value="[% framework.frameworkcode %]">[% framework.frameworktext %]</option>
151
                                                <option selected="selected" value="[% framework.frameworkcode | html %]">[% framework.frameworktext | html %]</option>
191
                                            [% ELSE %]
152
                                            [% ELSE %]
192
                                                <option value="[% framework.frameworkcode %]">[% framework.frameworktext %]</option>
153
                                                <option value="[% framework.frameworkcode | html %]">[% framework.frameworktext | html %]</option>
193
                                            [% END %]
154
                                            [% END %]
194
                                        [% END %]
155
                                        [% END %]
195
                                    </select>
156
                                    </select>
Lines 206-214 Link Here
206
                                        <option value="">None</option>
167
                                        <option value="">None</option>
207
                                        [% FOREACH matcher IN matchers %]
168
                                        [% FOREACH matcher IN matchers %]
208
                                            [% IF ( oai_pmh_request.import_matcher_code == matcher.code ) %]
169
                                            [% IF ( oai_pmh_request.import_matcher_code == matcher.code ) %]
209
                                                <option value="[% matcher.code %]" selected="selected">[% matcher.description %]</option>
170
                                                <option value="[% matcher.code | html %]" selected="selected">[% matcher.description | html %]</option>
210
                                            [% ELSE %]
171
                                            [% ELSE %]
211
                                                <option value="[% matcher.code %]">[% matcher.description %]</option>
172
                                                <option value="[% matcher.code | html %]">[% matcher.description | html %]</option>
212
                                            [% END %]
173
                                            [% END %]
213
                                        [% END %]
174
                                        [% END %]
214
                                    </select>
175
                                    </select>
Lines 221-227 Link Here
221
                            <ol>
182
                            <ol>
222
                                <li>
183
                                <li>
223
                                    <label for="interval">Interval (seconds): </label>
184
                                    <label for="interval">Interval (seconds): </label>
224
                                    <input type="text" id="interval" name="interval" value="[% oai_pmh_request.interval %]" size="4">
185
                                    <input type="text" id="interval" name="interval" value="[% oai_pmh_request.interval | html %]" size="4">
225
                                    <span class="help">The download request will be repeated in intervals of this many seconds. Enter "0" if you want the task to only happen once.</span>
186
                                    <span class="help">The download request will be repeated in intervals of this many seconds. Enter "0" if you want the task to only happen once.</span>
226
                                </li>
187
                                </li>
227
                            </ol>
188
                            </ol>
Lines 238-241 Link Here
238
                [% INCLUDE 'tools-menu.inc' %]
199
                [% INCLUDE 'tools-menu.inc' %]
239
            </div>
200
            </div>
240
        </div>
201
        </div>
202
[% MACRO jsinclude BLOCK %]
203
    [% INCLUDE 'calendar.inc' %]
204
    [% Asset.js("lib/jquery/plugins/jquery-ui-timepicker-addon.min.js") | $raw %]
205
    [% INCLUDE 'timepicker.inc' %]
206
    <script type="text/javascript">
207
        $(document).ready(function() {
208
            toggle_identifier();
209
            $("#oai_verb").on("click",toggle_identifier);
210
            $(".datetime_utc").datetimepicker({
211
                separator: "T",
212
                timeSuffix: 'Z',
213
                dateFormat: "yy-mm-dd",
214
                timeFormat: "HH:mm:ss",
215
                hour: 0,
216
                minute: 0,
217
                second: 0,
218
                showSecond: 1,
219
                // timezone doesn't work with the "Now" button in v1.4.3 although it appears to in v1.6.1
220
                // timezone: '+000'
221
            });
222
        });
223
        function toggle_identifier (){
224
            var verb = $("#oai_verb").find(":selected").val();
225
            var oai_identifier = $("#oai_identifier");
226
            var oai_set = $("#oai_set");
227
            var oai_from = $("#oai_from");
228
            var oai_until = $("#oai_until");
229
            if (verb == 'ListRecords'){
230
                oai_identifier.prop('disabled', true);
231
                oai_set.prop('disabled', false);
232
                oai_from.prop('disabled', false);
233
                oai_until.prop('disabled', false);
234
            }
235
            else if (verb == 'GetRecord'){
236
                oai_identifier.prop('disabled', false);
237
                oai_set.prop('disabled', true);
238
                oai_from.prop('disabled', true);
239
                oai_until.prop('disabled', true);
240
            }
241
        }
242
    </script>
243
[% END %]
241
[% INCLUDE 'intranet-bottom.inc' %]
244
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/rewrite-config.PL (-1 / +1 lines)
Lines 151-157 $prefix = $ENV{'INSTALL_BASE'} || "/usr"; Link Here
151
  "__MEMCACHED_SERVERS__" => "",
151
  "__MEMCACHED_SERVERS__" => "",
152
  "__MEMCACHED_NAMESPACE__" => "",
152
  "__MEMCACHED_NAMESPACE__" => "",
153
  "__FONT_DIR__" => "/usr/share/fonts/truetype/ttf-dejavu",
153
  "__FONT_DIR__" => "/usr/share/fonts/truetype/ttf-dejavu",
154
  "__TEMPLATE_CACHE_DIR__" => "/tmp/koha"
154
  "__TEMPLATE_CACHE_DIR__" => "/tmp/koha",
155
  "__OAI_RUN_DIR__" => "",
155
  "__OAI_RUN_DIR__" => "",
156
  "__OAI_LIB_DIR__" => "",
156
  "__OAI_LIB_DIR__" => "",
157
  "__OAI_SPOOL_DIR__" => "",
157
  "__OAI_SPOOL_DIR__" => "",
(-)a/svc/oai-pmh-harvester/history (-34 / +31 lines)
Lines 20-26 Link Here
20
use Modern::Perl;
20
use Modern::Perl;
21
use C4::Auth qw(check_cookie_auth haspermission get_session);
21
use C4::Auth qw(check_cookie_auth haspermission get_session);
22
use JSON;
22
use JSON;
23
use Koha::Database;
23
use Koha::OAI::Harvester::Biblios;
24
use Koha::OAI::Harvester::Histories;
24
25
25
my $input = new CGI;
26
my $input = new CGI;
26
27
Lines 88-127 if ($input->request_method eq "POST"){ Link Here
88
}
89
}
89
90
90
my $page = ( $start / $length ) + 1;
91
my $page = ( $start / $length ) + 1;
91
my $schema = Koha::Database->new()->schema();
92
my $results = Koha::OAI::Harvester::Histories->new->search(
92
if ($schema){
93
    \@search,
93
    my $rs = $schema->resultset("OaiHarvesterHistory");
94
    {
94
    my $results = $rs->search(
95
        page => $page,
95
        \@search,
96
        rows => $length,
96
        {
97
        order_by => \@order_by,
97
            result_class => 'DBIx::Class::ResultClass::HashRefInflator',
98
    },
98
            page => $page,
99
);
99
            rows => $length,
100
my $count = Koha::OAI::Harvester::Histories->new->count;
100
            order_by => \@order_by,
101
my $filtered_count = $results->pager->total_entries;
101
        },
102
my @rows = ();
102
    );
103
while (my $obj = $results->next){
103
    my $count = $rs->count;
104
    my $row = $obj->unblessed;
104
    my $filtered_count = $results->pager->total_entries;
105
    $row->{imported_record} = '';
105
    my @rows = ();
106
    if ($row->{record_type} eq "biblio"){
106
    while (my $row = $results->next){
107
        my $harvested_biblio = Koha::OAI::Harvester::Biblios->new->find(
107
        $row->{imported_record} = '';
108
                {
108
        if ($row->{record_type} eq "biblio"){
109
                    oai_repository => $row->{repository},
109
            my $harvested_biblio = $schema->resultset("OaiHarvesterBiblio")->find(
110
                    oai_identifier => $row->{header_identifier},
110
                    {
111
                },
111
                        oai_repository => $row->{repository},
112
                { key => "oai_record" },
112
                        oai_identifier => $row->{header_identifier},
113
        );
113
                    },
114
        $row->{imported_record} = $harvested_biblio->biblionumber if $harvested_biblio;
114
                    { key => "oai_record" },
115
            );
116
            $row->{imported_record} = $harvested_biblio->biblionumber->id if $harvested_biblio;
117
        }
118
        push(@rows,$row);
119
    }
120
    if ($count){
121
        $data->{recordsTotal} = $count;
122
        $data->{recordsFiltered} = $filtered_count;
123
        $data->{data} = \@rows if @rows;
124
    }
115
    }
116
    push(@rows,$row);
117
}
118
if ($count){
119
    $data->{recordsTotal} = $count;
120
    $data->{recordsFiltered} = $filtered_count;
121
    $data->{data} = \@rows if @rows;
125
}
122
}
126
123
127
binmode STDOUT, ":encoding(UTF-8)";
124
binmode STDOUT, ":encoding(UTF-8)";
(-)a/tools/oai-pmh-harvester/record.pl (-13 / +6 lines)
Lines 21-27 use Modern::Perl; Link Here
21
21
22
use C4::Auth;
22
use C4::Auth;
23
use C4::Output;
23
use C4::Output;
24
use Koha::Database;
24
use Koha::OAI::Harvester::Histories;
25
25
26
my $input = new CGI;
26
my $input = new CGI;
27
27
Lines 35-51 my ($template, $loggedinuser, $cookie) = Link Here
35
35
36
my $import_oai_id = $input->param('import_oai_id');
36
my $import_oai_id = $input->param('import_oai_id');
37
if ($import_oai_id){
37
if ($import_oai_id){
38
    my $schema = Koha::Database->new()->schema();
38
    my $history = Koha::OAI::Harvester::Histories->new->find($import_oai_id);
39
    if ($schema){
39
    if ($history){
40
        my $rs = $schema->resultset("OaiHarvesterHistory");
40
        my $record = $history->record;
41
        if ($rs){
41
        if ($record){
42
            my $row = $rs->find($import_oai_id);
42
            $template->{VARS}->{ record } = $record;
43
            if ($row){
44
                my $record = $row->record;
45
                if ($record){
46
                    $template->{VARS}->{ record } = $record;
47
                }
48
            }
49
        }
43
        }
50
    }
44
    }
51
}
45
}
52
- 

Return to bug 10662