From: Lebbeous Fogle-Weekley Date: Tue, 16 Aug 2011 20:22:31 +0000 (-0400) Subject: CSV export for bookbags X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=dac80a8fb00562dc5f32bcc4ce270160093534ff;p=evergreen%2Fequinox.git CSV export for bookbags Sorted the same way the user is currently viewing his/her bookbags. Signed-off-by: Lebbeous Fogle-Weekley --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm index d21a8cc092..a47f6fd9e6 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm @@ -1874,5 +1874,57 @@ sub get_bre_attrs { return $attrs; } +sub bib_container_items_via_search { + my ($class, $container_id, $search_query, $search_args) = @_; + + # First, Use search API to get container items sorted in any way that crad + # sorters support. + my $search_result = $class->simplereq( + "open-ils.search", "open-ils.search.biblio.multiclass.query", + $search_args, $search_query + ); + unless ($search_result) { + # empty result sets won't cause this, but actual errors should. + $logger->warn("bib_container_items_via_search() got nothing from search"); + return; + } + + # Throw away other junk from search, keeping only bib IDs. + my $id_list = [ map { pop @$_ } @{$search_result->{ids}} ]; + + return [] unless @$id_list; + + # Now get the bib container items themselves... + my $e = new OpenILS::Utils::CStoreEditor; + unless ($e) { + $logger->warn("bib_container_items_via_search() couldn't get cstoreeditor"); + return; + } + + my $items = $e->search_container_biblio_record_entry_bucket_item([ + { + "target_biblio_record_entry" => $id_list, + "bucket" => $container_id + }, { + flesh => 1, + flesh_fields => {"cbrebi" => [qw/notes target_biblio_record_entry/]} + } + ]); + unless ($items) { + $logger->warn( + "bib_container_items_via_search() couldn't get bucket items: " . + $e->die_event->{textcode} + ); + return; + } + + $e->disconnect; + + # ... and put them in the same order that the search API said they + # should be in. + my %ordering_hash = map { $_->target_biblio_record_entry->id, $_ } @$items; + return [map { $ordering_hash{$_} } @$id_list]; +} + 1; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm index cfeeca64b4..4214cabe6c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm @@ -5,6 +5,7 @@ use Template; use DateTime; use DateTime::Format::ISO8601; use Unicode::Normalize; +use XML::LibXML; use OpenSRF::Utils qw/:datetime/; use OpenSRF::Utils::Logger qw(:logger); use OpenILS::Application::AppUtils; @@ -199,6 +200,22 @@ my $_TT_helpers = { return; }, + csv_datum => sub { + my ($str) = @_; + + if ($str =~ /\,/ || $str =~ /"/) { + $str =~ s/"/""/g; + $str = '"' . $str . '"'; + } + + return $str; + }, + + xml_doc => sub { + my ($str) = @_; + return $str ? (new XML::LibXML)->parse_string($str) : undef; + } + }; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/ContainerCSV.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/ContainerCSV.pm new file mode 100644 index 0000000000..28a341927c --- /dev/null +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/ContainerCSV.pm @@ -0,0 +1,49 @@ +package OpenILS::Application::Trigger::Reactor::ContainerCSV; +use base "OpenILS::Application::Trigger::Reactor"; +use strict; +use warnings; +use OpenSRF::Utils::Logger qw/:logger/; +use Data::Dumper; +$Data::Dumper::Indent = 0; +my $U = "OpenILS::Application::AppUtils"; + +sub ABOUT { + return q| + +The ContainerCSV Reactor Module processes the configured template after +fetching the items from the bookbag refererred to in $env->{target} +by using the search api with the query in $env->{params}{search}. It's +the event-creator's responsibility to build a correct search query and check +permissions and do that sort of thing. + +open-ils.trigger is not a public service, so that should be ok. + +The output, like all processed templates, is stored in the event_output table. + +|; +} + +sub handler { + my ($self, $env) = @_; + + # get items for bookbags (bib containers of btype bookbag) + if ($env->{user_data}{item_search}) { + # use the search api for bib container items + my $items = $U->bib_container_items_via_search( + $env->{target}->id, $env->{user_data}{item_search} + ) or return 0; # TODO build error output for db? + + $env->{items} = $items; + } else { + # XXX TODO If we're going to support other types of containers here, + # we'll probably just want to flesh those containers' items directly, + # not involve the search API. + + $logger->warn("ContainerCSV reactor used without item_search, doesn't know what to do."); # XXX + } + + return 1 if $self->run_TT($env); + return 0; +} + +1; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index a9d0565757..07284d6583 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -144,6 +144,7 @@ sub load { return $self->load_myopac_update_password if $path =~ m|opac/myopac/update_password|; return $self->load_myopac_update_username if $path =~ m|opac/myopac/update_username|; return $self->load_myopac_bookbags if $path =~ m|opac/myopac/lists|; + return $self->load_myopac_bookbag_print if $path =~ m|opac/myopac/list/print|; return $self->load_myopac_bookbag_update if $path =~ m|opac/myopac/list/update|; return $self->load_myopac_circ_history if $path =~ m|opac/myopac/circ_history|; return $self->load_myopac_hold_history if $path =~ m|opac/myopac/hold_history|; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm index 6ae544485f..055a2bb20a 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm @@ -1207,6 +1207,7 @@ sub load_myopac_bookbags { my $sorter = $self->cgi->param("sort") || ""; my $modifier = ($sorter =~ /\.(.+$)/) ? $1 : undef; + $sorter =~ s/\..+$// if $sorter; $e->xact_begin; # replication... @@ -1499,4 +1500,56 @@ sub update_bookbag_item_notes { return 1; # success } -1 +sub load_myopac_bookbag_print { + my ($self) = @_; + + $self->apache->content_type("text/plain; encoding=utf8"); + + my $id = int($self->cgi->param("list")); + + # Prepare bib search query for bookbag's items, but don't use it yet. + my $sorter = $self->cgi->param("sort") || ""; + my $modifier = ($sorter =~ /\.(.+$)/) ? $1 : undef; + $sorter =~ s/\..+$// if $sorter; + + my $item_search = sprintf( + "container(bre,bookbag,%d,%s)%s%s", + $id, $self->editor->authtoken, + ($sorter ? " sort($sorter)" : ""), + ($modifier ? "#$modifier" : "") + ); + + my $bbag; + + # Get the bookbag object itself, assuming we're allowed to. + if ($self->editor->allowed("VIEW_CONTAINER")) { + + $bbag = $self->editor->retrieve_container_biblio_record_entry_bucket($id) or return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; + } else { + my $bookbags = $self->editor->search_container_biblio_record_entry_bucket( + { + "id" => $id, + "-or" => { + "owner" => $self->editor->requestor->id, + "pub" => "t" + } + } + ) or return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; + + $bbag = pop @$bookbags; + } + + # If we have a bookbag we're allowed to look at, issue the A/T event + # to get CSV, passing as a user param that search query we built before. + if ($bbag) { + $self->ctx->{csv} = $U->fire_object_event( + undef, "container.biblio_record_entry_bucket.csv", + $bbag, $self->editor->requestor->home_ou, + undef, {"item_search" => $item_search} + ); + } + + return Apache2::Const::OK; +} + +1; diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bookbag-goodies.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bookbag-goodies.sql index d6f82a43cc..df4e45687e 100644 --- a/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bookbag-goodies.sql +++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bookbag-goodies.sql @@ -16,4 +16,54 @@ ALTER TABLE container.copy_bucket ALTER TABLE container.user_bucket ADD COLUMN description TEXT; +INSERT INTO action_trigger.hook (key, core_type, description, passive) +VALUES ( + 'container.biblio_record_entry_bucket.csv', + 'cbreb', + oils_i18n_gettext( + 'container.biblio_record_entry_bucket.csv', + 'Produce a CSV file representing a bookbag', + 'ath', + 'description' + ), + FALSE +); + +INSERT INTO action_trigger.reactor (module, description) +VALUES ( + 'ContainerCSV', + oils_i18n_gettext( + 'ContainerCSV', + 'Facilitates produce a CSV file representing a bookbag by introducing an "items" variable into the TT environment, sorted as dictated according to user params', + 'atr', + 'description' + ) +); + +INSERT INTO action_trigger.event_definition ( + id, active, owner, + name, hook, reactor, + validator, template +) VALUES ( + 48, TRUE, 1, + 'Bookbag CSV', 'container.biblio_record_entry_bucket.csv', 'ContainerCSV', + 'NOOP_True', +$$ +[%- +# target is the bookbag itself. The 'items' variable does not need to be in +# the environment because a special reactor will take care of filling it in. + +FOR item IN items; + bibxml = helpers.xml_doc(item.target_biblio_record_entry.marc); + title = ""; + FOR part IN bibxml.findnodes('//*[@tag="245"]/*[@code="a" or @code="b"]'); + title = title _ part.textContent; + END; + author = bibxml.findnodes('//*[@tag="100"]/*[@code="a"]').textContent; + + helpers.csv_datum(title) %],[% helpers.csv_datum(author) %],[% FOR note IN item.notes; helpers.csv_datum(note.note); ","; END; "\n"; +END -%] +$$ +); + COMMIT; diff --git a/Open-ILS/web/templates/default/opac/myopac/list/print.tt2 b/Open-ILS/web/templates/default/opac/myopac/list/print.tt2 new file mode 100644 index 0000000000..fa3988f7f0 --- /dev/null +++ b/Open-ILS/web/templates/default/opac/myopac/list/print.tt2 @@ -0,0 +1 @@ +[%- ctx.csv.template_output.data -%] diff --git a/Open-ILS/web/templates/default/opac/myopac/lists.tt2 b/Open-ILS/web/templates/default/opac/myopac/lists.tt2 index 3fe465b526..17f2f8dfc2 100644 --- a/Open-ILS/web/templates/default/opac/myopac/lists.tt2 +++ b/Open-ILS/web/templates/default/opac/myopac/lists.tt2 @@ -96,6 +96,13 @@ +
+
+ + + +
+
[% IF bbag.pub == 't' %]