From: Mike Rylander Date: Thu, 1 Nov 2018 21:56:09 +0000 (-0400) Subject: LP#1749475: OPAC email/print record improvements X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=504c8fcdc6af6b4a587af21f7a41d0ac7a637fc9;p=working%2FEvergreen.git LP#1749475: OPAC email/print record improvements This commit provides new functionality for controlling and delivering print and email bibliographic record export options. Staff will be able to adjust existing and create new print and email formats using the Action/Trigger infrastructure and the new Event Definition Group capability. Patrons will be able to choose from one of several formats, as configured by staff, in which to receive one or more bibliographic records. Print and email preview is made available for individual records via the existing links on the record detail page, and for lists of records via new entry points on both the Basket (anonymous list) and My Lists interfaces. Signed-off-by: Mike Rylander Signed-off-by: Dan Wells --- diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index db651878bd..e5b3428814 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -1473,6 +1473,62 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/basic-admin-page.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/basic-admin-page.component.ts index d0b9224cf6..6cecebb80c 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/basic-admin-page.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/basic-admin-page.component.ts @@ -50,10 +50,10 @@ export class BasicAdminPageComponent implements OnInit { // the prefix because that will cause it to double-up. // e.g. eg.grid.acq.acq.cancel_reason this.persistKeyPfx = this.route.snapshot.parent.url[0].path; - const selfPrefixers = ['acq', 'booking']; + const selfPrefixers = ['acq', 'action_trigger', 'booking']; if (selfPrefixers.indexOf(this.persistKeyPfx) > -1) { - // ACQ is a special case, because unlike 'server', 'local', - // 'workstation', the schema ('acq') is the root of the path. + // selfPrefixers, unlike 'server', 'local', and + // 'workstation', are the root of the path. this.persistKeyPfx = ''; } diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html b/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html index 5e6058da9c..4b2dc03d25 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html @@ -95,5 +95,9 @@ routerLink="/staff/admin/server/config/z3950_index_field_map"> + + diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm index 159ecd78b9..b5435a1c84 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm @@ -10,6 +10,8 @@ use OpenSRF::Utils::SettingsClient; use OpenILS::Utils::CStoreEditor q/:funcs/; use OpenSRF::Utils::Cache; use Encode; +use Email::Send; +use Email::Simple; use OpenSRF::Utils::Logger qw/:logger/; @@ -1836,12 +1838,77 @@ sub biblio_record_to_marc_html { } __PACKAGE__->register_method( + method => "send_event_email_output", + api_name => "open-ils.search.biblio.record.email.send_output", +); +sub send_event_email_output { + my($self, $client, $auth, $event_id, $capkey, $capanswer) = @_; + return undef unless $event_id; + + my $captcha_pass = 0; + my $real_answer; + if ($capkey) { + $real_answer = $cache->get_cache(md5_hex($capkey)); + $captcha_pass++ if ($real_answer eq $capanswer); + } + + my $e = new_editor(authtoken => $auth); + return $e->die_event unless $captcha_pass || $e->checkauth; + + my $event = $e->retrieve_action_trigger_event([$event_id,{flesh => 1, flesh_fields => { atev => ['template_output']}}]); + return undef unless ($event and $event->template_output); + + my $smtp = OpenSRF::Utils::SettingsClient + ->new + ->config_value('email_notify', 'smtp_server'); + + my $sender = Email::Send->new({mailer => 'SMTP'}); + $sender->mailer_args([Host => $smtp]); + + my $stat; + my $err; + + my $email = Email::Simple->new($event->template_output->data); + + for my $hfield (qw/From To Subject Bcc Cc Reply-To Sender/) { + my @headers = $email->header($hfield); + $email->header_set($hfield => map { encode("MIME-Header", $_) } @headers) if ($headers[0]); + } + + $email->header_set('MIME-Version' => '1.0'); + $email->header_set('Content-Type' => "text/plain; charset=UTF-8"); + $email->header_set('Content-Transfer-Encoding' => '8bit'); + + try { + $stat = $sender->send($email); + } catch Error with { + $err = $stat = shift; + $logger->error("resend_at_email: Email failed with error: $err"); + }; + + return undef; +} + +__PACKAGE__->register_method( + method => "format_biblio_record_entry", + api_name => "open-ils.search.biblio.record.print.preview", +); + +__PACKAGE__->register_method( + method => "format_biblio_record_entry", + api_name => "open-ils.search.biblio.record.email.preview", +); + +__PACKAGE__->register_method( method => "format_biblio_record_entry", api_name => "open-ils.search.biblio.record.print", signature => { desc => 'Returns a printable version of the specified bib record', params => [ { desc => 'Biblio record entry ID or array of IDs', type => 'number' }, + { desc => 'Context library for holdings, if applicable' => 'number' }, + { desc => 'Sort order, if applicable' => 'string' }, + { desc => 'Definition Group Member id' => 'number' }, ], return => { desc => q/An action_trigger.event object or error event./, @@ -1857,6 +1924,13 @@ __PACKAGE__->register_method( params => [ { desc => 'Authentication token', type => 'string'}, { desc => 'Biblio record entry ID or array of IDs', type => 'number' }, + { desc => 'Context library for holdings, if applicable' => 'number' }, + { desc => 'Sort order, if applicable' => 'string' }, + { desc => 'Sort direction, if applicable' => 'string' }, + { desc => 'Definition Group Member id' => 'number' }, + { desc => 'Whether to bypass auth due to captcha' => 'bool' }, + { desc => 'Email address, if none for the user' => 'string' }, + { desc => 'Subject, if customized' => 'string' }, ], return => { desc => q/Undefined on success, otherwise an error event./, @@ -1866,25 +1940,44 @@ __PACKAGE__->register_method( ); sub format_biblio_record_entry { - my($self, $conn, $arg1, $arg2) = @_; + my($self, $conn, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $captcha_pass, $email, $subject) = @_; my $for_print = ($self->api_name =~ /print/); my $for_email = ($self->api_name =~ /email/); + my $preview = ($self->api_name =~ /preview/); - my $e; my $auth; my $bib_id; my $context_org; + my $e; my $auth; my $bib_id; my $context_org; my $holdings_context; my $bib_sort; my $group_member; my $type = 'brief'; my $sort_dir; if ($for_print) { $bib_id = $arg1; $context_org = $arg2 || $U->get_org_tree->id; + $holdings_context = $context_org; + $bib_sort = $arg3 || 'author'; + $sort_dir = $arg4 || 'ascending'; + $group_member = $arg5; $e = new_editor(xact => 1); } elsif ($for_email) { $auth = $arg1; $bib_id = $arg2; + $bib_sort = $arg4 || 'author'; + $sort_dir = $arg5 || 'ascending'; + $group_member = $arg6; $e = new_editor(authtoken => $auth, xact => 1); - return $e->die_event unless $e->checkauth; - $context_org = $e->requestor->home_ou; + return $e->die_event unless $captcha_pass || $e->checkauth; + $holdings_context = $arg3 || $U->get_org_tree->id; + $context_org = $e->requestor ? $e->requestor->home_ou : $arg3; + $email ||= $e->requestor ? $e->requestor->email : ''; + } + + if ($group_member) { + $group_member = $e->retrieve_action_trigger_event_def_group_member($group_member); + if ($group_member and $U->is_true($group_member->holdings)) { + $type = 'full'; + } } + $holdings_context = $e->retrieve_actor_org_unit($holdings_context); + my $bib_ids; if (ref $bib_id ne 'ARRAY') { $bib_ids = [ $bib_id ]; @@ -1896,7 +1989,7 @@ sub format_biblio_record_entry { $bucket->btype('temp'); $bucket->name('format_biblio_record_entry ' . $U->create_uuid_string); if ($for_email) { - $bucket->owner($e->requestor) + $bucket->owner($e->requestor || 1) } else { $bucket->owner(1); } @@ -1914,13 +2007,26 @@ sub format_biblio_record_entry { $e->commit; + my $usr_data = { + type => $type, + email => $email, + subject => $subject, + context_org => $holdings_context->shortname, + sort_by => $bib_sort, + sort_dir => $sort_dir, + preview => $preview + }; + if ($for_print) { - return $U->fire_object_event(undef, 'biblio.format.record_entry.print', [ $bucket ], $context_org); + return $U->fire_object_event(undef, 'biblio.format.record_entry.print', [ $bucket ], $context_org, undef, [ $usr_data ]); } elsif ($for_email) { - $U->create_events_for_hook('biblio.format.record_entry.email', $bucket, $context_org, undef, undef, 1); + return $U->fire_object_event(undef, 'biblio.format.record_entry.email', [ $bucket ], $context_org, undef, [ $usr_data ]) + if ($preview); + + $U->create_events_for_hook('biblio.format.record_entry.email', $bucket, $context_org, undef, $usr_data, 1); } return undef; 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 bf6b67eb2f..f011417cfc 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm @@ -418,7 +418,7 @@ $_TT_helpers = { $unapi_args->{flesh}, $unapi_args->{site}, $unapi_args->{depth}, - $unapi_args->{flesh_depth}, + $unapi_args->{flesh_limit}, ] }; @@ -427,6 +427,99 @@ $_TT_helpers = { return $_TT_helpers->{xml_doc}->($unapi->[0]->{'unapi.bre'}); }, + # input: list of bib bucket items; output: sorted list of unapi_bre objects + sort_bucket_unapi_bre => sub { + my ($list, $unapi_args, $sortby, $sortdir) = @_; + #$logger->info("sort_bucket_unapi_bre unapi_bre params: " . join(', ', map { "$_: $$unapi_args{$_}" } keys(%$unapi_args))); + my @sorted_list; + for my $i (@$list) { + my $xml = $_TT_helpers->{unapi_bre}->($i->target_biblio_record_entry, $unapi_args); + if ($xml) { + my $bib = { xml => $xml, id => $i->target_biblio_record_entry }; + + $$bib{title} = ''; + for my $part ($xml->findnodes('//*[@tag="245"]/*[@code="a" or @code="b"]')) { + $$bib{title} = $$bib{title} . $part->textContent; + } + $$bib{titlesort} = lc(substr($$bib{title}, $xml->findnodes('//*[@tag="245"]')->get_node(1)->getAttribute('ind2'))) + if ($$bib{title}); + + $$bib{authorsort} = $$bib{author} = $xml->findnodes('//*[@tag="100"]/*[@code="a"]')->to_literal_delimited(' '); + $$bib{authorsort} = lc($$bib{authorsort}); + $$bib{item_type} = $xml->findnodes('//*[local-name()="attributes"]/*[local-name()="field"][@name="item_type"]')->get_node(1)->getAttribute('coded-value'); + my $p = $xml->findnodes('//*[@tag="260" or @tag="264"]/*[@code="b"]')->get_node(1); + $$bib{publisher} = $p ? $p->textContent : ''; + $$bib{pubdatesort} = $$bib{pubdate} = $xml->findnodes('//*[local-name()="attributes"]/*[local-name()="field"][@name="date1"]')->get_node(1)->textContent; + $$bib{pubdatesort} = lc($$bib{pubdatesort}); + $$bib{isbn} = $xml->findnodes('//*[@tag="020"]/*[@code="a"]')->to_literal_delimited(', '); + $$bib{issn} = $xml->findnodes('//*[@tag="022"]/*[@code="a"]')->to_literal_delimited(', '); + $$bib{upc} = $xml->findnodes('//*[@tag="024"]/*[@code="a"]')->to_literal_delimited(', '); + + $$bib{holdings} = []; + + for my $vol ($xml->findnodes('//*[local-name()="volume" and @deleted="false" and @opac_visible="true"]')) { + my $vol_data = {}; + $$vol_data{prefix_sort} = $vol->findnodes('.//*[local-name()="call_number_prefix"]')->get_node(1)->getAttribute('label_sortkey'); + $$vol_data{prefix} = $vol->findnodes('.//*[local-name()="call_number_prefix"]')->get_node(1)->getAttribute('label'); + $$vol_data{callnumber} = $vol->getAttribute('label'); + $$vol_data{callnumber_sort} = $vol->getAttribute('label_sortkey'); + $$vol_data{suffix_sort} = $vol->findnodes('.//*[local-name()="call_number_suffix"]')->get_node(1)->getAttribute('label_sortkey'); + $$vol_data{suffix} = $vol->findnodes('.//*[local-name()="call_number_suffix"]')->get_node(1)->getAttribute('label'); + #$logger->info("sort_bucket_unapi_bre found volume: " . join(', ', map { "$_: $$vol_data{$_}" } keys(%$vol_data))); + + my @copies; + for my $cp ($vol->findnodes('.//*[local-name()="copy" and @deleted="false"]')) { + my $cp_data = {%$vol_data}; + my $l = $cp->findnodes('.//*[local-name()="location" and @opac_visible="true"]')->get_node(1); + next unless ($l); + $$cp_data{location} = $l->textContent; + + my $s = $cp->findnodes('.//*[local-name()="status" and @opac_visible="true"]')->get_node(1); + next unless ($s); + $$cp_data{status_label} = $s->textContent; + $$cp_data{status_id} = $s->getAttribute('ident'); + + my $c = $cp->findnodes('.//*[local-name()="circ_lib" and @opac_visible="true"]')->get_node(1); + next unless ($c); + $$cp_data{circ_lib} = $c->getAttribute('name'); + + $$cp_data{barcode} = $cp->getAttribute('barcode'); + + $$cp_data{parts} = ''; + for my $mp ($cp->findnodes('.//*[local-name()="monograph_part"]')) { + $$cp_data{parts} .= ', ' if $$cp_data{parts}; + $$cp_data{parts} .= $mp->textContent; + } + push @copies, $cp_data; + #$logger->info("sort_bucket_unapi_bre found copy: " . join(', ', map { "$_: $$cp_data{$_}" } keys(%$cp_data))); + } + if (@copies) { + push @{$$bib{holdings}}, @copies; + } + } + + # sort 'em! + $$bib{holdings} = [ sort { + $$a{circ_lib} cmp $$b{circ_lib} || + $$a{location} cmp $$b{location} || + $$a{prefix_sort} cmp $$b{prefix_sort} || + $$a{callnumber_sort} cmp $$b{callnumber_sort} || + $$a{suffix_sort} cmp $$b{suffix_sort} || + ($$a{status_id} == 0 ? -1 : 0) || + ($$a{status_id} == 7 ? -1 : 0) || + $$a{status_label} cmp $$b{status_label}; + } @{$$bib{holdings}} ]; + + push @sorted_list, $bib; + } + } + + if ($sortdir =~ /^d/) { + return [ sort { $$b{$sortby.'sort'} cmp $$a{$sortby.'sort'} } @sorted_list ]; + } + return [ sort { $$a{$sortby.'sort'} cmp $$b{$sortby.'sort'} } @sorted_list ]; + }, + # escapes quotes in csv string values escape_csv => sub { my $string = shift; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/SendEmail.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/SendEmail.pm index 9dd76ee454..10e32e1a17 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/SendEmail.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/SendEmail.pm @@ -49,6 +49,10 @@ sub handler { my $text = encode_utf8($self->run_TT($env)); return 0 if (!$text); + if ($$env{user_data} && ref($$env{user_data}) =~ /HASH/ && $$env{user_data}{preview}) { + $logger->info("SendEmail Reactor: success in preview mode, not sending email"); + return 1; + } my $sender = Email::Send->new({mailer => 'SMTP'}); $sender->mailer_args([Host => $smtp]); diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index 19a3b258a8..e66d84ebe2 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -12,6 +12,7 @@ use OpenSRF::Utils::Logger qw/$logger/; use OpenILS::Application::AppUtils; use OpenILS::Utils::CStoreEditor qw/:funcs/; use OpenILS::Utils::Fieldmapper; +use OpenSRF::Utils::Cache; use DateTime::Format::ISO8601; use CGI qw(:all -utf8); use Time::HiRes; @@ -133,6 +134,9 @@ sub load { $path =~ /opac\/my(opac\/lists|list)/ || $path =~ m!opac/api/mylist!; + my $org_unit = $self->ctx->{physical_loc} || $self->cgi->param('context_org') || $self->_get_search_lib; + $self->ctx->{selected_print_email_loc} = $org_unit; + return $self->load_api_mylist_retrieve if $path =~ m|opac/api/mylist/retrieve|; return $self->load_api_mylist_add if $path =~ m|opac/api/mylist/add|; return $self->load_api_mylist_delete if $path =~ m|opac/api/mylist/delete|; @@ -145,6 +149,7 @@ sub load { return $self->load_library if $path =~ m|opac/library|; return $self->load_rresults if $path =~ m|opac/results|; + return $self->load_print_or_email_preview('print') if $path =~ m|opac/record/print_preview|; return $self->load_print_record if $path =~ m|opac/record/print|; return $self->load_record if $path =~ m|opac/record/\d|; return $self->load_cnbrowse if $path =~ m|opac/cnbrowse|; @@ -184,11 +189,36 @@ sub load { } if ($path =~ m|opac/sms_cn| and !$self->editor->requestor) { - my $org_unit = $self->ctx->{physical_loc} || $self->cgi->param('loc') || $self->ctx->{aou_tree}->()->id; my $skip_sms_auth = $self->ctx->{get_org_setting}->($org_unit, 'sms.disable_authentication_requirement.callnumbers'); return $self->load_sms_cn if $skip_sms_auth; } + if (!$self->editor->requestor && $path =~ m|opac/record/email|) { + if ($self->ctx->{get_org_setting}->($org_unit, 'opac.email_record.allow_without_login')) { + my $cache = OpenSRF::Utils::Cache->new('global'); + + if ($path !~ m|preview|) { # the real thing! + $logger->info("not preview"); + my $cap_key = $self->ctx->{cap}->{key} = $self->cgi->param('capkey'); + $logger->info("got cap_key $cap_key"); + if ($cap_key) { + my $cap_answer = $self->ctx->{cap_answer} = $self->cgi->param('capanswer'); + my $real_answer = $self->ctx->{real_answer} = $cache->get_cache(md5_hex($cap_key)); + $logger->info("got answers $cap_answer $real_answer"); + return $self->load_email_record(1) if ( $cap_answer eq $real_answer ); + } + } + + my $captcha = {}; + $$captcha{key} = time() . $$ . rand(); + $$captcha{left} = int(rand(10)); + $$captcha{right} = int(rand(10)); + $cache->put_cache(md5_hex($$captcha{key}), $$captcha{left} + $$captcha{right}); + $self->ctx->{captcha} = $captcha; + return $self->load_print_or_email_preview('email', 1) if $path =~ m|opac/record/email_preview|; + } + } + # ---------------------------------------------------------------- # Everything below here requires authentication # ---------------------------------------------------------------- @@ -202,7 +232,9 @@ sub load { (undef, $self->ctx->{mylist}) = $self->fetch_mylist; } $self->load_simple("mylist/email") if $path =~ m|opac/mylist/email|; + return $self->load_print_or_email_preview('email') if $path =~ m|opac/mylist/doemail_preview|; return $self->load_mylist_email if $path =~ m|opac/mylist/doemail|; + return $self->load_print_or_email_preview('email') if $path =~ m|opac/record/email_preview|; return $self->load_email_record if $path =~ m|opac/record/email|; return $self->load_place_hold if $path =~ m|opac/place_hold|; 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 3ec7900939..f107218d24 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm @@ -2640,10 +2640,42 @@ sub load_myopac_bookbag_update { return $self->generic_redirect($url); } elsif ($action eq 'print') { - my $temp_cache_key = $self->_stash_record_list_in_anon_cache(@selected_item); + my ($incoming_sort,$sort_dir) = $self->_get_bookbag_sort_params('sort'); + $sort_dir = $self->cgi->param('sort_dir') if $self->cgi->param('sort_dir'); + if (!$incoming_sort) { + ($incoming_sort,$sort_dir) = $self->_get_bookbag_sort_params('anonsort'); + } + if (!$incoming_sort) { + $incoming_sort = 'author'; + } + + $incoming_sort =~ s/sort.*$//; + + $self->ctx->{sort} = $incoming_sort; + $self->ctx->{sort_dir} = $sort_dir; + + my $items = $self->editor->search_container_biblio_record_entry_bucket_item({id=>\@selected_item}); + my @bib_ids = map { $_->target_biblio_record_entry } @$items; + my $temp_cache_key = $self->_stash_record_list_in_anon_cache(@bib_ids); return $self->load_mylist_print($temp_cache_key); } elsif ($action eq 'email') { - my $temp_cache_key = $self->_stash_record_list_in_anon_cache(@selected_item); + my ($incoming_sort,$sort_dir) = $self->_get_bookbag_sort_params('sort'); + $sort_dir = $self->cgi->param('sort_dir') if $self->cgi->param('sort_dir'); + if (!$incoming_sort) { + ($incoming_sort,$sort_dir) = $self->_get_bookbag_sort_params('anonsort'); + } + if (!$incoming_sort) { + $incoming_sort = 'author'; + } + + $incoming_sort =~ s/sort.*$//; + + $self->ctx->{sort} = $incoming_sort; + $self->ctx->{sort_dir} = $sort_dir; + + my $items = $self->editor->search_container_biblio_record_entry_bucket_item({id=>\@selected_item}); + my @bib_ids = map { $_->target_biblio_record_entry } @$items; + my $temp_cache_key = $self->_stash_record_list_in_anon_cache(@bib_ids); return $self->load_mylist_email($temp_cache_key); } else { diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm index 6b076720ee..89ccdd08c4 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm @@ -205,7 +205,7 @@ sub load_mylist_print { } my $url = sprintf( - "%s://%s%s/record/print/%s", + "%s://%s%s/record/print_preview/%s", $self->ctx->{proto}, $self->ctx->{hostname}, $self->ctx->{opac_root}, @@ -215,8 +215,12 @@ sub load_mylist_print { my $redirect = $self->cgi->param('redirect_to'); $url .= '?redirect_to=' . uri_escape_utf8($redirect); my $clear_cart = $self->cgi->param('clear_cart'); - $url .= '&is_list=1'; $url .= '&clear_cart=1' if $clear_cart; + my $sort = $self->cgi->param('sort') || $self->cgi->param('anonsort'); + my $sort_dir = $self->cgi->param('sort_dir'); + $url .= '&sort='.$sort if $sort; + $url .= '&sort_dir='.$sort_dir if $sort_dir; + $url .= '&is_list=1'; return $self->generic_redirect($url); } @@ -231,7 +235,7 @@ sub load_mylist_email { } my $url = sprintf( - "%s://%s%s/record/email/%s", + "%s://%s%s/record/email_preview/%s", $self->ctx->{proto}, $self->ctx->{hostname}, $self->ctx->{opac_root}, @@ -241,8 +245,12 @@ sub load_mylist_email { my $redirect = $self->cgi->param('redirect_to'); $url .= '?redirect_to=' . uri_escape_utf8($redirect); my $clear_cart = $self->cgi->param('clear_cart'); - $url .= '&is_list=1'; $url .= '&clear_cart=1' if $clear_cart; + my $sort = $self->cgi->param('sort') || $self->cgi->param('anonsort'); + my $sort_dir = $self->cgi->param('sort_dir'); + $url .= '&sort='.$sort if $sort; + $url .= '&sort_dir='.$sort_dir if $sort_dir; + $url .= '&is_list=1'; return $self->generic_redirect($url); } @@ -279,10 +287,16 @@ sub load_mylist_move { return $self->load_myopac_bookbag_update('place_hold', undef, @rec_ids); } if ($action eq 'print') { + if ($self->cgi->param('entire_list')) { + @rec_ids = @$list; + } my $temp_cache_key = $self->_stash_record_list_in_anon_cache(@rec_ids); return $self->load_mylist_print($temp_cache_key); } if ($action eq 'email') { + if ($self->cgi->param('entire_list')) { + @rec_ids = @$list; + } my $temp_cache_key = $self->_stash_record_list_in_anon_cache(@rec_ids); return $self->load_mylist_email($temp_cache_key); } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm index c071c2452b..a9e39c2870 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm @@ -506,13 +506,30 @@ sub get_hold_copy_summary { $search->kill_me; } -sub load_print_record { +sub load_print_or_email_preview { my $self = shift; + my $type = shift; + my $captcha_pass = shift; + + my $ctx = $self->ctx; + my $e = new_editor(xact => 1); + my $old_event = $self->cgi->param('old_event'); + if ($old_event) { + $old_event = $e->retrieve_action_trigger_event([ + $old_event, + {flesh => 1, flesh_fields => { atev => ['template_output'] }} + ]); + $e->delete_action_trigger_event($old_event) if ($old_event); + $e->delete_action_trigger_event_output($old_event->template_output) if ($old_event && $old_event->template_output); + $e->commit; + } - my $rec_or_list_id = $self->ctx->{page_args}->[0] + my $rec_or_list_id = $ctx->{page_args}->[0] or return Apache2::Const::HTTP_BAD_REQUEST; - my $is_list = $self->cgi->param('is_list'); + $ctx->{bre_id} = $rec_or_list_id; + + my $is_list = $ctx->{is_list} = $self->cgi->param('is_list'); my $list; if ($is_list) { @@ -532,12 +549,88 @@ sub load_print_record { }; } else { $list = $rec_or_list_id; - $self->{ctx}->{bre_id} = $rec_or_list_id; + $ctx->{bre_id} = $rec_or_list_id; } - $self->{ctx}->{printable_record} = $U->simplereq( - 'open-ils.search', - 'open-ils.search.biblio.record.print', $list); + $ctx->{sortable} = (ref($list) && @$list > 1); + + my $group = $type eq 'print' ? 1 : 2; + + $ctx->{formats} = $self->editor->search_action_trigger_event_def_group_member([{grp => $group},{order_by => { atevdefgm => 'name'}}]); + $ctx->{format} = $self->cgi->param('format') || $ctx->{formats}[0]->id; + if ($type eq 'email') { + $ctx->{email} = $self->cgi->param('email') || ($ctx->{user} ? $ctx->{user}->email : ''); + $ctx->{subject} = $self->cgi->param('subject'); + } + + my $context_org = $self->cgi->param('context_org'); + if ($context_org) { + $context_org = $self->ctx->{get_aou}->($context_org); + } + + if (!$context_org) { + $context_org = $self->ctx->{get_aou}->($self->_get_search_lib()) || + $self->ctx->{aou_tree}->(); + } + + $ctx->{context_org} = $context_org->id; + + my ($incoming_sort,$sort_dir) = $self->_get_bookbag_sort_params('sort'); + $sort_dir = $self->cgi->param('sort_dir') if $self->cgi->param('sort_dir'); + if (!$incoming_sort) { + ($incoming_sort,$sort_dir) = $self->_get_bookbag_sort_params('anonsort'); + } + if (!$incoming_sort) { + $incoming_sort = 'author'; + } + + $incoming_sort =~ s/sort.*$//; + + $incoming_sort = 'author' + unless (grep {$_ eq $incoming_sort} qw/title author pubdate/); + + $ctx->{sort} = $incoming_sort; + $ctx->{sort_dir} = $sort_dir; + + my $method = "open-ils.search.biblio.record.$type.preview"; + my @args = ( + $list, + $ctx->{context_org}, + $ctx->{sort}, + $ctx->{sort_dir}, + $ctx->{format}, + $captcha_pass, + $ctx->{email}, + $ctx->{subject} + ); + + unshift(@args, $ctx->{authtoken}) if ($type eq 'email'); + + $ctx->{preview_record} = $U->simplereq( + 'open-ils.search', $method, @args); + + $ctx->{'redirect_to'} = $self->cgi->param('redirect_to') || $self->cgi->referer; + + return Apache2::Const::OK; +} + +sub load_print_record { + my $self = shift; + + my $event_id = $self->ctx->{page_args}->[0] + or return Apache2::Const::HTTP_BAD_REQUEST; + + my $event = $self->editor->retrieve_action_trigger_event([ + $event_id, + {flesh => 1, flesh_fields => { atev => ['template_output'] }} + ]); + + return Apache2::Const::HTTP_BAD_REQUEST + unless ($event and $event->template_output and $event->template_output->data); + + $self->ctx->{bre_id} = $self->cgi->param('bre_id'); + $self->ctx->{is_list} = $self->cgi->param('is_list'); + $self->ctx->{print_data} = $event->template_output->data; if ($self->cgi->param('clear_cart')) { $self->clear_anon_cache; @@ -549,37 +642,40 @@ sub load_print_record { sub load_email_record { my $self = shift; + my $captcha_pass = shift; - my $rec_or_list_id = $self->ctx->{page_args}->[0] + my $event_id = $self->ctx->{page_args}->[0] or return Apache2::Const::HTTP_BAD_REQUEST; - my $is_list = $self->cgi->param('is_list'); - my $list; - if ($is_list) { + my $e = new_editor(xact => 1, authtoken => $self->ctx->{authtoken}); + return Apache2::Const::HTTP_BAD_REQUEST + unless $captcha_pass || $e->checkauth; - $list = $U->simplereq( - 'open-ils.actor', - 'open-ils.actor.anon_cache.get_value', - $rec_or_list_id, (ref $self)->CART_CACHE_MYLIST); + my $event = $e->retrieve_action_trigger_event([ + $event_id, + {flesh => 1, flesh_fields => { atev => ['template_output'] }} + ]); - if(!$list) { - $list = []; - } + return Apache2::Const::HTTP_BAD_REQUEST + unless ($event and $event->template_output and $event->template_output->data); - { # sanitize - no warnings qw/numeric/; - $list = [map { int $_ } @$list]; - $list = [grep { $_ > 0} @$list]; - }; - } else { - $list = $rec_or_list_id; - $self->{ctx}->{bre_id} = $rec_or_list_id; - } + $self->ctx->{email} = $self->cgi->param('email'); + $self->ctx->{subject} = $self->cgi->param('subject'); + $self->ctx->{bre_id} = $self->cgi->param('bre_id'); + $self->ctx->{is_list} = $self->cgi->param('is_list'); + $self->ctx->{print_data} = $event->template_output->data; $U->simplereq( 'open-ils.search', - 'open-ils.search.biblio.record.email', - $self->ctx->{authtoken}, $list); + 'open-ils.search.biblio.record.email.send_output', + $self->ctx->{authtoken}, $event_id, + $self->ctx->{cap}->{key}, $self->ctx->{cap_answer}); + + # Move the output to async so it can't be used in a resend attack + $event->async_output($event->template_output->id); + $event->clear_template_output; + $e->update_action_trigger_event($event); + $e->commit; if ($self->cgi->param('clear_cart')) { $self->clear_anon_cache; diff --git a/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql b/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql index 50fa9d65f0..4d9e9e9dac 100644 --- a/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql +++ b/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql @@ -285,6 +285,33 @@ CREATE TABLE action_trigger.event_params ( CONSTRAINT event_params_event_def_param_once UNIQUE (event_def,param) ); +CREATE TABLE action_trigger.event_def_group ( + id SERIAL PRIMARY KEY, + owner INT NOT NULL REFERENCES actor.org_unit (id) + ON DELETE RESTRICT ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + hook TEXT NOT NULL REFERENCES action_trigger.hook (key) + ON DELETE RESTRICT ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + active BOOL NOT NULL DEFAULT TRUE, + name TEXT NOT NULL +); +SELECT SETVAL('action_trigger.event_def_group_id_seq'::TEXT, 100, TRUE); + +CREATE TABLE action_trigger.event_def_group_member ( + id SERIAL PRIMARY KEY, + grp INT NOT NULL REFERENCES action_trigger.event_def_group (id) + ON DELETE CASCADE ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + event_def INT NOT NULL REFERENCES action_trigger.event_definition (id) + ON DELETE RESTRICT ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + sortable BOOL NOT NULL DEFAULT TRUE, + holdings BOOL NOT NULL DEFAULT FALSE, + external BOOL NOT NULL DEFAULT FALSE, + name TEXT NOT NULL +); + CREATE OR REPLACE FUNCTION action_trigger.purge_events() RETURNS VOID AS $_$ /** * Deleting expired events without simultaneously deleting their outputs diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index 80db67122d..9f9e99a1f4 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -11816,39 +11816,47 @@ INSERT INTO action_trigger.event_definition ( $$ [%- USE date -%] [%- SET user = target.0.owner -%] -To: [%- params.recipient_email || user.email %] +To: [%- params.recipient_email || user_data.0.email || user.email %] From: [%- params.sender_email || default_sender %] Date: [%- date.format(date.now, '%a, %d %b %Y %T -0000', gmt => 1) %] -Subject: Bibliographic Records +Subject: [%- user_data.0.subject || 'Bibliographic Records' %] Auto-Submitted: auto-generated -[% FOR cbreb IN target %] -[% FOR item IN cbreb.items; - bre_id = item.target_biblio_record_entry; +[% FOR cbreb IN target; - bibxml = helpers.unapi_bre(bre_id, {flesh => '{mra}'}); - title = ''; - FOR part IN bibxml.findnodes('//*[@tag="245"]/*[@code="a" or @code="b"]'); - title = title _ part.textContent; + flesh_list = '{mra'; + IF user_data.0.type == 'full'; + flesh_list = flesh_list _ ',holdings_xml,acp'; + IF params.holdings_limit; + flimit = 'acn=>' _ params.holdings_limit _ ',acp=>' _ params.holdings_limit; + END; END; + flesh_list = flesh_list _ '}'; + + item_list = helpers.sort_bucket_unapi_bre(cbreb.items,{flesh => flesh_list, site => user_data.0.context_org, flesh_limit => flimit}, user_data.0.sort_by, user_data.0.sort_dir); + +FOR item IN item_list %] + +[% loop.count %]/[% loop.size %]. Bib ID# [% item.id %] +[% IF item.isbn %]ISBN: [% item.isbn _ "\n" %][% END -%] +[% IF item.issn %]ISSN: [% item.issn _ "\n" %][% END -%] +[% IF item.upc %]UPC: [% item.upc _ "\n" %][% END -%] +Title: [% item.title %] +[% IF item.author %]Author: [% item.author _ "\n" %][% END -%] +Publication Info: [% item.publisher %] [% item.pubdate %] +Item Type: [% item.item_type %] +[% IF user_data.0.type == 'full' && item.holdings.size == 0 %] + * No items for this record at the selected location +[% END %] +[% FOR cp IN item.holdings -%] + * Library: [% cp.circ_lib %] + Location: [% cp.location %] + Call Number: [% cp.prefix _ ' ' _ cp.callnumber _ ' ' _ cp.suffix %] +[% IF cp.parts %] Parts: [% cp.parts _ "\n" %][% END -%] + Status: [% cp.status_label %] + Barcode: [% cp.barcode %] - author = bibxml.findnodes('//*[@tag="100"]/*[@code="a"]').textContent; - item_type = bibxml.findnodes('//*[local-name()="attributes"]/*[local-name()="field"][@name="item_type"]').getAttribute('coded-value'); - publisher = bibxml.findnodes('//*[@tag="260"]/*[@code="b"]').textContent; - pubdate = bibxml.findnodes('//*[@tag="260"]/*[@code="c"]').textContent; - isbn = bibxml.findnodes('//*[@tag="020"]/*[@code="a"]').textContent; - issn = bibxml.findnodes('//*[@tag="022"]/*[@code="a"]').textContent; - upc = bibxml.findnodes('//*[@tag="024"]/*[@code="a"]').textContent; -%] - -[% loop.count %]/[% loop.size %]. Bib ID# [% bre_id %] -[% IF isbn %]ISBN: [% isbn _ "\n" %][% END -%] -[% IF issn %]ISSN: [% issn _ "\n" %][% END -%] -[% IF upc %]UPC: [% upc _ "\n" %] [% END -%] -Title: [% title %] -Author: [% author %] -Publication Info: [% publisher %] [% pubdate %] -Item Type: [% item_type %] +[% END %] [% END %] [% END %] @@ -11871,29 +11879,43 @@ $$
    - [% FOR cbreb IN target %] - [% FOR item IN cbreb.items; - bre_id = item.target_biblio_record_entry; - - bibxml = helpers.unapi_bre(bre_id, {flesh => '{mra}'}); - title = ''; - FOR part IN bibxml.findnodes('//*[@tag="245"]/*[@code="a" or @code="b"]'); - title = title _ part.textContent; - END; + [% FOR cbreb IN target; - author = bibxml.findnodes('//*[@tag="100"]/*[@code="a"]').textContent; - item_type = bibxml.findnodes('//*[local-name()="attributes"]/*[local-name()="field"][@name="item_type"]').getAttribute('coded-value'); - publisher = bibxml.findnodes('//*[@tag="260"]/*[@code="b"]').textContent; - pubdate = bibxml.findnodes('//*[@tag="260"]/*[@code="c"]').textContent; - isbn = bibxml.findnodes('//*[@tag="020"]/*[@code="a"]').textContent; - %] + flesh_list = '{mra'; + IF user_data.0.type == 'full'; + flesh_list = flesh_list _ ',holdings_xml,acp'; + IF params.holdings_limit; + flimit = 'acn=>' _ params.holdings_limit _ ',acp=>' _ params.holdings_limit; + END; + END; + flesh_list = flesh_list _ '}'; + item_list = helpers.sort_bucket_unapi_bre(cbreb.items,{flesh => flesh_list, site => user_data.0.context_org, flesh_limit => flimit}, user_data.0.sort_by, user_data.0.sort_dir); + FOR item IN item_list %]
  1. - Bib ID# [% bre_id %] ISBN: [% isbn %]
    - Title: [% title %]
    - Author: [% author %]
    - Publication Info: [% publisher %] [% pubdate %]
    - Item Type: [% item_type %] + Bib ID# [% item.id %]
    + [% IF item.isbn %]ISBN: [% item.isbn %]
    [% END %] + [% IF item.issn %]ISSN: [% item.issn %]
    [% END %] + [% IF item.upc %]UPC: [% item.upc %]
    [% END %] + Title: [% item.title %]
    +[% IF item.author %] Author: [% item.author %]
    [% END -%] + Publication Info: [% item.publisher %] [% item.pubdate %]
    + Item Type: [% item.item_type %] +
      + [% IF user_data.0.type == 'full' && item.holdings.size == 0 %] +
    • No items for this record at the selected location
    • + [% END %] + [% FOR cp IN item.holdings -%] +
    • + Library: [% cp.circ_lib %]
      + Location: [% cp.location %]
      + Call Number: [% cp.prefix _ ' ' _ cp.callnumber _ ' ' _ cp.suffix %]
      + [% IF cp.parts %]Parts: [% cp.parts %]
      [% END %] + Status: [% cp.status_label %]
      + Barcode: [% cp.barcode %] +
    • + [% END %] +
  2. [% END %] [% END %] @@ -19500,6 +19522,35 @@ VALUES ( ) ); +INSERT into config.org_unit_setting_type +( name, grp, label, description, datatype, fm_class ) VALUES +( 'opac.email_record.allow_without_login', 'opac', + oils_i18n_gettext('opac.email_record.allow_without_login', + 'Allow record emailing without login', + 'coust', 'label'), + oils_i18n_gettext('opac.email_record.allow_without_login', + 'Instead of forcing a patron to log in in order to email the details of a record, just challenge them with a simple catpcha.', + 'coust', 'description'), + 'bool', null) +; + +INSERT INTO action_trigger.event_def_group (id, owner, hook, name) + VALUES (1, 1, 'biblio.format.record_entry.print','Print Record(s)'); + +INSERT INTO action_trigger.event_def_group_member (grp, name, event_def) + SELECT 1, 'Brief', id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.print'; + +INSERT INTO action_trigger.event_def_group_member (grp, name, holdings, event_def) + SELECT 1, 'Full', TRUE, id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.print'; + +INSERT INTO action_trigger.event_def_group (id, owner, hook, name) + VALUES (2,1,'biblio.format.record_entry.email','Email Record(s)'); + +INSERT INTO action_trigger.event_def_group_member (grp, name, event_def) + SELECT 2, 'Brief', id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.email'; + +INSERT INTO action_trigger.event_def_group_member (grp, name, holdings, event_def) + SELECT 2, 'Full', TRUE, id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.email'; INSERT into config.org_unit_setting_type (name, label, description, datatype) VALUES ( diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.AT-def-groups.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.AT-def-groups.sql new file mode 100644 index 0000000000..573aabb243 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.AT-def-groups.sql @@ -0,0 +1,160 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +INSERT into config.org_unit_setting_type +( name, grp, label, description, datatype, fm_class ) VALUES +( 'opac.email_record.allow_without_login', 'opac', + oils_i18n_gettext('opac.email_record.allow_without_login', + 'Allow record emailing without login', + 'coust', 'label'), + oils_i18n_gettext('opac.email_record.allow_without_login', + 'Instead of forcing a patron to log in in order to email the details of a record, just challenge them with a simple catpcha.', + 'coust', 'description'), + 'bool', null) +; + +CREATE TABLE action_trigger.event_def_group ( + id SERIAL PRIMARY KEY, + owner INT NOT NULL REFERENCES actor.org_unit (id) + ON DELETE RESTRICT ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + hook TEXT NOT NULL REFERENCES action_trigger.hook (key) + ON DELETE RESTRICT ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + active BOOL NOT NULL DEFAULT TRUE, + name TEXT NOT NULL +); +SELECT SETVAL('action_trigger.event_def_group_id_seq'::TEXT, 100, TRUE); + +CREATE TABLE action_trigger.event_def_group_member ( + id SERIAL PRIMARY KEY, + grp INT NOT NULL REFERENCES action_trigger.event_def_group (id) + ON DELETE CASCADE ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + event_def INT NOT NULL REFERENCES action_trigger.event_definition (id) + ON DELETE RESTRICT ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + sortable BOOL NOT NULL DEFAULT TRUE, + holdings BOOL NOT NULL DEFAULT FALSE, + external BOOL NOT NULL DEFAULT FALSE, + name TEXT NOT NULL +); + +INSERT INTO action_trigger.event_def_group (id, owner, hook, name) + VALUES (1, 1, 'biblio.format.record_entry.print','Print Record(s)'); + +INSERT INTO action_trigger.event_def_group_member (grp, name, event_def) + SELECT 1, 'Brief', id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.print'; + +INSERT INTO action_trigger.event_def_group_member (grp, name, holdings, event_def) + SELECT 1, 'Full', TRUE, id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.print'; + +INSERT INTO action_trigger.event_def_group (id, owner, hook, name) + VALUES (2,1,'biblio.format.record_entry.email','Email Record(s)'); + +INSERT INTO action_trigger.event_def_group_member (grp, name, event_def) + SELECT 2, 'Brief', id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.email'; + +INSERT INTO action_trigger.event_def_group_member (grp, name, holdings, event_def) + SELECT 2, 'Full', TRUE, id FROM action_trigger.event_definition WHERE hook = 'biblio.format.record_entry.email'; + +UPDATE action_trigger.event_definition SET template = $$ +[%- USE date -%] +[%- SET user = target.0.owner -%] +To: [%- params.recipient_email || user_data.0.email || user.email %] +From: [%- params.sender_email || default_sender %] +Date: [%- date.format(date.now, '%a, %d %b %Y %T -0000', gmt => 1) %] +Subject: [%- user_data.0.subject || 'Bibliographic Records' %] +Auto-Submitted: auto-generated + +[% FOR cbreb IN target; + + flesh_list = '{mra'; + IF user_data.0.type == 'full'; + flesh_list = flesh_list _ ',holdings_xml,acp'; + IF params.holdings_limit; + flimit = 'acn=>' _ params.holdings_limit _ ',acp=>' _ params.holdings_limit; + END; + END; + flesh_list = flesh_list _ '}'; + + item_list = helpers.sort_bucket_unapi_bre(cbreb.items,{flesh => flesh_list, site => user_data.0.context_org, flesh_limit => flimit}, user_data.0.sort_by, user_data.0.sort_dir); + +FOR item IN item_list %] + +[% loop.count %]/[% loop.size %]. Bib ID# [% item.id %] +[% IF item.isbn %]ISBN: [% item.isbn _ "\n" %][% END -%] +[% IF item.issn %]ISSN: [% item.issn _ "\n" %][% END -%] +[% IF item.upc %]UPC: [% item.upc _ "\n" %][% END -%] +Title: [% item.title %] +[% IF item.author %]Author: [% item.author _ "\n" %][% END -%] +Publication Info: [% item.publisher %] [% item.pubdate %] +Item Type: [% item.item_type %] +[% IF user_data.0.type == 'full' && item.holdings.size == 0 %] + * No items for this record at the selected location +[% END %] +[% FOR cp IN item.holdings -%] + * Library: [% cp.circ_lib %] + Location: [% cp.location %] + Call Number: [% cp.prefix _ ' ' _ cp.callnumber _ ' ' _ cp.suffix %] +[% IF cp.parts %] Parts: [% cp.parts _ "\n" %][% END -%] + Status: [% cp.status_label %] + Barcode: [% cp.barcode %] + +[% END %] + +[% END %] +[% END %] +$$ WHERE hook = 'biblio.format.record_entry.email'; + +UPDATE action_trigger.event_definition SET template = $$ +
    + +
      + [% FOR cbreb IN target; + + flesh_list = '{mra'; + IF user_data.0.type == 'full'; + flesh_list = flesh_list _ ',holdings_xml,acp'; + IF params.holdings_limit; + flimit = 'acn=>' _ params.holdings_limit _ ',acp=>' _ params.holdings_limit; + END; + END; + flesh_list = flesh_list _ '}'; + + item_list = helpers.sort_bucket_unapi_bre(cbreb.items,{flesh => flesh_list, site => user_data.0.context_org, flesh_limit => flimit}, user_data.0.sort_by, user_data.0.sort_dir); + FOR item IN item_list %] +
    1. + Bib ID# [% item.id %]
      + [% IF item.isbn %]ISBN: [% item.isbn %]
      [% END %] + [% IF item.issn %]ISSN: [% item.issn %]
      [% END %] + [% IF item.upc %]UPC: [% item.upc %]
      [% END %] + Title: [% item.title %]
      +[% IF item.author %] Author: [% item.author %]
      [% END -%] + Publication Info: [% item.publisher %] [% item.pubdate %]
      + Item Type: [% item.item_type %] +
        + [% IF user_data.0.type == 'full' && item.holdings.size == 0 %] +
      • No items for this record at the selected location
      • + [% END %] + [% FOR cp IN item.holdings -%] +
      • + Library: [% cp.circ_lib %]
        + Location: [% cp.location %]
        + Call Number: [% cp.prefix _ ' ' _ cp.callnumber _ ' ' _ cp.suffix %]
        + [% IF cp.parts %]Parts: [% cp.parts %]
        [% END %] + Status: [% cp.status_label %]
        + Barcode: [% cp.barcode %] +
      • + [% END %] +
      +
    2. + [% END %] + [% END %] +
    +
    +$$ WHERE hook = 'biblio.format.record_entry.print'; + +COMMIT; + diff --git a/Open-ILS/src/templates/opac/parts/anon_list.tt2 b/Open-ILS/src/templates/opac/parts/anon_list.tt2 index 56fbd6cee5..3cfec09a45 100644 --- a/Open-ILS/src/templates/opac/parts/anon_list.tt2 +++ b/Open-ILS/src/templates/opac/parts/anon_list.tt2 @@ -13,6 +13,7 @@
+
diff --git a/Open-ILS/src/templates/opac/parts/cart.tt2 b/Open-ILS/src/templates/opac/parts/cart.tt2 index ae587bcb80..171e97018b 100644 --- a/Open-ILS/src/templates/opac/parts/cart.tt2 +++ b/Open-ILS/src/templates/opac/parts/cart.tt2 @@ -4,8 +4,8 @@ - - + + [% IF !ctx.is_browser_staff %] [% END %] diff --git a/Open-ILS/src/templates/opac/parts/record/summary.tt2 b/Open-ILS/src/templates/opac/parts/record/summary.tt2 index 3bc0ef5855..fbc54a5348 100644 --- a/Open-ILS/src/templates/opac/parts/record/summary.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/summary.tt2 @@ -139,8 +139,8 @@
[%- IF ctx.refworks.enabled == 'true' %] [%- INCLUDE 'opac/parts/record/refworks.tt2' %] diff --git a/Open-ILS/src/templates/opac/record/email.tt2 b/Open-ILS/src/templates/opac/record/email.tt2 index 88cf88cd76..f086b993fb 100644 --- a/Open-ILS/src/templates/opac/record/email.tt2 +++ b/Open-ILS/src/templates/opac/record/email.tt2 @@ -8,11 +8,10 @@

- [% IF ctx.user.email %] -

[% l('Your email has been queued for delivery to [_1]', ctx.user.email ) %]

- [% ELSE %] +

[% l('Your email has been queued for delivery to [_1]', ctx.email ) %]

+ [% IF ctx.user && !ctx.user.email %]

- [% here_link_text = ""; + [% here_link_text = ""; here_link_text = here_link_text _ l("here"); here_link_text = here_link_text _ ""; l('Your account does not currently have an email address set. Set your email address [_1]', here_link_text) %] diff --git a/Open-ILS/src/templates/opac/record/email_preview.tt2 b/Open-ILS/src/templates/opac/record/email_preview.tt2 new file mode 100644 index 0000000000..969809117f --- /dev/null +++ b/Open-ILS/src/templates/opac/record/email_preview.tt2 @@ -0,0 +1,111 @@ +[%- PROCESS "opac/parts/header.tt2"; + WRAPPER "opac/parts/base.tt2"; + INCLUDE "opac/parts/topnav.tt2"; + ctx.page_title = l("Email Record Preview"); + PROCESS "opac/parts/org_selector.tt2"; +-%] +

[% l('Email Record Preview') %]

+ [% INCLUDE "opac/parts/searchbar.tt2" %] +
+
+ + + + + + + + + + + + + + + [% IF ctx.is_list == '1' %] + + [% END %] + + [% IF ctx.format_obj.holdings == 't' %] + + [% END %] + +
+ +
+ + +
+ +
+ + + + + + + + + [% IF ctx.preview_record.template_output %] + [% IF ctx.captcha.key %] + + [% END %] + | + [% l("Return") %] +
+
[% ctx.preview_record.template_output.data %]
+ [% ELSE %] + +
+ + [% END %] +
+
+
+[%- END %] diff --git a/Open-ILS/src/templates/opac/record/print.tt2 b/Open-ILS/src/templates/opac/record/print.tt2 index 26c35432a8..c1b55a4a3f 100644 --- a/Open-ILS/src/templates/opac/record/print.tt2 +++ b/Open-ILS/src/templates/opac/record/print.tt2 @@ -6,18 +6,21 @@ - [% IF ctx.printable_record.template_output %] - - [% ctx.printable_record.template_output.data %] - +
+ [% IF ctx.redirect_to %] +

[ [% l("Return") %] ]

+ [% ELSE %] +

[ [% l("Back to Record") %] ]

+ [% END %] +
+
+ [% IF ctx.print_data %] +
+ [% ctx.print_data %] +
[% ELSE %] [% END %]
diff --git a/Open-ILS/src/templates/opac/record/print_preview.tt2 b/Open-ILS/src/templates/opac/record/print_preview.tt2 new file mode 100644 index 0000000000..8fc58390bb --- /dev/null +++ b/Open-ILS/src/templates/opac/record/print_preview.tt2 @@ -0,0 +1,82 @@ +[%- PROCESS "opac/parts/header.tt2"; + WRAPPER "opac/parts/base.tt2"; + INCLUDE "opac/parts/topnav.tt2"; + ctx.page_title = l("Print Record Preview"); + PROCESS "opac/parts/org_selector.tt2"; +-%] +

[% l('Print Record Preview') %]

+ [% INCLUDE "opac/parts/searchbar.tt2" %] +
+
+ +
+ + + + + + + + + [% IF ctx.is_list == '1' %] + + [% END %] + + [% IF ctx.format_obj.holdings == 't' %] + + [% END %] + +
+ + +
+
+ + [% IF ctx.preview_record.template_output %] + [% l("Print Now") %] | + [% l("Return") %] +
+
[% ctx.preview_record.template_output.data %]
+ [% ELSE %] + +
+ + [% END %] +
+
+
+[%- END %] diff --git a/Open-ILS/src/templates/staff/admin/server/t_splash.tt2 b/Open-ILS/src/templates/staff/admin/server/t_splash.tt2 index c03666f6b5..677cc0c735 100644 --- a/Open-ILS/src/templates/staff/admin/server/t_splash.tt2 +++ b/Open-ILS/src/templates/staff/admin/server/t_splash.tt2 @@ -26,6 +26,8 @@ ,[ l('Circulation Max Fine Rules'), "./admin/server/config/rule_max_fine" ] ,[ l('Circulation Modifiers'), "./admin/server/config/circ_modifier" ] ,[ l('Circulation Recurring Fine Rules'), "./admin/server/config/rule_recurring_fine" ] + ,[ l('Event Definition Groups'), "/eg2/staff/admin/server/action_trigger/event_def_group" ] + ,[ l('Event Definition Group Members'), "/eg2/staff/admin/server/action_trigger/event_def_group_member" ] ,[ l('Item Statuses'), "./admin/server/legacy/config/copy_status" ] ,[ l('Item Tag Types'), "./admin/server/config/copy_tag_type" ] ,[ l('Custom Org Unit Trees'), "./admin/server/actor/org_unit_custom_tree" ]