<event code='3' textcode='NO_CHANGE'>
<desc xml:lang="en-US">No change occurred</desc>
</event>
+
+ <event code='4' textcode='CACHE_MISS'>
+ <desc xml:lang="en-US">A cached object could not be retrieved by the given reference.</desc>
+ </event>
+
<event code='1000' textcode='LOGIN_FAILED'>
<desc xml:lang="en-US">User login failed</desc>
</event>
__PACKAGE__->register_method(
method => 'register_map',
api_name => 'open-ils.fielder.flattened_search.prepare',
- argc => 2,
+ argc => 3,
signature => {
params => [
{name => "auth", type => "string", desc => "auth token"},
my $e = new_editor(authtoken => $auth);
return $e->event unless $e->checkauth;
+ $e->disconnect;
- my $blob = $cache->get_cache( $key );
+ my $blob = $cache->get_cache( $key ) or
+ return new OpenILS::Event('CACHE_MISS');
flattened_search( $self, $conn, $auth, $blob->{hint}, $blob->{map}, @_ )
if (ref($blob) and $blob->{hint} and $blob->{map});
use Apache2::Log;
use Apache2::Const -compile => qw(
- OK HTTP_NOT_ACCEPTABLE HTTP_INTERNAL_SERVER_ERROR :log
+ OK HTTP_NOT_ACCEPTABLE HTTP_PAYMENT_REQUIRED HTTP_INTERNAL_SERVER_ERROR :log
);
use XML::LibXML;
use XML::LibXSLT;
use OpenSRF::AppSession;
use OpenSRF::Utils::SettingsClient;
+use OpenILS::Application::AppUtils;
+my $U = 'OpenILS::Application::AppUtils';
+
my $_parser = new XML::LibXML;
my $_xslt = new XML::LibXSLT;
sub html_ish_output {
my ($r, $args, $xslt) = @_;
$args->{'stylesheet'} =
- OpenSRF::Utils::SettingsClient->new->config_value(dirs => 'xsl') . $xslt;
+ OpenSRF::Utils::SettingsClient->new->config_value(dirs => 'xsl') . '/' . $xslt;
print data_to_xml($args);
return Apache2::Const::OK;
}
"code" => sub {
my ($r, $args) = @_;
$r->headers_out->set("Content-Disposition" => "attachment; filename=FlatSearch.csv");
- $r->content_type('text/csv; name=FlatSearch.csv; charset=utf-8');
- return data_to_csv( $args );
+ $r->content_type('text/csv; charset=utf-8');
+ print_data_as_csv($args, \*STDOUT);
+ return Apache2::Const::OK;
}
},
"text/html" => {
"prio" => 0,
"code" => sub {
$_[0]->content_type("text/html; charset=utf-8");
- return html_ish_output( @_, 'FlatFielder2HTML.xsl' );
+ print html_ish_output( @_, 'FlatFielder2HTML.xsl' );
+ return Apache2::Const::OK;
}
},
"application/xml" => {
return $dom->toString();
}
-sub data_to_csv {
- my ($args) = @_;
-
- my @keys = sort { $a cmp $b } keys %{ $$args{data}[0] };
- return if (!@keys);
+sub print_data_as_csv {
+ my ($args, $fh) = @_;
- my $output = quote_for_csv(@keys);
+ my @keys = sort keys %{ $$args{data}[0] };
+ return unless @keys;
- for my $i (@{$$args{data}}) {
- $output = quote_for_csv(
- map { $$args{data}[$i]{$_} } @keys
- );
- }
+ my $csv = new Text::CSV({ always_quote => 1, eol => "\r\n" });
- return $output;
-}
+ $csv->print($fh, \@keys);
-sub quote_for_csv {
- return '"' . join('","', map { s/"/""/g } @_ ) . "\"\015\012";
+ for my $row (@{$$args{data}}) {
+ $csv->print($fh, [map { $row->{$_} } @keys]);
+ }
}
sub data_to_json {
'open-ils.fielder.flattened_search.execute.atomic',
@args{qw/auth key where slo/}
)->gather(1);
+
+ if (ref $args{data} and $args{data}[0] and
+ $U->event_equals($args{data}[0], 'CACHE_MISS')) {
+
+ # You have to pay the cache! I kill me.
+ return Apache2::Const::HTTP_PAYMENT_REQUIRED;
+ }
}
return output_handler( $r, \%args );
query="{'owner': 'BR1'}">
<thead>
<tr>
- <th field="barcode" fpath="barcode">Barcode</th>
+ <th field="barcode" fpath="barcode" ffilter="true">Barcode</th>
<th field="owner" fpath="owner.shortname" ffilter="true">Circulation Library</th>
<th field="resource_type" fpath="type.name">Resource type</th>
</tr>
dojo.provide("openils.FlattenerStore");
+ dojo.require("DojoSRF");
dojo.require("openils.User");
dojo.require("openils.Util");
},
"_prepare_flattener_params": function(req) {
- var content = {
+ var params = {
"hint": this.fmClass,
"ses": openils.User.authtoken
};
var where = {};
where[this.fmIdentifier] = req.identity;
- content.where = dojo.toJson(where);
+ params.where = dojo.toJson(where);
} else {
var limit = (!isNaN(req.count) && req.count != Infinity) ?
req.count : this.limit;
req.start : this.offset;
dojo.mixin(
- content, {
+ params, {
"where": dojo.toJson(req.query),
"slo": dojo.toJson({
"sort": this._prepare_sort(req.sort),
}
if (this.mapKey) { /* XXX TODO, get a map key */
- content.key = this.mapKey;
+ params.key = this.mapKey;
} else {
- content.map = dojo.toJson(this.mapClause);
+ params.map = dojo.toJson(this.mapClause);
}
- return content;
+ for (var key in params)
+ console.debug("flattener param " + key + " -> " + params[key]);
+
+ return params;
},
"_display_attributes": function() {
function(key) { return self.mapClause[key].display; }
);
},
+
+ "_get_map_key": function() {
+ console.debug("mapClause: " + dojo.toJson(this.mapClause));
+ this.mapKey = fieldmapper.standardRequest(
+ ["open-ils.fielder",
+ "open-ils.fielder.flattened_search.prepare"], {
+ "params": [openils.User.authtoken, this.fmClass,
+ this.mapClause],
+ "async": false
+ }
+ );
+ },
+
/* *** Begin dojo.data.api.Read methods *** */
"getValue": function(
// the one we provide does nothing but issue an alert().
console.info("fetch(" + dojo.toJson(req) + ")");
+ var self = this;
+ var callback_scope = req.scope || dojo.global;
- // this._current_items={}; /* I'm pretty sure we don't want this */
+ if (!this.mapKey) {
+ try {
+ this._get_map_key();
+ } catch (E) {
+ if (req.onError)
+ req.onError.call(callback_scope, E);
+ else
+ throw E;
+ }
+ }
- var callback_scope = req.scope || dojo.global;
var post_params = this._prepare_flattener_params(req);
if (!post_params) {
return;
}
- var self = this;
var process_fetch = function(obj, when) {
if (when < self._last_fetch) /* Stale response. Discard. */
return;
+ self._retried_map_key_already = false;
+
/* The following is apparently the "right" way to call onBegin,
* and is very necessary (at least in Dojo 1.3.3) to get
* the Grid's fetch-more-when-I-need-it logic to work
"sync": false,
"preventCache": true,
"headers": {"Accept": "application/json"},
- "load": function(obj) { process_fetch(obj, fetch_time); }
+ "load": function(obj) { process_fetch(obj, fetch_time); },
+ "error": function(response, ioArgs) {
+ if (response.status == 402) { /* 'Payment Required' stands
+ in for cache miss */
+ if (self._retried_map_key_already) {
+ console.error("Server won't cache flattener map?");
+ } else {
+ self._retried_map_key_already = true;
+ delete self.mapKey;
+ return self.fetch(req);
+ }
+ }
+ }
});
/* as for onError: what to do? */