</permacrud>
</class>
+ <class id="atevdefg" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action_trigger::event_def_group" oils_persist:tablename="action_trigger.event_def_group" reporter:label="Trigger Event Definition Group" oils_persist:restrict_primary="100">
+ <fields oils_persist:primary="id" oils_persist:sequence="action_trigger.event_def_group_id_seq">
+ <field reporter:label="Definition ID" name="id" reporter:datatype="id"/>
+ <field reporter:label="Enabled" name="active" reporter:datatype="bool"/>
+ <field reporter:label="Owning Library" name="owner" reporter:datatype="org_unit"/>
+ <field reporter:label="Hook" name="hook" reporter:datatype="link"/>
+ <field reporter:label="Name" name="name" reporter:datatype="text"/>
+ <field reporter:label="Members" name="members" oils_persist:virtual="true" reporter:datatype="link"/>
+ </fields>
+ <links>
+ <link field="owner" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="hook" reltype="has_a" key="key" map="" class="ath"/>
+ <link field="members" reltype="has_many" key="grp" map="" class="atevdefgm"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="ADMIN_TRIGGER_EVENT_DEF CREATE_TRIGGER_EVENT_DEF" context_field="owner"/>
+ <retrieve permission="ADMIN_TRIGGER_EVENT_DEF VIEW_TRIGGER_EVENT_DEF" context_field="owner"/>
+ <update permission="ADMIN_TRIGGER_EVENT_DEF UPDATE_TRIGGER_EVENT_DEF" context_field="owner"/>
+ <delete permission="ADMIN_TRIGGER_EVENT_DEF DELETE_TRIGGER_EVENT_DEF" context_field="owner"/>
+ </actions>
+ </permacrud>
+ </class>
+
+ <class id="atevdefgm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action_trigger::event_def_group_member" oils_persist:tablename="action_trigger.event_def_group_member" reporter:label="Trigger Event Definition Group Member">
+ <fields oils_persist:primary="id" oils_persist:sequence="action_trigger.event_def_group_member_id_seq">
+ <field reporter:label="Definition ID" name="id" reporter:datatype="id"/>
+ <field reporter:label="Name" name="name" reporter:datatype="text"/>
+ <field reporter:label="Group" name="grp" reporter:datatype="link"/>
+ <field reporter:label="Definition" name="event_def" reporter:datatype="link"/>
+ <field reporter:label="Sortable" name="sortable" reporter:datatype="bool"/>
+ <field reporter:label="Include Holdings" name="holdings" reporter:datatype="bool"/>
+ <field reporter:label="Externally Processed" name="external" reporter:datatype="bool"/>
+ </fields>
+ <links>
+ <link field="grp" reltype="has_a" key="id" map="" class="atevdefg"/>
+ <link field="event_def" reltype="has_a" key="id" map="" class="atevdef"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="ADMIN_TRIGGER_EVENT_DEF CREATE_TRIGGER_EVENT_DEF">
+ <context link="grp" field="owner"/>
+ </create>
+ <retrieve permission="ADMIN_TRIGGER_EVENT_DEF VIEW_TRIGGER_EVENT_DEF">
+ <context link="grp" field="owner"/>
+ </retrieve>
+ <update permission="ADMIN_TRIGGER_EVENT_DEF UPDATE_TRIGGER_EVENT_DEF">
+ <context link="grp" field="owner"/>
+ </update>
+ <delete permission="ADMIN_TRIGGER_EVENT_DEF DELETE_TRIGGER_EVENT_DEF">
+ <context link="grp" field="owner"/>
+ </delete>
+ </actions>
+ </permacrud>
+ </class>
+
<class id="atev" controller="open-ils.cstore" oils_obj:fieldmapper="action_trigger::event" oils_persist:tablename="action_trigger.event" reporter:label="Trigger Event Entry">
<fields oils_persist:primary="id" oils_persist:sequence="action_trigger.event_id_seq">
<field reporter:label="Event ID" name="id" reporter:datatype="id"/>
// 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 = '';
} else {
this.configLinkBasePath += '/' + this.persistKeyPfx;
routerLink="/staff/admin/server/config/z3950_index_field_map"></eg-link-table-link>
<eg-link-table-link i18n-label label="Z39.50 Servers"
routerLink="/staff/admin/server/config/z3950_source"></eg-link-table-link>
+ <eg-link-table-link i18n-label label="Event Defintion Groups"
+ routerLink="/staff/admin/server/action_trigger/event_def_group"></eg-link-table-link>
+ <eg-link-table-link i18n-label label="Event Defintion Group Members"
+ routerLink="/staff/admin/server/action_trigger/event_def_group_member"></eg-link-table-link>
</eg-link-table>
</div>
use OpenILS::Utils::CStoreEditor q/:funcs/;
use OpenSRF::Utils::Cache;
use Encode;
+use Email::Send;
+use Email::Simple;
use OpenSRF::Utils::Logger qw/:logger/;
}
__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./,
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./,
);
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 ];
$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);
}
$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;
$unapi_args->{flesh},
$unapi_args->{site},
$unapi_args->{depth},
- $unapi_args->{flesh_depth},
+ $unapi_args->{flesh_limit},
]
};
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;
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]);
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;
$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|;
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|;
}
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
# ----------------------------------------------------------------
(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|;
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 {
}
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},
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);
}
}
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},
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);
}
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);
}
$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) {
};
} 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;
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;
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
$$
[%- 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 %]
<div>
<style> li { padding: 8px; margin 5px; }</style>
<ol>
- [% 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 %]
<li>
- Bib ID# [% bre_id %] ISBN: [% isbn %]<br />
- Title: [% title %]<br />
- Author: [% author %]<br />
- Publication Info: [% publisher %] [% pubdate %]<br/>
- Item Type: [% item_type %]
+ Bib ID# [% item.id %]<br />
+ [% IF item.isbn %]ISBN: [% item.isbn %]<br />[% END %]
+ [% IF item.issn %]ISSN: [% item.issn %]<br />[% END %]
+ [% IF item.upc %]UPC: [% item.upc %]<br />[% END %]
+ Title: [% item.title %]<br />
+[% IF item.author %] Author: [% item.author %]<br />[% END -%]
+ Publication Info: [% item.publisher %] [% item.pubdate %]<br/>
+ Item Type: [% item.item_type %]
+ <ul>
+ [% IF user_data.0.type == 'full' && item.holdings.size == 0 %]
+ <li>No items for this record at the selected location</li>
+ [% END %]
+ [% FOR cp IN item.holdings -%]
+ <li>
+ Library: [% cp.circ_lib %]<br/>
+ Location: [% cp.location %]<br/>
+ Call Number: [% cp.prefix _ ' ' _ cp.callnumber _ ' ' _ cp.suffix %]<br/>
+ [% IF cp.parts %]Parts: [% cp.parts %]<br/>[% END %]
+ Status: [% cp.status_label %]<br/>
+ Barcode: [% cp.barcode %]
+ </li>
+ [% END %]
+ </ul>
</li>
[% END %]
[% END %]
)
);
+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 (
--- /dev/null
+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 = $$
+<div>
+ <style> li { padding: 8px; margin 5px; }</style>
+ <ol>
+ [% 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 %]
+ <li>
+ Bib ID# [% item.id %]<br />
+ [% IF item.isbn %]ISBN: [% item.isbn %]<br />[% END %]
+ [% IF item.issn %]ISSN: [% item.issn %]<br />[% END %]
+ [% IF item.upc %]UPC: [% item.upc %]<br />[% END %]
+ Title: [% item.title %]<br />
+[% IF item.author %] Author: [% item.author %]<br />[% END -%]
+ Publication Info: [% item.publisher %] [% item.pubdate %]<br/>
+ Item Type: [% item.item_type %]
+ <ul>
+ [% IF user_data.0.type == 'full' && item.holdings.size == 0 %]
+ <li>No items for this record at the selected location</li>
+ [% END %]
+ [% FOR cp IN item.holdings -%]
+ <li>
+ Library: [% cp.circ_lib %]<br/>
+ Location: [% cp.location %]<br/>
+ Call Number: [% cp.prefix _ ' ' _ cp.callnumber _ ' ' _ cp.suffix %]<br/>
+ [% IF cp.parts %]Parts: [% cp.parts %]<br/>[% END %]
+ Status: [% cp.status_label %]<br/>
+ Barcode: [% cp.barcode %]
+ </li>
+ [% END %]
+ </ul>
+ </li>
+ [% END %]
+ [% END %]
+ </ol>
+</div>
+$$ WHERE hook = 'biblio.format.record_entry.print';
+
+COMMIT;
+
</form>
</div>
<form action="[% mkurl(ctx.opac_root _ '/mylist/move') %]" method="post">
+ <input type="hidden" name="anonsort" value="[% CGI.param('anonsort') %]" />
<input type="hidden" name="orig_referrer" value="[% CGI.referer | html %]" />
<input type="hidden" name="redirect_to" value="[% mkurl('', {}, ['list_none_selected', 'cart_none_selected']) %]" />
<div class="bbag-action" style="clear:both;">
<option value="">[% l('-- Basket Actions --') %]</option>
<option value="[% mkurl(ctx.opac_root _ '/mylist', {}) %]">[% l('View Basket') %]</option>
<option value="[% mkurl(ctx.opac_root _ '/mylist/move', { action => 'place_hold', entire_list => 1 }) %]">[% l('Place Holds') %]</option>
- <option value="[% mkurl(ctx.opac_root _ '/mylist/print', {}) %]">[% l('Print Title Details') %]</option>
- <option value="[% mkurl(ctx.opac_root _ '/mylist/email', {}) %]">[% l('Email Title Details') %]</option>
+ <option value="[% mkurl(ctx.opac_root _ '/mylist/move', { action => 'print', entire_list => 1}) %]">[% l('Print Title Details') %]</option>
+ <option value="[% mkurl(ctx.opac_root _ '/mylist/move', { action => 'email', entire_list => 1}) %]">[% l('Email Title Details') %]</option>
[% IF !ctx.is_browser_staff %]
<option value="[% mkurl(ctx.opac_root _ '/myopac/lists', { move_cart_by_default => 1, from_basket => 1 }) %]">[% l('Add Basket to Saved List') %]</option>
[% END %]
</div>
<div class="rdetail_aux_utils">
<img src="[% ctx.media_prefix %]/images/clipboard.png[% ctx.cache_key %]" alt="[% l('Print / Email Actions Image') %]" />
- <a href="[% mkurl(ctx.opac_root _ '/record/print/' _ ctx.bre_id) %]" class="no-dec" rel="nofollow" vocab="">[% l('Print') %]</a> /
- <a href="[% mkurl(ctx.opac_root _ '/record/email/' _ ctx.bre_id) %]" class="no-dec" rel="nofollow" vocab="">[% l('Email') %]</a>
+ <a href="[% mkurl(ctx.opac_root _ '/record/print_preview/' _ ctx.bre_id) %]" class="no-dec" rel="nofollow" vocab="">[% l('Print') %]</a> /
+ <a href="[% mkurl(ctx.opac_root _ '/record/email_preview/' _ ctx.bre_id) %]" class="no-dec" rel="nofollow" vocab="">[% l('Email') %]</a>
</div>
[%- IF ctx.refworks.enabled == 'true' %]
[%- INCLUDE 'opac/parts/record/refworks.tt2' %]
<div id="content-wrapper" class="content-wrapper-record-page">
<div id='main-content'>
<br/>
- [% IF ctx.user.email %]
- <h2 class='success'>[% l('Your email has been queued for delivery to [_1]', ctx.user.email ) %]</h2>
- [% ELSE %]
+ <h2 class='success'>[% l('Your email has been queued for delivery to [_1]', ctx.email ) %]</h2>
+ [% IF ctx.user && !ctx.user.email %]
<h2 class='error'>
- [% here_link_text = "<a href=\"${ctx.opac_root}/myopac/update_email?return_to_referer=1\">";
+ [% here_link_text = "<a href=\"${ctx.opac_root}/myopac/update_email\">";
here_link_text = here_link_text _ l("here");
here_link_text = here_link_text _ "</a>";
l('Your account does not currently have an email address set. Set your email address [_1]', here_link_text) %]
--- /dev/null
+[%- 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";
+-%]
+ <h2 class="sr-only">[% l('Email Record Preview') %]</h2>
+ [% INCLUDE "opac/parts/searchbar.tt2" %]
+ <br class="clear-both" />
+ <div id="content-wrapper" class="content-wrapper-record-page">
+
+ <form id="previewForm" method="POST" action="[% mkurl('',{},['locg','format','sort','sort_dir','context_org','bre_id','is_list']) %]">
+ <input type="hidden" name="old_event" value="[% ctx.preview_record.id %]"/>
+ <input type="hidden" name="bre_id" value="[% ctx.bre_id %]"/>
+ <input type="hidden" name="locg" value="[% ctx.selected_print_email_loc %]"/>
+ <input type="hidden" name="is_list" value="[% ctx.is_list %]"/>
+ <input type="hidden" name="redirect_to" value="[% ctx.redirect_to | html %]"/>
+
+ <div class="searchbar">
+ <label for="email">[% l('Email Address: ') %]
+ <input id="email" type="text" name="email" value="[% ctx.email || ctx.user.email %]"/>
+ </label>
+ </div>
+
+ <div class="searchbar">
+ <label for="subject">[% l('Custom Email Subject: ') %]
+ <input id="subject" type="text" name="subject" value="[% ctx.subject || '' %]"/>
+ </label>
+ </div>
+
+ <div class="searchbar">
+ <label for="formats">[% l('Format: ') %]
+ <select id="formats" name="format">
+ [% FOR f IN ctx.formats %]
+ [% IF !ctx.format_obj; ctx.format_obj = f; END %]
+ <option [% IF f.id == ctx.format; ctx.format_obj = f; 'selected="selected"'; END %] value="[% f.id %]">[% f.name | html %]</option>
+ [% END %]
+ </select>
+ </label>
+ </div>
+
+ [% IF ctx.is_list == '1' %]
+ <div class="searchbar">
+ <label for="sortby">[% l('Sort by: ') %]
+ <select id="sortby" name="sort">
+ <option [% IF ctx.sort == 'author'; 'selected="selected"'; END %] value="author">[% l('Author') %]</option>
+ <option [% IF ctx.sort == 'title'; 'selected="selected"'; END %] value="title">[% l('Title') %]</option>
+ <option [% IF ctx.sort == 'pubdate'; 'selected="selected"'; END %] value="pubdate">[% l('Publication Date') %]</option>
+ </select>
+ <select id="sort_dir" name="sort_dir">
+ <option [% IF ctx.sort_dir == 'ascending'; 'selected="selected"'; END %] value="ascending">[% l('Ascending') %]</option>
+ <option [% IF ctx.sort_dir == 'descending'; 'selected="selected"'; END %] value="descending">[% l('Descending') %]</option>
+ </select>
+ </label>
+ </div>
+ [% END %]
+
+ [% IF ctx.format_obj.holdings == 't' %]
+ <div class="searchbar">
+ <label for="context_org">[% l('Holdings Library: ') %]
+ [% INCLUDE build_org_selector id='context_org' name='context_org' value=ctx.selected_print_email_loc %]</br>
+ </label>
+ </div>
+ [% END %]
+
+ <br/>
+ <input type="submit" class="opac-button" value="[% l("Update") %]" />
+ <br/>
+ </form>
+
+ <hr/>
+
+ <form id="emailForm" method="POST" action="[% mkurl('../email/' _ ctx.preview_record.id,{},['locg','old_event','email','format','sort','bre_id','is_list']) %]">
+ <input type="hidden" name="old_event" value="[% ctx.preview_record.id %]"/>
+ <input type="hidden" name="bre_id" value="[% ctx.bre_id %]"/>
+ <input type="hidden" name="locg" value="[% ctx.selected_print_email_loc %]"/>
+ <input type="hidden" name="is_list" value="[% ctx.is_list %]"/>
+ <input type="hidden" name="redirect_to" value="[% ctx.redirect_to | html %]"/>
+ <input type="hidden" name="email" value="[% ctx.email || ctx.user.email %]"/>
+
+
+ [% IF ctx.preview_record.template_output %]
+ [% IF ctx.captcha.key %]
+ <div class="searchbar">
+ <p>[% l('Please prove you are not a robot by answering the following addition problem:') %]</p>
+ <p>[% ctx.captcha.left %] + [% ctx.captcha.right %] = <input type="text" name="capanswer"/></p>
+ <input type="hidden" name="capkey" value="[% ctx.captcha.key %]"/>
+ </div>
+ [% END %]
+ <input type="submit" class="opac-button" value="[% l("Email Now") %]"/> |
+ <a class="opac-button" href="[% ctx.redirect_to | html %]">[% l("Return") %]</a>
+ <br/>
+ <pre>[% ctx.preview_record.template_output.data %]</pre>
+ [% ELSE %]
+ <div class="print-error">
+ [% l(
+ 'Error previwing record: [_1]',
+ (ctx.preview_record.textcode ? ctx.preview_record.textcode _ ' / ' _ ctx.preview_record.desc : 0) ||
+ ctx.preview_record.error_output.data ||
+ l('No record data returned from server')
+ ) | html %]
+ </div>
+ <hr />
+ <div>
+ <a class="opac-button" href="[% ctx.redirect_to | html %]">[% l("Return") %]</a>
+ </div>
+ [% END %]
+ <br class="clear-both" />
+ </form>
+ </div>
+[%- END %]
<style type="text/css" media="print">.noprint {display: none}</style>
</head>
<body onload="if (document.getElementById('printable-record')) window.print();">
- [% IF ctx.printable_record.template_output %]
- <tt id="printable-record">
- [% ctx.printable_record.template_output.data %]
- </tt>
+ <div class='noprint'>
+ [% IF ctx.redirect_to %]
+ <p>[ <a href="[% ctx.redirect_to | html %]">[% l("Return") %]</a> ] </p>
+ [% ELSE %]
+ <p>[ <a href="[% mkurl(ctx.opac_root _ '/record/' _ ctx.bre_id) %]">[% l("Back to Record") %]</a> ]</p>
+ [% END %]
+ <hr />
+ </div>
+ [% IF ctx.print_data %]
+ <div id="printable-record">
+ [% ctx.print_data %]
+ </div>
[% ELSE %]
<div class="noprint print-error">
- [% l(
- 'Error printing record: [_1]',
- (ctx.printable_record.textcode ? ctx.printable_record.textcode _ ' / ' _ ctx.printable_record.desc : 0) ||
- ctx.printable_record.error_output.data ||
- l('No record data returned from server')
- ) | html %]
+ [% l( 'Error printing record: [_1]', l('No record data returned from server')) | html %]
</div>
[% END %]
<div class='noprint'>
--- /dev/null
+[%- 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";
+-%]
+ <h2 class="sr-only">[% l('Print Record Preview') %]</h2>
+ [% INCLUDE "opac/parts/searchbar.tt2" %]
+ <br class="clear-both" />
+ <div id="content-wrapper" class="content-wrapper-record-page">
+
+ <form id="previewForm" action="[% mkurl('',{},['locg','format','sort','sort_by','context_org','bre_id','is_list']) %]">
+ <input type="hidden" name="old_event" value="[% ctx.preview_record.id %]"/>
+ <input type="hidden" name="bre_id" value="[% ctx.bre_id %]"/>
+ <input type="hidden" name="locg" value="[% ctx.selected_print_email_loc %]"/>
+ <input type="hidden" name="is_list" value="[% ctx.is_list %]"/>
+ <input type="hidden" name="redirect_to" value="[% ctx.redirect_to | html %]"/>
+
+ <div class="searchbar">
+ <label for="formats">[% l('Format: ') %]
+ <select id="formats" name="format">
+ [% FOR f IN ctx.formats %]
+ [% IF !ctx.format_obj; ctx.format_obj = f; END %]
+ <option [% IF f.id == ctx.format; ctx.format_obj = f; 'selected="selected"'; END %] value="[% f.id %]">[% f.name | html %]</option>
+ [% END %]
+ </select>
+ </label>
+ </div>
+
+ [% IF ctx.is_list == '1' %]
+ <div class="searchbar">
+ <label for="sortby">[% l('Sort by: ') %]
+ <select id="sortby" name="sort">
+ <option [% IF ctx.sort == 'author'; 'selected="selected"'; END %] value="author">[% l('Author') %]</option>
+ <option [% IF ctx.sort == 'title'; 'selected="selected"'; END %] value="title">[% l('Title') %]</option>
+ <option [% IF ctx.sort == 'pubdate'; 'selected="selected"'; END %] value="pubdate">[% l('Publication Date') %]</option>
+ </select>
+ <select id="sort_dir" name="sort_dir">
+ <option [% IF ctx.sort_dir == 'ascending'; 'selected="selected"'; END %] value="ascending">[% l('Ascending') %]</option>
+ <option [% IF ctx.sort_dir == 'descending'; 'selected="selected"'; END %] value="descending">[% l('Descending') %]</option>
+ </select>
+ </label>
+ </div>
+ [% END %]
+
+ [% IF ctx.format_obj.holdings == 't' %]
+ <div class="searchbar">
+ <label for="context_org">[% l('Holdings Library: ') %]
+ [% INCLUDE build_org_selector id='context_org' name='context_org' value=ctx.selected_print_email_loc %]</br>
+ </label>
+ </div>
+ [% END %]
+
+ <br/>
+
+ <input type="submit" class="opac-button" value="[% l("Update") %]" />
+ <br/>
+ <hr/>
+
+ [% IF ctx.preview_record.template_output %]
+ <a class="opac-button" href="[% mkurl('../print/' _ ctx.preview_record.id, {redirect_to => ctx.redirect_to}) %]">[% l("Print Now") %]</a> |
+ <a class="opac-button" href="[% ctx.redirect_to | html %]">[% l("Return") %]</a>
+ <br/>
+ <div>[% ctx.preview_record.template_output.data %]</div>
+ [% ELSE %]
+ <div class="print-error">
+ [% l(
+ 'Error previwing record: [_1]',
+ (ctx.preview_record.textcode ? ctx.preview_record.textcode _ ' / ' _ ctx.preview_record.desc : 0) ||
+ ctx.preview_record.error_output.data ||
+ l('No record data returned from server')
+ ) | html %]
+ </div>
+ <hr />
+ <div>
+ <a class="opac-button" href="[% ctx.redirect_to | html %]">[% l("Return") %]</a>
+ </div>
+ [% END %]
+ <br class="clear-both" />
+ </form>
+ </div>
+[%- END %]
,[ l('Circulation Modifiers'), "./admin/server/config/circ_modifier" ]
,[ l('Circulation Recurring Fine Rules'), "./admin/server/config/rule_recurring_fine" ]
,[ l('Custom Org Unit Trees'), "./admin/server/actor/org_unit_custom_tree" ]
+ ,[ 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('Floating Groups'), "./admin/server/config/floating_groups" ]
,[ l('Global Flags'), "./admin/server/config/global_flag" ]
,[ l('Hard Due Date Changes'), "./admin/server/config/hard_due_date" ]