Improve error handling
Change-Id: I1f54cf9cd4770d6602f70036cf0e27c9ede8c893
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index 340d1fc..f5151b4 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -116,7 +116,8 @@
# Client notifications
$self->plugin(Notifications => {
'Kalamar::Plugin::Notifications' => 1,
- JSON => 1
+ JSON => 1,
+ 'HTML' => 1
});
# Localization framework
@@ -208,10 +209,9 @@
# Base query route
$r->get('/')->to('search2#query')->name('index');
- $r->get('/q2')->to('search2#query');
- # Collection route
- $r->get('/corpus')->to('Search#corpus_info')->name('corpus');
+ # Corpus route
+ $r->get('/corpus')->to('Search2#corpus_info')->name('corpus');
# Documentation routes
$r->get('/doc')->to('documentation#page', page => 'korap')->name('doc_start');
@@ -225,11 +225,8 @@
# Match route
my $corpus = $r->route('/corpus/:corpus_id');
my $doc = $corpus->get('/:doc_id');
- my $text = $doc->get('/:text_id')->to('search#text_info')->name('text');
- my $match = $doc->get('/:text_id/:match_id')->to('search#match_info')->name('match');
-
- $r->get('/corpus2')->to('Search2#corpus_info')->name('corpus');
- $r->route('/corpus2/:corpus_id/:doc_id/:text_id/:match_id')->to('search2#match_info')->name('match');
+ my $text = $doc->get('/:text_id')->to('search2#text_info')->name('text');
+ my $match = $doc->get('/:text_id/:match_id')->to('search2#match_info')->name('match');
# User Management
my $user = $r->any('/user')->to(controller => 'User');
diff --git a/lib/Kalamar/Controller/Search2.pm b/lib/Kalamar/Controller/Search2.pm
index 397d7c5..7922a2a 100644
--- a/lib/Kalamar/Controller/Search2.pm
+++ b/lib/Kalamar/Controller/Search2.pm
@@ -23,9 +23,6 @@
# Validate user input
my $v = $c->validation;
- # In case the user is not known, it is assumed, the user is not logged in
- my $user = $c->stash('user') // 'not_logged_in';
-
$v->optional('q', 'trim');
$v->optional('ql')->in(qw/poliqarp cosmas2 annis cql fcsql/);
$v->optional('collection', 'trim'); # Legacy
@@ -50,28 +47,33 @@
};
my %query = ();
- $query{q} = $v->param('q');
+ $query{q} = $query;
$query{ql} = $v->param('ql') // 'poliqarp';
- $query{p} = $v->param('p') // 1; # Start page
$query{count} = $v->param('count') // $c->items_per_page;
$query{cq} = $v->param('cq') // $v->param('collection');
$query{cutoff} = $v->param('cutoff');
-
# Before: 'base/s:p'/'paragraph'
$query{context} = $v->param('context') // '40-t,40-t';
+ # Start page
+ my $page = $v->param('p') // 1;
+
+ $c->stash(query => $query);
+ $c->stash(ql => $query{ql});
+
my $items_per_page = $c->items_per_page;
# Set count
if ($query{count} && $query{count} <= $c->items_per_page ) {
$items_per_page = delete $query{count};
+ $query{count} = $items_per_page;
};
$c->stash(items_per_page => $items_per_page);
# Set offset
# From Mojolicious::Plugin::Search::Index
- $query{o} = $v->param('o') || ((($query{p} // 1) - 1) * ($items_per_page || 1));
+ $query{offset} = $v->param('o') || ((($page // 1) - 1) * ($items_per_page || 1));
# already set by stash - or use plugin param
@@ -95,27 +97,35 @@
# $url->query(%query);
$url->query(map { $_ => $query{$_}} sort keys %query);
- # Check if total results is cached
+ # In case the user is not known, it is assumed, the user is not logged in
+ my $total_cache_str;
+
+ # Check if total results information is cached
my $total_results = -1;
unless ($c->no_cache) {
+ # Create cache string
+ my $user = $c->user->handle;
+ my $cache_url = $url->clone;
+ $cache_url->query->remove('context')->remove('count')->remove('cutoff')->remove('offset');
+ $total_cache_str = "total-$user-" . $cache_url->to_string;
+
+ $c->app->log->debug('Check for total results: ' . $total_cache_str);
+
# Get total results value
- $total_results = $c->chi->get('total-' . $user . '-' . $url->to_string);
+ $total_results = $c->chi->get($total_cache_str);
# Set stash if cache exists
- $c->stash(total_results => $total_results) if $total_results;
- $c->app->log->debug('Get total result from cache');
+ if (defined $total_results) {
+ $c->stash(total_results => $total_results);
- # Set cutoff unless already set
- $url->query({cutoff => 'true'});
+ $c->app->log->debug('Get total result from cache: ' . $total_results);
+
+ # Set cutoff unless already set
+ $url->query({cutoff => 'true'});
+ };
};
- # Choose the snippet based on the parameter
- # TODO:
- # scalar $v->param('snippet') ? 'snippet' : 'search2';
- $c->stash(template => 'search2');
-
-
# Wait for rendering
$c->render_later;
@@ -132,26 +142,30 @@
# The stash is set in case the total results value is from the cache,
# so in that case, it does not need to be cached again
my $total_results = $c->stash('total_results');
- if (!$total_results) {
+
+ unless (defined $total_results) {
# There are results to remember
if ($json->{meta}->{totalResults} >= 0) {
# Remove cutoff requirement again
- $url->query([cutoff => 'true']);
+ # $url->query([cutoff => 'true']);
$total_results = $json->{meta}->{totalResults};
$c->stash(total_results => $total_results);
+ $c->app->log->debug('Set for total results: ' . $total_cache_str);
+
# Set cache
- $c->chi->set(
- 'total-' . $user . '-' . $url->to_string => $total_results
- );
+ $c->chi->set($total_cache_str => $total_results);
+ }
+
+ # Undefined total results
+ else {
+ $c->stash(total_results => -1);
};
- }
- else {
- $c->stash(total_results => -1);
- }
+ };
+
$c->stash(total_pages => 0);
@@ -163,28 +177,76 @@
);
};
- # Process match results
- $c->_process_query_response($json);
+ # Process meta
+ my $meta = $json->{meta};
+
+ # TODO:
+ # Set benchmark in case of development mode only.
+ # Use server timing API
+ #
+ # Reformat benchmark counter
+ # my $benchmark = $meta->{benchmark};
+ # if ($benchmark && $benchmark =~ s/\s+(m)?s$//) {
+ # $benchmark = sprintf("%.2f", $benchmark) . ($1 ? $1 : '') . 's';
+ # };
+ #
+ # # Set benchmark
+ # $self->stash(benchmark => $benchmark);
+
+ # Set time exceeded
+ if ($meta->{timeExceeded} &&
+ $meta->{timeExceeded} eq Mojo::JSON::true) {
+ $c->stash(time_exceeded => 1);
+ };
+
+ # Set result values
+ $c->stash(items_per_page => $meta->{itemsPerPage});
+
+ ## Bouncing query
+ ## if ($json->{query}) {
+ ## $index->query_jsonld($json->{query});
+ ## };
+
+ ## Legacy
+ ## elsif ($json->{request}->{query}) {
+ ## $index->query_jsonld($json->{request}->{query});
+ ## };
+
+ # Bouncing collection query
+ if ($json->{corpus} || $json->{collection}) {
+ $c->stash(corpus_jsonld => ($json->{corpus} || $json->{collection}));
+ };
+
+ # TODO:
+ # scalar $v->param('snippet') ? 'snippet' : 'search2';
# Render result
return $c->render(
- q => $query,
- ql => $query{ql},
- start_page => $query{p},
+ q => $c->stash('query'),
+ ql => $c->stash('ql'),
+ start_page => $page,
+ start_index => $json->{meta}->{startIndex},
+ results => _map_matches($json->{matches}),
+ template => 'search2'
);
-
}
# Deal with errors
)->catch(
sub {
+ my $err_msg = shift;
+
+ # Only raised in case of connection errors
+ if ($err_msg) {
+ $c->stash('err_msg' => 'backendNotAvailable');
+ $c->notify(error => { src => 'Backend' } => $err_msg)
+ };
# $c->_notify_on_errors(shift);
return $c->render(
- results => c(),
- q => $query,
- ql => $query{ql},
- start_page => 1
+ q => $c->stash('query'),
+ ql => $c->stash('ql'),
+ template => 'failure'
);
}
)
@@ -353,63 +415,6 @@
};
-# Process response and set stash values
-sub _process_query_response {
- my ($self, $json) = @_;
-
- # Process meta
- my $meta = $json->{meta};
-
- # TODO:
- # Set benchmark in case of development mode only.
- # Use server timing API
- #
- # Reformat benchmark counter
- # my $benchmark = $meta->{benchmark};
- # if ($benchmark && $benchmark =~ s/\s+(m)?s$//) {
- # $benchmark = sprintf("%.2f", $benchmark) . ($1 ? $1 : '') . 's';
- # };
- #
- # # Set benchmark
- # $self->stash(benchmark => $benchmark);
-
- # Set time exceeded
- if ($meta->{timeExceeded} && $meta->{timeExceeded} eq Mojo::JSON::true) {
- $self->stash(time_exceeded => 1);
- };
-
- # Set result values
- $self->stash(items_per_page => $meta->{itemsPerPage});
-
- ## Bouncing query
- ## if ($json->{query}) {
- ## $index->query_jsonld($json->{query});
- ## };
-
- ## Legacy
- ## elsif ($json->{request}->{query}) {
- ## $index->query_jsonld($json->{request}->{query});
- ## };
-
-
- if ($meta->{totalResults}) {
- $self->stash(total_results => $meta->{totalResults});
- };
-
- # Bouncing collection query
- if ($json->{corpus} || $json->{collection}) {
- $self->stash(corpus_jsonld => ($json->{corpus} || $json->{collection}));
- };
-
- # Set results to stash
- $self->stash(
- results => _map_matches($json->{matches})
- );
-
- return;
-};
-
-
1;
diff --git a/lib/Kalamar/Plugin/KalamarErrors.pm b/lib/Kalamar/Plugin/KalamarErrors.pm
index fd9ead3..2c897fc 100644
--- a/lib/Kalamar/Plugin/KalamarErrors.pm
+++ b/lib/Kalamar/Plugin/KalamarErrors.pm
@@ -59,11 +59,11 @@
}
);
- # Catch connection errors
+ # Catch errors and warnings
+ # This won't be called for connection errors!
$mojo->helper(
catch_errors_and_warnings => sub {
my ($c, $tx) = @_;
-
my $err = $tx->error;
if ($err && $err->{code} != 500) {
@@ -79,17 +79,19 @@
if (!$json && !$err) {
$c->notify(error => 'JSON response is invalid');
- return Mojo::Promise->new->reject;
+ return; # Mojo::Promise->new->reject;
};
# There is json
if ($json) {
+ $c->stash(api_response => $json);
+
# There are errors
if ($c->notify_on_errors($json)) {
# Return on errors - ignore warnings
- return Mojo::Promise->new->reject;
+ return;# Mojo::Promise->new->reject;
};
# Notify on warnings
@@ -99,7 +101,7 @@
if ($json->{status}) {
$c->notify(error => 'Middleware error ' . $json->{'status'});
- return Mojo::Promise->new->reject;
+ return;# Mojo::Promise->new->reject;
};
}
@@ -108,7 +110,7 @@
# Send rejection promise
$c->notify(error => $err->{code} . ': ' . $err->{message});
- return Mojo::Promise->new->reject;
+ return; #Mojo::Promise->new->reject;
};
return $json;
diff --git a/lib/Kalamar/Plugin/KalamarHelpers.pm b/lib/Kalamar/Plugin/KalamarHelpers.pm
index b0006c3..6e0b228 100644
--- a/lib/Kalamar/Plugin/KalamarHelpers.pm
+++ b/lib/Kalamar/Plugin/KalamarHelpers.pm
@@ -277,23 +277,14 @@
);
- # Get a cached request from the backend
+ # Get a cached request from the backend as a promise
$mojo->helper(
cached_koral_p => sub {
my ($c, $method, $url) = @_;
# In case the user is not known, it is assumed,
# the user is not logged in
- my $user = $c->stash('user');
- unless ($user) {
- $user = $c->session('user');
- if ($user) {
- $c->stash(user => $user);
- }
- else {
- $user = 'not_logged_in';
- }
- };
+ my $user = $c->user->handle;
# Set api request for debugging
my $cache_str = "$method-$user-" . $url->to_string;
@@ -302,10 +293,10 @@
if ($c->no_cache) {
return $c->user->auth_request_p($method => $url)->then(
sub {
- my $json = shift;
+ my $tx = shift;
# Catch errors and warnings
- $c->stash(api_response => $json);
- return $c->catch_errors_and_warnings($json);
+ return ($c->catch_errors_and_warnings($tx) ||
+ Mojo::Promise->new->reject);
}
);
};
@@ -319,7 +310,7 @@
if ($koral) {
# Mark response as cache
- $koral->{'X-cached'} = Mojo::JSON->true;
+ $c->res->headers->add('X-Kalamar-Cache' => 'true');
# The promise is already satisfied by the cache
return Mojo::Promise->new->resolve($koral)->then(
@@ -335,17 +326,15 @@
# Resolve request
return $c->user->auth_request_p($method => $url)->then(
sub {
- my $json = shift;
- # Catch errors and warnings
- $c->stash(api_response => $json);
- return $c->catch_errors_and_warnings($json);
+ my $tx = shift;
+ return ($c->catch_errors_and_warnings($tx) ||
+ Mojo::Promise->new->reject);
}
)->then(
# Cache on success
sub {
my $json = shift;
$c->chi->set($cache_str => $json);
- $c->stash(api_response => $json);
return $json;
}
);
diff --git a/lib/Kalamar/Plugin/KalamarUser.pm b/lib/Kalamar/Plugin/KalamarUser.pm
index 41251a1..19bb2a7 100644
--- a/lib/Kalamar/Plugin/KalamarUser.pm
+++ b/lib/Kalamar/Plugin/KalamarUser.pm
@@ -86,6 +86,29 @@
}
);
+ # Get user handle
+ $mojo->helper(
+ 'user.handle' => sub {
+ my $c = shift;
+
+ # Get from stash
+ my $user = $c->stash('user');
+ return $user if $user;
+
+ # Get from session
+ $user = $c->session('user');
+
+ # Set in stash
+ if ($user) {
+ $c->stash(user => $user);
+ return $user;
+ };
+
+ return 'not_logged_in';
+ }
+ );
+
+
# Request with authorization header
$mojo->helper(
'user.auth_request' => sub {
diff --git a/lib/Kalamar/Plugin/Notifications.pm b/lib/Kalamar/Plugin/Notifications.pm
index 9fea51b..8b6df94 100644
--- a/lib/Kalamar/Plugin/Notifications.pm
+++ b/lib/Kalamar/Plugin/Notifications.pm
@@ -21,6 +21,9 @@
foreach (@$notify_array) {
$js .= 'KorAP.Notifications.push([';
$js .= quote($_->[0]) . ',' . quote($_->[-1]);
+ if (ref $_->[1] && ref $_->[1] eq 'HASH') {
+ $js .= ',' . quote($_->[1]->{src}) if $_->[1]->{src};
+ };
$js .= "]);\n";
$noscript .= qq{<div class="notify notify-} . $_->[0] . '">' .