]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor.pm
Merge branch 'master' of git://git.evergreen-ils.org/Evergreen into ttopac
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Trigger / Reactor.pm
1 package OpenILS::Application::Trigger::Reactor;
2 use strict; use warnings;
3 use Encode qw/ encode /;
4 use Template;
5 use DateTime;
6 use DateTime::Format::ISO8601;
7 use Unicode::Normalize;
8 use OpenSRF::Utils qw/:datetime/;
9 use OpenSRF::Utils::Logger qw(:logger);
10 use OpenILS::Application::AppUtils;
11 use OpenILS::Utils::CStoreEditor qw/:funcs/;
12 my $U = 'OpenILS::Application::AppUtils';
13
14 sub fourty_two { return 42 }
15 sub NOOP_True  { return  1 }
16 sub NOOP_False { return  0 }
17
18
19
20 # helper functions inserted into the TT environment
21 my $_TT_helpers = {
22
23     # turns a date into something TT can understand
24     format_date => sub {
25         my $date = shift;
26         $date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($date));
27         return sprintf(
28             "%0.2d:%0.2d:%0.2d %0.2d-%0.2d-%0.4d",
29             $date->hour,
30             $date->minute,
31             $date->second,
32             $date->day,
33             $date->month,
34             $date->year
35         );
36     },
37
38     # escapes a string for inclusion in an XML document.  escapes &, <, and > characters
39     escape_xml => sub {
40         my $str = shift;
41         $str =~ s/&/&amp;/sog;
42         $str =~ s/</&lt;/sog;
43         $str =~ s/>/&gt;/sog;
44         return $str;
45     },
46
47     escape_json => sub {
48         my $str = shift;
49         $str =~ s/([\x{0080}-\x{fffd}])/sprintf('\u%0.4x',ord($1))/sgoe;
50         return $str;
51     },
52
53     # encode email headers in UTF-8, per RFC2231
54     escape_email_header => sub {
55         my $str = shift;
56         $str = encode("MIME-Header", $str);
57         return $str;
58     },
59
60     # strip non-ASCII characters after splitting base characters and diacritics
61     # least common denominator for EDIFACT messages using the UNOB character set
62     force_jedi_unob => sub {
63         my $str = shift;
64         $str = NFD($str);
65         $str =~ s/[\x{0080}-\x{fffd}]//g;
66         return $str;
67     },
68
69     # returns the calculated user locale
70     get_user_locale => sub { 
71         my $user_id = shift;
72         return $U->get_user_locale($user_id);
73     },
74
75     # returns the calculated copy price
76     get_copy_price => sub {
77         my $copy_id = shift;
78         return $U->get_copy_price(new_editor(xact=>1), $copy_id);
79     },
80
81     # given a copy, returns the title and author in a hash
82     get_copy_bib_basics => sub {
83         my $copy_id = shift;
84         my $copy = new_editor(xact=>1)->retrieve_asset_copy([
85             $copy_id,
86             {
87                 flesh => 2,
88                 flesh_fields => {
89                     acp => ['call_number'],
90                     acn => ['record']
91                 }
92             }
93         ]);
94         if($copy->call_number->id == -1) {
95             return {
96                 title  => $copy->dummy_title,
97                 author => $copy->dummy_author,
98             };
99         } else {
100             my $mvr = $U->record_to_mvr($copy->call_number->record);
101             return {
102                 title  => $mvr->title,
103                 author => $mvr->author
104             };
105         }
106     },
107
108     # returns the org unit setting value
109     get_org_setting => sub {
110         my($org_id, $setting) = @_;
111         return $U->ou_ancestor_setting_value($org_id, $setting);
112     },
113
114     # This basically greps/maps out ths isbn string values, but also promotes the first isbn-13 to the
115     # front of the line (so that the EDI translator takes it as primary) if there is one.
116     get_li_isbns => sub {
117         my $attrs = shift;
118         my @isbns;
119         my $primary;
120         foreach (@$attrs) {
121             $_->attr_name eq 'isbn' or next;
122             my $val = $_->attr_value;
123             if (! $primary and length($val) == 13) {
124                 $primary = $val;
125             } else {
126                 push @isbns, $val;
127             }
128         }
129         $primary and unshift @isbns, $primary;
130         $logger->debug("get_li_isbns returning isbns: " . join(', ', @isbns));
131         return @isbns;
132     },
133
134     # helpers.get_li_attr('isbn_13', li.attributes)
135     # returns matching line item attribute, or undef
136     get_li_attr => sub {
137         my $name = shift or return;     # the first arg is always the name
138         my ($type, $attr) = (scalar(@_) == 1) ? (undef, $_[0]) : @_;
139         # if the next is the last, it's the attributes, otherwise type
140         # use Data::Dumper; $logger->warn("get_li_attr: " . Dumper($attr));
141         ($name and @$attr) or return;
142         my $length;
143         $name =~ s/^(\D+)_(\d+)$/$1/ and $length = $2;
144         foreach (@$attr) {
145             $_->attr_name eq $name or next;
146             next if $length and $length != length($_->attr_value);
147             return $_->attr_value if (! $type) or $type eq $_->attr_type;
148         }
149         return;
150     },
151
152     get_queued_bib_attr => sub {
153         my $name = shift or return;     # the first arg is always the name
154         my ($attr) = @_;
155         # use Data::Dumper; $logger->warn("get_queued_bib_attr: " . Dumper($attr));
156         ($name and @$attr) or return;
157
158         my $query = {
159             select => {'vqbrad' => ['id']},
160             from => 'vqbrad',
161             where => {code => $name}
162         };
163
164         my $def_ids = new_editor()->json_query($query);
165         @$def_ids or return;
166
167         my $length;
168         $name =~ s/^(\D+)_(\d+)$/$1/ and $length = $2;
169         foreach (@$attr) {
170             $_->field eq @{$def_ids}[0]->{id} or next;
171             next if $length and $length != length($_->attr_value);
172             return $_->attr_value;
173         }
174         return;
175     },
176
177     get_queued_auth_attr => sub {
178         my $name = shift or return;     # the first arg is always the name
179         my ($attr) = @_;
180         # use Data::Dumper; $logger->warn("get_queued_auth_attr: " . Dumper($attr));
181         ($name and @$attr) or return;
182
183         my $query = {
184             select => {'vqarad' => ['id']},
185             from => 'vqarad',
186             where => {code => $name}
187         };
188
189         my $def_ids = new_editor()->json_query($query);
190         @$def_ids or return;
191
192         my $length;
193         $name =~ s/^(\D+)_(\d+)$/$1/ and $length = $2;
194         foreach (@$attr) {
195             $_->field eq @{$def_ids}[0]->{id} or next;
196             next if $length and $length != length($_->attr_value);
197             return $_->attr_value;
198         }
199         return;
200     },
201
202 };
203
204
205 # processes templates.  Returns template output on success, undef on error
206 sub run_TT {
207     my $self = shift;
208     my $env = shift;
209     my $nostore = shift;
210     return undef unless $env->{template};
211
212     my $error;
213     my $output = '';
214     my $tt = Template->new;
215     # my $tt = Template->new(ENCODING => 'utf8');   # ??
216     $env->{helpers} = $_TT_helpers;
217
218     unless( $tt->process(\$env->{template}, $env, \$output) ) {
219         $output = undef;
220         ($error = $tt->error) =~ s/\n/ /og;
221         $logger->error("Error processing Trigger template: $error");
222     }
223
224     if ( $error or (!$nostore && $output) ) {
225         my $t_o = Fieldmapper::action_trigger::event_output->new;
226         $t_o->data( ($error) ? $error : $output );
227         $t_o->is_error( ($error) ? 't' : 'f' );
228         $logger->info("trigger: writing " . length($t_o->data) . " bytes to template output");
229
230         $env->{EventProcessor}->editor->xact_begin;
231         $t_o = $env->{EventProcessor}->editor->create_action_trigger_event_output( $t_o );
232
233         my $state = (ref $$env{event} eq 'ARRAY') ? $$env{event}->[0]->state : $env->{event}->state;
234         my $key = ($error) ? 'error_output' : 'template_output';
235         $env->{EventProcessor}->update_state( $state, { $key => $t_o->id } );
236     }
237         
238     return $output;
239 }
240
241
242 1;