From 233e5e179f186f31140756b632091c258bea39b5 Mon Sep 17 00:00:00 2001 From: Julian Maurice Date: Thu, 19 Jun 2014 09:46:23 +0200 Subject: [PATCH] Bug 12460: Allow to start a new search from multiple search history lines This patch regroups searches of current and previous sessions to allow selecting lines from both groups. It adds a new column (session date) to allow to differentiate searches of current session from other sessions. Patch is for Intranet and OPAC (bootstrap only) Test plan: 1/ Login to intranet interface 2/ Do some biblio searches 3/ Go to the search history page 4/ See you have a new action available "Start a new search", grayed beacause you haven't selected any line 5/ Select two or more searches 6/ "Start a new search" is now enabled, click it. 7/ A dropdown list appears, asking you to chose between a "Match any" search and a "Match all" search. There is also a new column in the table ("Not") allowing you to apply a NOT to the corresponding line. 8/ Make your choice, and then click on Go button, next to the dropdown list. You will be redirected to the catalogue search results. 9/ Confirm that the results are correct. 10/ Set syspref opacthemes to 'bootstrap' 11/ Go to OPAC interface anonymously and repeat steps 2-9 12/ Login to OPAC interface and repeat steps 2-9 13/ Check that authority search history still works as before the patch (except that there is only one table instead of two) Depends on bug 11430 --- C4/Search/History.pm | 45 +-- catalogue/search-history.pl | 98 +++--- .../prog/en/modules/catalogue/search-history.tt | 276 ++++++++-------- .../bootstrap/en/modules/opac-search-history.tt | 350 ++++++++++----------- opac/opac-search-history.pl | 171 +++++----- 5 files changed, 461 insertions(+), 479 deletions(-) diff --git a/C4/Search/History.pm b/C4/Search/History.pm index c80310e..ad37d21 100644 --- a/C4/Search/History.pm +++ b/C4/Search/History.pm @@ -155,37 +155,44 @@ sub get { } my $query = q{ - SELECT * - FROM search_history + SELECT sh.* , s.a_session + FROM search_history sh + LEFT JOIN sessions s ON (sh.sessionid = s.id) WHERE 1 }; - $query .= q{ AND id IN ( } . join( q{,}, (q{?}) x @$id ) . q{ )} - if @$id; + my @bind_params; - $query .= q{ - AND userid = ? - } if $userid; + if (@$id) { + $query .= q{ AND sh.id IN ( } . join( q{,}, (q{?}) x @$id ) . q{ )}; + push @bind_params, @$id; + } + + if ($userid) { + $query .= q{ AND sh.userid = ? }; + push @bind_params, $userid; + } if ($sessionid) { - $query .= - $previous - ? q{ AND sessionid != ?} - : q{ AND sessionid = ?}; + if (defined $previous) { + $query .= + $previous + ? q{ AND sh.sessionid != ?} + : q{ AND sh.sessionid = ?}; + push @bind_params, $sessionid; + } } - $query .= q{ AND type = ?} - if $type; + if ($type) { + $query .= q{ AND sh.type = ?}; + push @bind_params, $type; + } my $dbh = C4::Context->dbh; my $sth = $dbh->prepare($query); - $sth->execute( - ( @$id ? ( @$id ) : () ), - ( $userid ? $userid : () ), - ( $sessionid ? $sessionid : () ), - ( $type ? $type : () ) - ); + $sth->execute(@bind_params); return $sth->fetchall_arrayref( {} ); + } sub get_from_session { diff --git a/catalogue/search-history.pl b/catalogue/search-history.pl index e60f20b..ec062b6 100755 --- a/catalogue/search-history.pl +++ b/catalogue/search-history.pl @@ -20,8 +20,11 @@ use Modern::Perl; use CGI qw ( -utf8 ); +use URI::Escape; use C4::Auth; +use C4::Languages; +use C4::Search; use C4::Search::History; use C4::Output; @@ -37,61 +40,74 @@ my ($template, $loggedinuser, $cookie) = get_template_and_user({ my $type = $cgi->param('type'); my $action = $cgi->param('action') || q{list}; -my $previous = $cgi->param('previous'); -# Deleting search history -if ( $action eq 'delete' ) { - my $sessionid = defined $previous - ? $cgi->cookie("CGISESSID") - : q{}; - C4::Search::History::delete( - { - id => [ $cgi->param('id') ], +if ( $action eq 'search' ) { + # Start a new search + + my @ids = $cgi->param('id'); + my @nots = $cgi->param('not'); + my $searches = C4::Search::History::get({ + userid => $loggedinuser, + id => \@ids, + }); + my @ccl_queries; + foreach my $search (@$searches) { + my $scgi = new CGI($search->{query_cgi}); + my @operators = map uri_unescape($_), $scgi->param('op'); + my @indexes = map uri_unescape($_), $scgi->param('idx'); + my @operands = map uri_unescape($_), $scgi->param('q'); + my @limits = map uri_unescape($_), $scgi->param('limit'); + my @sort_by = $scgi->param('sort_by'); + my $scan = $scgi->param('scan'); + my $lang = C4::Languages::getlanguage($cgi); + my ( $error, $query ) = + buildQuery( \@operators, \@operands, \@indexes, \@limits, \@sort_by, + $scan, $lang ); + + if (grep {$_ == $search->{id}} @nots) { + $query = "allrecords,alwaysmatches='' not ($query)"; } - ); - # Redirecting to this same url so the user won't see the search history link in the header + + push @ccl_queries, $query; + } + my $join = ($cgi->param('join') eq 'or') ? 'or' : 'and'; + my $query = 'ccl=(' . join(") $join (", @ccl_queries) . ')'; + print $cgi->redirect("/cgi-bin/koha/catalogue/search.pl?q=$query"); + exit; +} elsif ( $action eq 'delete' ) { + # Deleting search history + C4::Search::History::delete({ id => [ $cgi->param('id') ] }); + # Redirecting to this same url so the user won't see the search history link + # in the header my $uri = $cgi->url(); print $cgi->redirect($uri); - -# Showing search history + exit; } else { - my $current_searches = C4::Search::History::get({ + # Showing search history + my $searches = C4::Search::History::get({ userid => $loggedinuser, sessionid => $cgi->cookie("CGISESSID") }); - my @current_biblio_searches = map { - $_->{type} eq 'biblio' ? $_ : () - } @$current_searches; - - my @current_authority_searches = map { - $_->{type} eq 'authority' ? $_ : () - } @$current_searches; - - my $previous_searches = C4::Search::History::get({ - userid => $loggedinuser, - sessionid => $cgi->cookie("CGISESSID"), - previous => 1 - }); - - my @previous_biblio_searches = map { + foreach my $row (@$searches) { + if ($row->{a_session}) { + $row->{session} = YAML::Load($row->{a_session}); + $row->{session}->{session_ctime} = $row->{session}->{_SESSION_CTIME}; + $row->{session}->{session_id} = $row->{session}->{_SESSION_ID}; + } + } + my @biblio_searches = map { $_->{type} eq 'biblio' ? $_ : () - } @$previous_searches; + } @$searches; - my @previous_authority_searches = map { + my @authority_searches = map { $_->{type} eq 'authority' ? $_ : () - } @$previous_searches; + } @$searches; $template->param( - current_biblio_searches => \@current_biblio_searches, - current_authority_searches => \@current_authority_searches, - previous_biblio_searches => \@previous_biblio_searches, - previous_authority_searches => \@previous_authority_searches, - + biblio_searches => \@biblio_searches, + authority_searches => \@authority_searches, + sessionid => $cgi->cookie("CGISESSID"), ); } - -$template->param( -); - output_html_with_http_headers $cgi, $cookie, $template->output; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/search-history.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/search-history.tt index dbee0ab..83d3d3b 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/search-history.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/search-history.tt @@ -1,6 +1,85 @@ -[% INCLUDE 'doc-head-open.inc' %] [% USE Koha %] [% USE KohaDates %] +[% USE date %] + +[% BLOCK search_history_table %] +
+
+ Select all + Clear all + | + + Select searches to: + [%# Search from multiple lines is only enabled for biblios %] + [% IF type == 'biblio' %] + Start a new search + Cancel new search + + + + +   + [% END %] + Delete + +
+ + + + + + + + + + + + + + [% FOREACH s IN searches %] + + + + + + [% IF type == 'biblio' %] + [% search_url = '/cgi-bin/koha/catalogue/search.pl' %] + [% ELSE %] + [% search_url = '/cgi-bin/koha/authorities/authorities-home.pl' %] + [% END %] + + + + [% END %] + +
NotSession dateDateSearchResults
+ + + [% IF s.session %] + [% session_ctime = date.format(s.session.session_ctime, '%Y-%m-%d %H:%M:%S') %] + + [% IF s.session.session_id == sessionid %] + + [% END %] + [% session_ctime | $KohaDates %] + [% IF s.session.session_id == sessionid %] + + [% END %] + + [% ELSE %] + Unknown + [% END %] + [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
+
+[% END %] + +[% INCLUDE 'doc-head-open.inc' %] Koha › Catalog › Search history [% INCLUDE 'doc-head-close.inc' %] @@ -13,10 +92,10 @@ $(document).ready(function() { // We show table ordered by descending dates by default // (so that the more recent query is shown first) $(".historyt").dataTable($.extend(true, {}, dataTablesDefaults, { - "aaSorting": [[ 1, "desc" ]], + "aaSorting": [[ 3, "desc" ]], "aoColumnDefs": [ - { "aTargets": [ 0 ], "bSortable": false, "bSearchable": false }, - { "aTargets": [ 1 ], "sType": "title-string" }, + { "aTargets": [ 0, 1 ], "bSortable": false, "bSearchable": false }, + { "aTargets": [ 2, 3 ], "sType": "title-string" }, ], })); @@ -48,11 +127,44 @@ $(document).ready(function() { return false; } if ( confirm(MSG_CONFIRM_DELETE_HISTORY) ) { + $(form).find('input[name="action"]').val('delete'); $(form).submit(); } return false; }); + $(".action_search").click(function() { + var $form = $(this).parents('form'); + var $checked = $form.find('input:checkbox:checked'); + if ($checked.length) { + $(this).hide(); + $('.action_search_cancel').show(); + $('.search_options').show(); + $('.not').show(); + } + return false; + }); + + $('.search_options button[type="submit"]').click(function() { + var $form = $(this).parents('form'); + var $checked = $form.find('input:checkbox:checked'); + if ($checked.length ) { + $form.find('input[name="action"]').val('search'); + $form.submit(); + } + return false; + }); + + $('.action_search_cancel').click(function() { + $(this).hide(); + $('.action_search').show(); + $('.search_options').hide(); + $('.not').hide(); + return false; + }).click(); + $('form').each(function() { + enableCheckboxActions(this); + }); }); function enableCheckboxActions(form){ @@ -92,157 +204,21 @@ function enableCheckboxActions(form){
  • Authority
  • - [% IF ( current_biblio_searches ) %] -

    Current session

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN current_biblio_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
    -
    - [% END %] - - [% IF ( previous_biblio_searches ) %] -

    Previous sessions

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN previous_biblio_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
    -
    - [% END %] - - [% IF !current_biblio_searches && !previous_biblio_searches %] + [% IF ( biblio_searches ) %] + [% INCLUDE search_history_table + searches = biblio_searches + type = 'biblio' %] + [% ELSE %]

    Your catalog search history is empty.

    [% END %]
    - [% IF ( current_authority_searches ) %] -

    Current session

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN current_authority_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
    -
    - [% END %] - - [% IF ( previous_authority_searches ) %] -

    Previous sessions

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN previous_authority_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
    -
    - [% END %] - - [% IF !current_authority_searches && !previous_authority_searches %] + [% IF ( authority_searches ) %] + [% INCLUDE search_history_table + searches = authority_searches + type = 'authority' %] + [% ELSE %]

    Your authority search history is empty.

    [% END %]
    diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-search-history.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-search-history.tt index a14f25c..c8bcbee 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-search-history.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-search-history.tt @@ -1,5 +1,97 @@ [% USE Koha %] [% USE KohaDates %] +[% USE date %] + +[% BLOCK search_history_table %] +
    +
    + Select all + Clear all + | + + Select searches to: + [% IF type == 'biblio' %] + Start a new search + Cancel new search + + + + +   + [% END %] + Delete + +
    + + + + + + + [% IF hide_session_column %] + + [% ELSE %] + + [% END %] + + + + + + + [% FOREACH s IN searches %] + + + + [% IF hide_session_column %] + + + [% IF type == 'biblio' %] + [% search_url = '/cgi-bin/koha/opac-search.pl' %] + [% ELSIF type == 'authority' %] + [% search_url = '/cgi-bin/koha/opac-authorities-home.pl' %] + [% END %] + + + + [% END %] + +
    NotSession dateSession dateDateSearchResults
    + + + [% ELSE %] + + [% END %] + [% IF s.session %] + [% session_ctime = date.format(s.session.session_ctime, '%Y-%m-%d %H:%M:%S') %] + + [% IF s.session.session_id == sessionid %] + + [% END %] + [% session_ctime | $KohaDates %] + [% IF s.session.session_id == sessionid %] + + [% END %] + + [% ELSE %] + Unknown + [% END %] + [% s.time |$KohaDates with_hours => 1 %] + [% IF type == 'biblio' %] + + Subscribe to this search + + [% END %] + [% s.query_desc |html %][% s.total %]
    +
    +[% END %] + [% INCLUDE 'doc-head-open.inc' %] [% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › Your search history [% INCLUDE 'doc-head-close.inc' %] @@ -31,186 +123,39 @@
    [% END %]
    -

    Search history

    - [% IF Koha.Preference( 'OpacAuthorities' ) == 1 %] -
    - +

    Search history

    + [% IF Koha.Preference( 'OpacAuthorities' ) == 1 %] +
    + + [% END %] +
    + [% IF ( biblio_searches ) %] + [% INCLUDE search_history_table + searches = biblio_searches + type = 'biblio' %] + [% ELSE %] +

    Your catalog search history is empty.

    [% END %] -
    -
    - [% IF ( current_biblio_searches ) %] -

    Current session

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN current_biblio_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %]Subscribe to this search [% s.query_desc |html %][% s.total %]
    - -
    - [% END # IF ( current_biblio_searches ) %] -
    - -
    - [% IF ( previous_biblio_searches ) %] -

    Previous sessions

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - - [% FOREACH s IN previous_biblio_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %]Subscribe to this search [% s.query_desc |html %][% s.total %]
    - -
    - [% END # IF ( previous_biblio_searches ) %] -
    - - [% IF !current_biblio_searches && !previous_biblio_searches %] -

    Your catalog search history is empty.

    - [% END %] -
    +
    - [% IF Koha.Preference( 'OpacAuthorities' ) == 1 %] -
    - [% IF ( current_authority_searches ) %] -

    Current session

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN current_authority_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
    - -
    - [% END # / IF ( current_authority_searches ) %] - - [% IF ( previous_authority_searches ) %] -

    Previous sessions

    -
    -
    - Select all - Clear all - | - - Select searches to: - Delete - -
    - - - - - - - - - - - - [% FOREACH s IN previous_authority_searches %] - - - - - - - [% END %] - -
    DateSearchResults
    [% s.time |$KohaDates with_hours => 1 %][% s.query_desc |html %][% s.total %]
    - -
    - [% END # / IF ( previous_authority_searches )%] - - [% IF !current_authority_searches && !previous_authority_searches %] -

    Your authority search history is empty.

    - [% END %] -
    - [% END # / IF Koha.Preference( 'OpacAuthorities' ) %] -
    -
    -
    -
    - - + [% IF Koha.Preference( 'OpacAuthorities' ) == 1 %] +
    + [% IF ( authority_searches ) %] + [% INCLUDE search_history_table + searches = authority_searches + type = 'authority' %] + [% ELSE %] +

    Your authority search history is empty.

    + [% END %] +
    + [% END %] + + + + [% INCLUDE 'opac-bottom.inc' %] [% BLOCK jsinclude %] @@ -220,14 +165,14 @@ //param('type'); my $action = $cgi->param('action') || q{}; -my $previous = $cgi->param('previous'); -# If the user is not logged in, we deal with the session -unless ( $loggedinuser ) { +if ( $action eq 'search' ) { + # Start a new search + + my @ids = $cgi->param('id'); + my @nots = $cgi->param('not'); + my @searches; + if ($loggedinuser) { + @searches = @{ C4::Search::History::get({ + userid => $loggedinuser, + id => \@ids, + }) }; + } else { + @searches = C4::Search::History::get_from_session({ cgi => $cgi }); + if ( @ids ) { + @searches = map { + my $search = $_; + ( grep {/^$search->{id}$/} @ids ) ? $_ : () + } @searches; + } + } + my @ccl_queries; + foreach my $search (@searches) { + my $scgi = new CGI($search->{query_cgi}); + my @operators = map uri_unescape($_), $scgi->param('op'); + my @indexes = map uri_unescape($_), $scgi->param('idx'); + my @operands = map uri_unescape($_), $scgi->param('q'); + my @limits = map uri_unescape($_), $scgi->param('limit'); + my @sort_by = $scgi->param('sort_by'); + my $scan = $scgi->param('scan'); + my $lang = C4::Languages::getlanguage($cgi); + my ( $error, $query ) = + buildQuery( \@operators, \@operands, \@indexes, \@limits, \@sort_by, + $scan, $lang ); + + if (grep {$_ == $search->{id}} @nots) { + $query = "allrecords,alwaysmatches='' not ($query)"; + } + + push @ccl_queries, $query; + } + my $join = ($cgi->param('join') eq 'or') ? 'or' : 'and'; + my $query = 'ccl=(' . join(") $join (", @ccl_queries) . ')'; + print $cgi->redirect("/cgi-bin/koha/opac-search.pl?q=$query"); + exit; +} elsif ( $action eq 'delete' ) { # Deleting search history - if ( $action eq 'delete') { + my @id = $cgi->param('id'); + if ($loggedinuser) { + if ( @id ) { + C4::Search::History::delete({ id => \@id }); + } else { + C4::Search::History::delete({ userid => $loggedinuser }); + } + } else { # Deleting session's search history - my @id = $cgi->param('id'); - my $all = not scalar( @id ); - my $type = $cgi->param('type'); my @searches = (); - unless ( $all ) { + if ( scalar @id ) { @searches = C4::Search::History::get_from_session({ cgi => $cgi }); if ( $type ) { @searches = map { $_->{type} ne $type ? $_ : () } @searches; @@ -70,90 +117,48 @@ unless ( $loggedinuser ) { } } C4::Search::History::set_to_session({ cgi => $cgi, search_history => \@searches }); - - # Redirecting to this same url so the user won't see the search history link in the header - my $uri = $cgi->url(); - print $cgi->redirect(-uri => $uri); - # Showing search history - } else { - # Getting the searches from session - my @current_searches = C4::Search::History::get_from_session({ - cgi => $cgi, - }); - - my @current_biblio_searches = map { - $_->{type} eq 'biblio' ? $_ : () - } @current_searches; - - my @current_authority_searches = map { - $_->{type} eq 'authority' ? $_ : () - } @current_searches; - - $template->param( - current_biblio_searches => \@current_biblio_searches, - current_authority_searches => \@current_authority_searches, - ); } + # Redirecting to this same url so the user won't see the search history link in the header + my $uri = $cgi->url(); + print $cgi->redirect($uri); + exit; } else { - # And if the user is logged in, we deal with the database - my $dbh = C4::Context->dbh; - - # Deleting search history - if ( $action eq 'delete' ) { - my @id = $cgi->param('id'); - if ( @id ) { - C4::Search::History::delete( - { - id => [ $cgi->param('id') ], - } - ); - } else { - C4::Search::History::delete( - { - userid => $loggedinuser, - } - ); - } - # Redirecting to this same url so the user won't see the search history link in the header - my $uri = $cgi->url(); - print $cgi->redirect($uri); - # Showing search history - } else { - my $current_searches = C4::Search::History::get({ + my @searches; + if ($loggedinuser) { + @searches = @{ C4::Search::History::get({ userid => $loggedinuser, sessionid => $cgi->cookie("CGISESSID") + }) }; + foreach my $row (@searches) { + if ($row->{a_session}) { + $row->{session} = YAML::Load($row->{a_session}); + $row->{session}->{session_ctime} = $row->{session}->{_SESSION_CTIME}; + $row->{session}->{session_id} = $row->{session}->{_SESSION_ID}; + } + } + } else { + # Getting the searches from session + @searches = C4::Search::History::get_from_session({ + cgi => $cgi, }); - my @current_biblio_searches = map { - $_->{type} eq 'biblio' ? $_ : () - } @$current_searches; - - my @current_authority_searches = map { - $_->{type} eq 'authority' ? $_ : () - } @$current_searches; - - my $previous_searches = C4::Search::History::get({ - userid => $loggedinuser, - sessionid => $cgi->cookie("CGISESSID"), - previous => 1 - }); + $template->param(hide_session_column => 1); + } - my @previous_biblio_searches = map { - $_->{type} eq 'biblio' ? $_ : () - } @$previous_searches; - my @previous_authority_searches = map { - $_->{type} eq 'authority' ? $_ : () - } @$previous_searches; + my @biblio_searches = map { + $_->{type} eq 'biblio' ? $_ : () + } @searches; - $template->param( - current_biblio_searches => \@current_biblio_searches, - current_authority_searches => \@current_authority_searches, - previous_biblio_searches => \@previous_biblio_searches, - previous_authority_searches => \@previous_authority_searches, + my @authority_searches = map { + $_->{type} eq 'authority' ? $_ : () + } @searches; - ); - } + $template->param( + biblio_searches => \@biblio_searches, + authority_searches => \@authority_searches, + sessionid => $cgi->cookie('CGISESSID'), + ); } $template->param(searchhistoryview => 1); -- 1.9.1