1 package OpenILS::WWW::FlatFielder;
7 use Apache2::Const -compile => qw(
8 OK HTTP_NOT_ACCEPTABLE HTTP_PAYMENT_REQUIRED HTTP_INTERNAL_SERVER_ERROR :log
13 use CGI qw(:all -utf8);
15 use OpenSRF::Utils::JSON;
16 use OpenSRF::AppSession;
17 use OpenSRF::Utils::SettingsClient;
19 use OpenILS::Application::AppUtils;
20 my $U = 'OpenILS::Application::AppUtils';
23 my $_parser = new XML::LibXML;
24 my $_xslt = new XML::LibXSLT;
26 # BEGIN package globals
28 # We'll probably never need this fanciness for autosuggest, but
29 # you can add handlers for different requested content-types here, and
30 # you can weight them to control what matches requests for things like
35 my ($r, $args, $xslt) = @_;
36 $args->{'stylesheet'} =
37 OpenSRF::Utils::SettingsClient->new->config_value(dirs => 'xsl') . '/' . $xslt;
38 print data_to_xml($args);
39 return Apache2::Const::OK;
42 my $_output_handler_dispatch = {
47 $r->headers_out->set("Content-Disposition" => "attachment; filename=FlatSearch.csv");
48 # Anecdotally, IE 8 needs name= here to provoke downloads, where
49 # other browswers respect filename= in Content-Disposition. Also,
50 # we might want to make the filename choosable by CGI param later?
51 # Or vary it by timestamp?
52 $r->content_type('text/csv; name=FlatSearch.csv; charset=utf-8');
53 print_data_as_csv($args, \*STDOUT);
54 return Apache2::Const::OK;
60 $_[0]->content_type("text/html; charset=utf-8");
61 return html_ish_output( @_, 'FlatFielder2HTML.xsl' );
64 "application/xml" => {
68 $r->content_type("application/xml; charset=utf-8");
69 print data_to_xml($args);
70 return Apache2::Const::OK;
73 "application/json" => {
77 $r->content_type("application/json; charset=utf-8");
78 print data_to_json($args);
79 return Apache2::Const::OK;
84 my @_output_handler_types = sort {
85 $_output_handler_dispatch->{$a}->{prio} <=>
86 $_output_handler_dispatch->{$b}->{prio}
87 } keys %$_output_handler_dispatch;
93 <FlatSearch hint='foo' identifier='bar' label='Foo Bar' FS_key='ad1awe43a3a2a3ra32a23ra32ra23rar23a23r'>
95 <column name='fiz'>YAY!</column>
96 <column name='faz'>boooo</column>
99 <column name='fiz'>WHEEE!</column>
100 <column name='faz'>noooo</column>
109 my $dom = new XML::LibXML::Document("1.0", "UTF-8");
110 my $fs = $dom->createElement("FlatSearch");
111 $fs->setAttribute("hint", $args->{hint}) if $args->{hint};
112 $fs->setAttribute("identifier", $args->{id_field}) if $args->{id_field};
113 $fs->setAttribute("label", $args->{label_field}) if $args->{label_field};
114 $fs->setAttribute("FS_key", $args->{key}) if $args->{key};
115 $dom->setDocumentElement($fs);
119 if (@{$args->{columns}}) {
120 @columns = @{$args->{columns}};
121 if (@{$args->{labels}}) {
122 my @labels = @{$args->{labels}};
123 $column_labels{$columns[$_]} = $labels[$_] for (0..$#labels);
128 for my $i (@{$$args{data}}) {
129 my $item = $dom->createElement("row");
130 $item->setAttribute('ordinal', $rownum);
132 @columns = keys %$i unless @columns;
133 for my $k (@columns) {
134 my $val = $dom->createElement('column');
135 my $datum = $i->{$k};
136 $datum = join(" ", @$datum) if ref $datum eq 'ARRAY';
138 $val->setAttribute('name', $column_labels{$k} || $k);
139 $val->appendText($datum);
140 $item->addChild($val);
142 $fs->addChild($item);
145 # XML::LibXML::Document::toString() returns an encoded byte string, which
146 # is why we don't need to binmode STDOUT, ':utf8'.
148 return $_xslt->parse_stylesheet(
149 $_parser->parse_file( $$args{stylesheet} )
152 )->toString if ($$args{stylesheet}); # configured transform, early return
154 return $dom->toString();
157 sub print_data_as_csv {
158 my ($args, $fh) = @_;
160 my @keys = sort keys %{ $$args{data}[0] };
163 my $csv = new Text::CSV({ always_quote => 1, eol => "\r\n" });
165 $csv->print($fh, \@keys);
167 for my $row (@{$$args{data}}) {
168 $csv->print($fh, [map { $row->{$_} } @keys]);
175 # Turns out we don't want the data structure you'd use to initialize an
176 # itemfilereadstore or similar. We just want rows.
178 # return OpenSRF::Utils::JSON->perl2JSON({
179 # ($$args{hint} ? (hint => $$args{hint}) : ()),
180 # ($$args{id_field} ? (identifier => $$args{id_field}) : ()),
181 # ($$args{label_field} ? (label => $$args{label_field}) : ()),
182 # ($$args{key} ? (FS_key => $$args{key}) : ()),
183 # items => $$args{data}
185 return OpenSRF::Utils::JSON->perl2JSON($args->{data});
188 # Given data and the Apache request object, this sub picks a sub from a
189 # dispatch table based on the list of content-type encodings that the client
190 # has indicated it will accept, and calls that sub, which will deliver
191 # a response of appropriately encoded data.
195 my @types = split /,/, $r->headers_in->{Accept};
197 if ($$args{format}) {
198 unshift @types, $$args{format};
201 foreach my $media_range (@types) {
202 $media_range =~ s/;.+$//; # keep type, subtype. lose parameters.
205 Text::Glob::match_glob($media_range, $_)
206 } @_output_handler_types;
209 return $_output_handler_dispatch->{$match}{code}->($r, $args);
213 return Apache2::Const::HTTP_NOT_ACCEPTABLE;
221 $args{format} = $cgi->param('format');
222 $args{auth} = $cgi->param('ses');
223 $args{hint} = $cgi->param('hint');
224 $args{map} = OpenSRF::Utils::JSON->JSON2perl($cgi->param('map'));
225 $args{where} = OpenSRF::Utils::JSON->JSON2perl($cgi->param('where'));
226 $args{slo} = OpenSRF::Utils::JSON->JSON2perl($cgi->param('slo'));
227 $args{key} = $cgi->param('key');
228 $args{id_field} = $cgi->param('identifier');
229 $args{label_field} = $cgi->param('label');
230 $args{columns} = [ $cgi->param('columns') ];
231 $args{labels} = [ $cgi->param('labels') ];
233 my $fielder = OpenSRF::AppSession->create('open-ils.fielder');
235 $args{data} = $fielder->request(
236 'open-ils.fielder.flattened_search.atomic',
237 @args{qw/auth hint map where slo/}
240 $args{data} = $fielder->request(
241 'open-ils.fielder.flattened_search.execute.atomic',
242 @args{qw/auth key where slo/}
245 if (ref $args{data} and $args{data}[0] and
246 $U->event_equals($args{data}[0], 'CACHE_MISS')) {
248 # You have to pay the cache! I kill me.
249 return Apache2::Const::HTTP_PAYMENT_REQUIRED;
253 return output_handler( $r, \%args );