Bug #1044721: QP handles explicit group+joiner badly
[transitory.git] / Open-ILS / src / perlmods / lib / OpenILS / WWW / EGCatLoader / Search.pm
index 48231d3..e66fee2 100644 (file)
@@ -10,11 +10,6 @@ use Data::Dumper;
 $Data::Dumper::Indent = 0;
 my $U = 'OpenILS::Application::AppUtils';
 
-# when fetching "all" search results for staff client 
-# start/end paging, fetch this many IDs at most
-my $all_recs_limit = 10000;
-
-
 sub _prepare_biblio_search_basics {
     my ($cgi) = @_;
 
@@ -30,6 +25,12 @@ sub _prepare_biblio_search_basics {
 
         next unless $query =~ /\S/;
 
+        # Hack for journal title
+        my $q = $qtype;
+        if ($q eq 'jtitle') {
+            $qtype = 'title';
+        }
+
         # This stuff probably will need refined or rethought to better handle
         # the weird things Real Users will surely type in.
         $contains = "" unless defined $contains; # silence warning
@@ -46,6 +47,11 @@ sub _prepare_biblio_search_basics {
         }
         $query = "$qtype:$query" unless $qtype eq 'keyword' and $i == 0;
 
+        # Hack for journal title - completed!
+        if ($q eq 'jtitle') {
+            $query = "bib_level:s $query";
+        }
+
         $bool = ($bool and $bool eq 'or') ? '||' : '&&';
         $full_query = $full_query ? "($full_query $bool $query)" : $query;
     }
@@ -57,6 +63,9 @@ sub _prepare_biblio_search {
     my ($cgi, $ctx) = @_;
 
     my $query = _prepare_biblio_search_basics($cgi) || '';
+    $query = "($query)";
+
+    $query .= ' ' . $ctx->{global_search_filter} if $ctx->{global_search_filter};
 
     foreach ($cgi->param('modifier')) {
         # The unless bit is to avoid stacking modifiers.
@@ -70,6 +79,15 @@ sub _prepare_biblio_search {
         $query .= " $1($term)" if length $term;
     }
 
+    # filter group entries.  Entries from like filters are grouped into a single 
+    # filter_group_entry() filter (ORed).  Each collection is ANDed together.
+    # fg:foo_group=foo_entry_id
+    foreach (grep /^fg:/, $cgi->param) {
+        /:(-?\w+)$/ or next;
+        my $term = join(",", $cgi->param($_));
+        $query .= " filter_group_entry($term)" if length $term;
+    }
+
     if ($cgi->param("bookbag")) {
         $query .= " container(bre,bookbag," . int($cgi->param("bookbag")) . ")";
     }
@@ -105,11 +123,14 @@ sub _prepare_biblio_search {
         }
     }
 
-    my $site;
+    my (@naive_query_re, $site);
+
     my $org = $ctx->{search_ou};
     if (defined($org) and $org ne '' and ($org ne $ctx->{aou_tree}->()->id) and not $query =~ /site\(\S+\)/) {
-        $site = $ctx->{get_aou}->($org)->shortname;
-        $query .= " site($site)";
+        my $thing = " site(" . $ctx->{get_aou}->($org)->shortname . ")";
+
+        $query .= $thing;
+        push @naive_query_re, $thing;
     }
 
     my $pref_ou = $ctx->{pref_ou};
@@ -142,9 +163,21 @@ sub _prepare_biblio_search {
             my ($org) = grep { $_->shortname eq $site } @{$ctx->{aou_list}->()};
             $depth = $org->ou_type->depth;
         }
-        $query .= " depth($depth)";
+        my $thing = " depth($depth)";
+
+        $query .= $thing;
+        push @naive_query_re, $thing;
     }
 
+    # This gives templates a way to take site() and depth() back out of
+    # query strings when they shouldn't be there (because they're controllable
+    # with other widgets).
+    $ctx->{naive_query_scrub} = sub {
+        my ($query) = @_;
+        $query =~ s/\Q$_\E// foreach (@naive_query_re);
+        return $query;
+    };
+
     $logger->info("tpac: site=$site, depth=$depth, query=$query");
 
     return ($query, $site, $depth);
@@ -270,6 +303,9 @@ sub load_rresults {
     my $ctx = $self->ctx;
     my $e = $self->editor;
 
+    # find the last record in the set, then redirect
+    my $find_last = $cgi->param('find_last');
+
     $self->timelog("Loading results");
     # load bookbag metadata, if requested.
     if (my $bbag_err = $self->load_rresults_bookbag) {
@@ -311,9 +347,9 @@ sub load_rresults {
     $ctx->{page_size} = $limit;
     $ctx->{search_page} = $page;
 
-    # fetch the first hit from the next page
+    # fetch this page plus the first hit from the next page
     if ($internal) {
-        $limit = $all_recs_limit;
+        $limit = $offset + $limit + 1;
         $offset = 0;
     }
 
@@ -321,7 +357,7 @@ sub load_rresults {
 
     $self->get_staff_search_settings;
 
-    if ($ctx->{staff_saved_search_size}) {
+    if (!$find_last and $ctx->{staff_saved_search_size}) {
         my ($key, $list) = $self->staff_save_search($query);
         if ($key) {
             $self->apache->headers_out->add(
@@ -395,6 +431,15 @@ sub load_rresults {
     $ctx->{hit_count} = $results->{count};
     $ctx->{parsed_query} = $results->{parsed_query};
 
+    if ($find_last) {
+        # redirect to the record detail page for the last record in the results
+        my $rec_id = pop @$rec_ids;
+        $cgi->delete('find_last');
+        my $url = $cgi->url(-full => 1, -path => 1, -query => 1);
+        $url =~ s|/results|/record/$rec_id|;
+        return $self->generic_redirect($url);
+    }
+
     return Apache2::Const::OK if @$rec_ids == 0 or $internal;
 
     $self->load_rresults_bookbag_item_notes($rec_ids) if $ctx->{bookbag};
@@ -416,6 +461,9 @@ sub load_rresults {
         return $stat if $stat;
     }
 
+    # load temporary_list settings for user and ou:
+    $self->_load_lists_and_settings if ($ctx->{user});
+
     # shove recs into context in search results order
     for my $rec_id (@$rec_ids) {
         push(
@@ -467,8 +515,8 @@ sub check_1hit_redirect {
 
     my $base_url = sprintf(
         '%s://%s%s/record/%s',
-        $ctx->{proto}, 
-        $self->apache->hostname,
+        $self->ctx->{proto},
+        $self->ctx->{hostname},
         $self->ctx->{opac_root},
         $$rec_ids[0],
     );
@@ -476,7 +524,7 @@ sub check_1hit_redirect {
     # If we get here from the same record detail page to which we
     # now wish to redirect, do not perform the redirect.  This
     # approach seems to work well, with the rare exception of 
-    # performing a new serach directly from the detail page that 
+    # performing a new search directly from the detail page that 
     # happens to result in the same single hit.  In this case, the 
     # user will be left on the search results page.  This could be 
     # overcome w/ additional CGI, etc., but I'm not sure it's necessary.
@@ -531,6 +579,8 @@ sub item_barcode_shortcut {
         $self->ctx->{search_facets} = {};
         $self->ctx->{hit_count} = scalar @data;
         $self->ctx->{page_size} = $self->ctx->{hit_count};
+        # load temporary_list settings for user and ou:
+        $self->_load_lists_and_settings if ($self->ctx->{user});
 
         return Apache2::Const::OK;
     } {
@@ -580,15 +630,17 @@ sub marc_expert_search {
     return Apache2::Const::OK if @$query == 0;
 
     if ($args{internal}) {
-        $limit = $all_recs_limit;
+        $limit = $offset + $limit + 1;
         $offset = 0;
     }
 
     $self->timelog("Searching for MARC expert");
+    my $method = 'open-ils.search.biblio.marc';
+    $method .= '.staff' if $self->ctx->{is_staff};
     my $timeout = 120;
     my $ses = OpenSRF::AppSession->create('open-ils.search');
     my $req = $ses->request(
-        'open-ils.search.biblio.marc',
+        $method,
         {searches => $query, org_unit => $self->ctx->{search_ou}}, 
         $limit, $offset, $timeout);
 
@@ -624,6 +676,9 @@ sub marc_expert_search {
     );
     $self->timelog("Returned from calling get_records_and_facets() for MARC expert");
 
+    # load temporary_list settings for user and ou:
+    $self->_load_lists_and_settings if ($self->ctx->{user});
+
     $self->ctx->{records} = [@data];
 
     return Apache2::Const::OK;
@@ -634,12 +689,13 @@ sub call_number_browse_standalone {
 
     if (my $cnfrag = $self->cgi->param("query")) {
         my $url = sprintf(
-            'http%s://%s%s/cnbrowse?cn=%s',
-            $self->cgi->https ? "s" : "",
-            $self->apache->hostname,
+            '%s://%s%s/cnbrowse?cn=%s',
+            $self->ctx->{proto},
+            $self->ctx->{hostname},
             $self->ctx->{opac_root},
             $cnfrag # XXX some kind of escaping needed here?
         );
+        $url .= '&locg=' . $self->_get_search_lib() if ($self->_get_search_lib());
         return $self->generic_redirect($url);
     } else {
         return $self->generic_redirect; # return to search page