package OpenILS::WWW::TemplateBatchBibUpdate;
use strict;
use warnings;
use bytes;
use Apache2::Log;
use Apache2::Const -compile => qw(OK REDIRECT DECLINED NOT_FOUND :log);
use APR::Const -compile => qw(:error SUCCESS);
use APR::Table;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::RequestUtil;
use CGI;
use Data::Dumper;
use Text::CSV;
use OpenSRF::EX qw(:try);
use OpenSRF::Utils qw/:datetime/;
use OpenSRF::Utils::Cache;
use OpenSRF::System;
use OpenSRF::AppSession;
use XML::LibXML;
use XML::LibXSLT;
use Encode;
use Unicode::Normalize;
use OpenILS::Utils::Fieldmapper;
use OpenSRF::Utils::Logger qw/$logger/;
use MARC::Record;
use MARC::File::XML ( BinaryEncoding => 'UTF-8' );
use UNIVERSAL::require;
our @formats = qw/USMARC UNIMARC XML BRE/;
# set the bootstrap config and template include directory when
# this module is loaded
my $bootstrap;
sub import {
my $self = shift;
$bootstrap = shift;
}
sub child_init {
OpenSRF::System->bootstrap_client( config_file => $bootstrap );
Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
return Apache2::Const::OK;
}
sub handler {
my $r = shift;
my $cgi = new CGI;
my $authid = $cgi->cookie('ses') || $cgi->param('ses');
my $usr = verify_login($authid);
return show_template($r) unless ($usr);
my $template = $cgi->param('template');
return show_template($r) unless ($template);
my $rsource = $cgi->param('recordSource');
# find some IDs ...
my @records;
if ($rsource eq 'r') {
@records = map { $_ ? ($_) : () } $cgi->param('recid');
}
if ($rsource eq 'c') { # try for a file
my $file = $cgi->param('idfile');
if ($file) {
my $col = $cgi->param('idcolumn') || 0;
my $csv = new Text::CSV;
while (<$file>) {
$csv->parse($_);
my @data = $csv->fields;
my $id = $data[$col];
$id =~ s/\D+//o;
next unless ($id);
push @records, $id;
}
}
}
my $e = OpenSRF::AppSession->connect('open-ils.cstore');
$e->request('open-ils.cstore.transaction.begin')->gather(1);
$e->request('open-ils.cstore.set_audit_info', $authid, $usr->id, $usr->wsid)->gather(1);
# still no records ...
my $container = $cgi->param('containerid');
if ($rsource eq 'b') {
if ($container) {
my $bucket = $e->request(
'open-ils.cstore.direct.container.biblio_record_entry_bucket.retrieve',
$container
)->gather(1);
unless($bucket) {
$e->request('open-ils.cstore.transaction.rollback')->gather(1);
$e->disconnect;
$r->log->error("No such bucket $container");
$logger->error("No such bucket $container");
return Apache2::Const::NOT_FOUND;
}
my $recs = $e->request(
'open-ils.cstore.direct.container.biblio_record_entry_bucket_item.search.atomic',
{ bucket => $container }
)->gather(1);
@records = map { ($_->target_biblio_record_entry) } @$recs;
}
}
unless (@records) {
$e->request('open-ils.cstore.transaction.rollback')->gather(1);
$e->disconnect;
return show_template($r);
}
# we have a template and some record ids, so...
# insert the template record
my $min_id = $e->request(
'open-ils.cstore.json_query',
{ select => { bre => [{ column => 'id', transform => 'min', aggregate => 1}] }, from => 'bre' }
)->gather(1)->{id} - 1;
warn "new template bib id = $min_id\n";
my $tmpl_rec = Fieldmapper::biblio::record_entry->new;
$tmpl_rec->id($min_id);
$tmpl_rec->deleted('t');
$tmpl_rec->active('f');
$tmpl_rec->marc($template);
$tmpl_rec->creator($usr->id);
$tmpl_rec->editor($usr->id);
warn "about to create bib $min_id\n";
$e->request('open-ils.cstore.direct.biblio.record_entry.create', $tmpl_rec )->gather(1);
# create the new container for the records and the template
my $bucket = Fieldmapper::container::biblio_record_entry_bucket->new;
$bucket->owner($usr->id);
$bucket->btype('template_merge');
my $bname = $cgi->param('bname') || 'Temporary Merge Bucket '. localtime() . ' ' . $usr->id;
$bucket->name($bname);
$bucket = $e->request('open-ils.cstore.direct.container.biblio_record_entry_bucket.create', $bucket )->gather(1);
# create items in the bucket
my $item = Fieldmapper::container::biblio_record_entry_bucket_item->new;
$item->bucket($bucket->id);
$item->target_biblio_record_entry($min_id);
$e->request('open-ils.cstore.direct.container.biblio_record_entry_bucket_item.create', $item )->gather(1);
my %seen;
for my $r (@records) {
next if ($seen{$r});
$item->target_biblio_record_entry($r);
$e->request('open-ils.cstore.direct.container.biblio_record_entry_bucket_item.create', $item )->gather(1);
$seen{$r}++;
}
$e->request('open-ils.cstore.transaction.commit')->gather(1);
$e->disconnect;
# fire the background bucket processor
my $cache_key = OpenSRF::AppSession
->create('open-ils.cat')
->request('open-ils.cat.container.template_overlay.background', $authid, $bucket->id)
->gather(1);
return show_processing_template($r, $bucket->id, \@records, $cache_key);
}
sub verify_login {
my $auth_token = shift;
return undef unless $auth_token;
my $user = OpenSRF::AppSession
->create("open-ils.auth")
->request( "open-ils.auth.session.retrieve", $auth_token )
->gather(1);
if (ref($user) eq 'HASH' && $user->{ilsevent} == 1001) {
return undef;
}
return $user if ref($user);
return undef;
}
sub show_processing_template {
my $r = shift;
my $bid = shift;
my $recs = shift;
my $cache_key = shift;
my $rec_string = @$recs;
$r->content_type('text/html');
$r->print(<
Merging records...
MARC Batch Editor Status
Status
Record Count
Success
Failure
Total Processed
Total To Process
$rec_string
HTML
return Apache2::Const::OK;
}
sub show_template {
my $r = shift;
$r->content_type('text/html');
$r->print(<<'HTML');
Merge Template Builder
Bucket named:
Column of:
Columns are numbered starting at 0. For instance, when looking at a CSV file in Excel, the column labeled A is the same as column 0, and the column labeled B is the same as column 1.
Record ID:
(After setting up your template below.)
Update Template Preview:
Rule Setup
Data
Help
Action (Rule Type)
How to change the existing records
MARC Tag
Three characters, no spaces, no indicators, etc. eg: 245
Subfields (optional)
No spaces, no delimiters, eg: abcnp
MARC Data
MARC-Breaker formatted data with indicators and subfield delimiters, eg: 245 04$aThe End