[Koha-patches] [PATCH] Adding Opac-SearchHistory feature

Henri-Damien LAURENT henridamien.laurent at biblibre.com
Mon Aug 24 22:10:25 CEST 2009


Enables ppl to store their search history and delete the whole history

Adding Storable required by Opac-Search-History
---
 C4/Auth.pm                                         |   65 +++++++++
 C4/Search.pm                                       |   22 +++
 Makefile.PL                                        |    1 +
 .../mysql/atomicupdate/0007-Opac-search-history.pl |   24 +++
 koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc  |    4 +-
 .../prog/en/modules/opac-search-history.tmpl       |   80 +++++++++++
 opac/opac-search-history.pl                        |  147 ++++++++++++++++++++
 opac/opac-search.pl                                |   53 +++++++-
 8 files changed, 392 insertions(+), 4 deletions(-)
 create mode 100644 installer/data/mysql/atomicupdate/0007-Opac-search-history.pl
 create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-search-history.tmpl
 create mode 100755 opac/opac-search-history.pl

diff --git a/C4/Auth.pm b/C4/Auth.pm
index 871c124..04e0b35 100644
--- a/C4/Auth.pm
+++ b/C4/Auth.pm
@@ -19,6 +19,8 @@ package C4::Auth;
 
 use strict;
 use Digest::MD5 qw(md5_base64);
+use Storable qw(thaw freeze);
+use URI::Escape;
 use CGI::Session;
 
 require Exporter;
@@ -225,6 +227,58 @@ sub get_template_and_user {
                 }
             }
         }
+		# Logged-in opac search history
+		# If the requested template is an opac one and opac search history is enabled
+		if ($in->{'type'} == "opac" && C4::Context->preference('EnableOpacSearchHistory')) {
+			my $dbh = C4::Context->dbh;
+			my $query = "SELECT COUNT(*) FROM search_history WHERE userid=?";
+			my $sth = $dbh->prepare($query);
+			$sth->execute($borrowernumber);
+			
+			# If at least one search has already been performed
+			if ($sth->fetchrow_array > 0) { 
+			# We show the link in opac
+			$template->param(ShowOpacRecentSearchLink => 1);
+			}
+
+			# And if there's a cookie with searches performed when the user was not logged in, 
+			# we add them to the logged-in search history
+			my @recentSearches;
+			my $searchcookie = $in->{'query'}->cookie('KohaOpacRecentSearches');
+			if ($searchcookie){
+				$searchcookie = uri_unescape($searchcookie);
+				if (thaw($searchcookie)) {
+					@recentSearches = @{thaw($searchcookie)};
+				}
+
+				if (@recentSearches > 0) {
+					my $query = "INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, total, time) VALUES";
+					my $icount = 1;
+					foreach my $asearch (@recentSearches) {
+						$query .= "(";
+						$query .= $borrowernumber . ", ";
+						$query .= '"' . $in->{'query'}->cookie("CGISESSID") . "\", ";
+						$query .= '"' . $asearch->{'query_desc'} . "\", ";
+						$query .= '"' . $asearch->{'query_cgi'} . "\", ";
+						$query .=       $asearch->{'total'} . ", ";
+						$query .= 'FROM_UNIXTIME(' . $asearch->{'time'} . "))";
+						if ($icount < @recentSearches) { $query .= ", ";}
+						$icount++;
+					}
+
+					my $sth = $dbh->prepare($query);
+					$sth->execute;
+
+					# And then, delete the cookie's content
+					my $newsearchcookie = $in->{'query'}->cookie(
+												-name => 'KohaOpacRecentSearches',
+												-value => freeze([]),
+												-expires => ''
+											 );
+					$cookie = [$cookie, $newsearchcookie];
+				}
+			}
+		}
     }
     else {  # if this is an anonymous session, setup to display public lists...
 
@@ -250,6 +304,17 @@ sub get_template_and_user {
         }
 
     }
+ 	# Anonymous opac search history
+ 	# If opac search history is enabled and at least one search has already been performed
+ 	if (C4::Context->preference('EnableOpacSearchHistory') && $in->{'query'}->cookie('KohaOpacRecentSearches')) {
+ 	    # We show the link in opac
+ 	    if (thaw(uri_unescape($in->{'query'}->cookie('KohaOpacRecentSearches')))) {
+			my @recentSearches = @{thaw(uri_unescape($in->{'query'}->cookie('KohaOpacRecentSearches')))};
+			if (@recentSearches > 0) {
+				$template->param(ShowOpacRecentSearchLink => 1);
+			}
+	    }
+ 	}
 
     # these template parameters are set the same regardless of $in->{'type'}
     $template->param(
diff --git a/C4/Search.pm b/C4/Search.pm
index f72bb11..b6bec0f 100644
--- a/C4/Search.pm
+++ b/C4/Search.pm
@@ -61,6 +61,7 @@ This module provides searching functions for Koha's bibliographic databases
   &getRecords
   &buildQuery
   &NZgetRecords
+  &AddSearchHistory
 );
 
 # make all your functions, whether exported or not;
@@ -2051,6 +2052,27 @@ sub enabled_staff_search_views
 	);
 }
 
+sub AddSearchHistory{
+	my ($borrowernumber,$session,$query_desc,$query_cgi, $total)=@_;
+    my $dbh = C4::Context->dbh;
+
+    # Add the request the user just made
+    my $sql = "INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, total, time) VALUES(?, ?, ?, ?, ?, NOW())";
+    my $sth   = $dbh->prepare($sql);
+    $sth->execute($borrowernumber, $session, $query_desc, $query_cgi, $total);
+	return $dbh->last_insert_id(undef, 'search_history', undef,undef,undef);
+}
+
+sub GetSearchHistory{
+	my ($borrowernumber,$session)=@_;
+    my $dbh = C4::Context->dbh;
+
+    # Add the request the user just made
+    my $query = "SELECT FROM search_history WHERE (userid=? OR sessionid=?)";
+    my $sth   = $dbh->prepare($query);
+	$sth->execute($borrowernumber, $session);
+    return  $sth->fetchall_hashref({});
+}
 
 =head2 z3950_search_args
 
diff --git a/Makefile.PL b/Makefile.PL
index a3775f0..635683a 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -588,6 +588,7 @@ WriteMakefile(
                             'POE'                              => 0.9999,
                             'POSIX'                            => 1.09,
                             'Schedule::At'                     => 1.06,
+                            'Storable'	                       => 2.21,
                             'SMS::Send'                        => 0.05, # optional
                             'Term::ANSIColor'                  => 1.10,
                             'Test'                             => 1.25,
diff --git a/installer/data/mysql/atomicupdate/0007-Opac-search-history.pl b/installer/data/mysql/atomicupdate/0007-Opac-search-history.pl
new file mode 100644
index 0000000..db902a9
--- /dev/null
+++ b/installer/data/mysql/atomicupdate/0007-Opac-search-history.pl
@@ -0,0 +1,24 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+use C4::Context;
+my $dbh=C4::Context->dbh;
+
+$dbh->do("INSERT INTO `systempreferences` (`variable`, `value`, `options`, `explanation`, `type`) VALUES ('EnableOpacSearchHistory', '1', '', 'Enable or disable opac search history', 'YesNo')");
+
+my $create = << END;
+CREATE TABLE IF NOT EXISTS `search_history` (
+  `userid` int(11) NOT NULL,
+  `sessionid` varchar(32) NOT NULL,
+  `query_desc` varchar(255) NOT NULL,
+  `query_cgi` varchar(255) NOT NULL,
+  `total` int(11) NOT NULL,
+  `time` timestamp NOT NULL default CURRENT_TIMESTAMP,
+  KEY `userid` (`userid`),
+  KEY `sessionid` (`sessionid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Opac search history results';
+END
+
+$dbh->do($create);
+
+print "Upgrade done (added OPAC search history preference and table)\n";
diff --git a/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc b/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc
index afe34d3..0112166 100644
--- a/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc
+++ b/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc
@@ -1,7 +1,7 @@
 <div id="header-wrapper"><div id="members">
   <!-- TMPL_IF NAME="opacuserlogin" -->
-	<ul><!-- TMPL_IF NAME="loggedinusername" --><li><span class="members">Welcome, <a href="/cgi-bin/koha/opac-user.pl"><span class="loggedinusername"><!-- TMPL_LOOP NAME="USER_INFO" --><!-- TMPL_VAR NAME="title" --> <!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --><!-- /TMPL_LOOP --></span></a></span></li><li><a class="logout" id="logout" href="/cgi-bin/koha/opac-main.pl?logout.x=1">Log Out</a></li><!-- TMPL_ELSE --><li><a href="/cgi-bin/koha/opac-user.pl">Log in to Your Account</a></li><!-- /TMPL_IF -->
-	</ul>	
+	<ul><!-- TMPL_IF NAME="loggedinusername" --><li><span class="members">Welcome, <a href="/cgi-bin/koha/opac-user.pl"><span class="loggedinusername"><!-- TMPL_LOOP NAME="USER_INFO" --><!-- TMPL_VAR NAME="title" --> <!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --><!-- /TMPL_LOOP --></span></a></span></li><!-- TMPL_IF NAME="ShowOpacRecentSearchLink" --><li><a href="/cgi-bin/koha/opac-search-history.pl" title="View your search history">Search history</a> [<a href="/cgi-bin/koha/opac-search-history.pl?action=delete" title="Delete your search history" onclick="javascript:return confirm(_('Are you sure you want to delete your search history?'));">x</a>]</li> <!-- /TMPL_IF --><li><a class="logout" id="logout" href="/cgi-bin/koha/opac-main.pl?logout.x=1">Log Out</a></li><!-- TMPL_ELSE --><li><a href="/cgi-bin/koha/opac-user.pl">Log in to Your Account</a></li><!-- /TMPL_IF -->
+   	</ul>	
   <!-- /TMPL_IF -->
 </div>
   <!-- TMPL_IF NAME="opacheader" -->
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-search-history.tmpl b/koha-tmpl/opac-tmpl/prog/en/modules/opac-search-history.tmpl
new file mode 100644
index 0000000..2823501
--- /dev/null
+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-search-history.tmpl
@@ -0,0 +1,80 @@
+<!-- TMPL_INCLUDE NAME="doc-head-open.inc" -->
+<!-- TMPL_IF NAME="LibraryNameTitle" --><!-- TMPL_VAR NAME="LibraryNameTitle" --><!-- TMPL_ELSE -->Koha Online<!-- /TMPL_IF --> Catalog
+<!-- TMPL_INCLUDE NAME="doc-head-close.inc" -->
+<script type="text/javascript" src="<!-- TMPL_VAR name="themelang" -->/lib/jquery/plugins/jquery.tablesorter.min.js"></script>
+<script type="text/JavaScript" language="JavaScript">
+//<![CDATA[
+         $(document).ready(function() {
+		// We show table ordered by descending dates by default
+		// (so that the more recent query is shown first)
+		$.tablesorter.defaults.sortList = [[0,1]]; 
+                $("#historyt").tablesorter({<!-- TMPL_IF EXPR="dateformat eq 'metric'" -->
+                        dateFormat: 'uk'<!-- /TMPL_IF -->
+                });
+            });
+//]]>
+
+</script>
+</head>
+<body>
+<!-- TMPL_IF NAME="OpacNav" --><div id="doc3" class="yui-t1"><!-- TMPL_ELSE --><div id="doc3" class="yui-t7"><!-- /TMPL_IF -->
+   <div id="bd">
+<!--TMPL_INCLUDE NAME="masthead.inc" -->
+
+	<div id="yui-main">
+<div class="yui-b"><div class="yui-g">
+        <div class="container">
+	<h1>Search history</h1>
+	<!-- TMPL_IF EXPR="recentSearches || previousSearches" -->
+	    <!-- TMPL_IF NAME="recentSearches" -->
+	    <!-- TMPL_IF NAME="previousSearches" -->
+	    <h2>Current session</h2>
+	    <!-- /TMPL_IF -->
+	    <table id="historyt">
+		<thead>
+		    <tr><th>Date</th><th>Search</th><th>Results</th></tr>
+		</thead>
+		<tbody>
+		    <!-- TMPL_LOOP NAME="recentSearches" -->
+		    <tr>
+			<td><!-- TMPL_VAR NAME="time" --></td>
+			<td><a href="/cgi-bin/koha/opac-search.pl?<!-- TMPL_VAR NAME="query_cgi" -->"><!-- TMPL_VAR NAME="query_desc" --></a></td>
+			<td><!-- TMPL_VAR NAME="total" --></td>
+		    </tr>
+		    <!-- /TMPL_LOOP -->
+		</tbody>
+	    </table>
+	    <!-- /TMPL_IF -->
+
+	    <!-- TMPL_IF NAME="previousSearches" -->
+	    <h2>Previous sessions</h2>
+	    <table id="historyt">
+		<thead>
+		    <tr><th>Date</th><th>Search</th><th>Results</th></tr>
+		</thead>
+		<tbody>
+		    <!-- TMPL_LOOP NAME="previousSearches" -->
+		    <tr>
+			<td><!-- TMPL_VAR NAME="time" --></td>
+			<td><a href="/cgi-bin/koha/opac-search.pl?<!-- TMPL_VAR NAME="query_cgi" -->"><!-- TMPL_VAR NAME="query_desc" --></a></td>
+			<td><!-- TMPL_VAR NAME="total" --></td>
+		    </tr>
+		    <!-- /TMPL_LOOP -->
+		</tbody>
+	    </table>
+	    <!-- /TMPL_IF -->
+	<!-- TMPL_ELSE -->
+	<p>Your search history is now empty.</p> 
+	<!-- /TMPL_IF -->
+     </div>
+     </div>
+     </div>
+     </div>
+<!-- TMPL_IF EXPR="OpacNav||loggedinusername" -->
+<div class="yui-b"><div class="container">
+<!--TMPL_INCLUDE NAME="navigation.inc" -->
+<!--TMPL_INCLUDE NAME="usermenu.inc" -->
+</div></div></div>
+<!-- /TMPL_IF -->
+
+<!-- TMPL_INCLUDE NAME="opac-bottom.inc" -->
diff --git a/opac/opac-search-history.pl b/opac/opac-search-history.pl
new file mode 100755
index 0000000..fdf0701
--- /dev/null
+++ b/opac/opac-search-history.pl
@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+
+# Copyright 2009 BibLibre SARL
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA  02111-1307 USA
+
+use strict;
+use C4::Auth qw(:DEFAULT get_session);
+use CGI;
+use Storable qw(freeze thaw);
+use C4::Context;
+use C4::Output;
+use C4::Log;
+use C4::Items;
+use C4::Debug;
+use C4::Dates;
+use URI::Escape;
+use POSIX qw(strftime);
+
+
+my $cgi = new CGI;
+
+# Getting the template and auth
+my ($template, $loggedinuser, $cookie)
+= get_template_and_user({template_name => "opac-search-history.tmpl",
+                                query => $cgi,
+                                type => "opac",
+                                authnotrequired => 1,
+                                flagsrequired => {borrowers => 1},
+                                debug => 1,
+                                });
+
+$template->param(dateformat => C4::Context->preference("dateformat"));
+
+# If the user is not logged in, we deal with the cookie
+if ($loggedinuser == '') {
+
+    # Deleting search history
+    if ($cgi->param('action') && $cgi->param('action') eq 'delete') {
+	# Deleting cookie's content 
+	my $recentSearchesCookie = $cgi->cookie(
+	    -name => 'KohaOpacRecentSearches',
+	    -value => freeze([]),
+	    -expires => ''
+	    );
+
+	# Redirecting to this same url with the cookie in the headers so it's deleted immediately
+	my $uri = $cgi->url();
+	print $cgi->redirect(-uri => $uri,
+			     -cookie => $recentSearchesCookie);
+
+    # Showing search history
+    } else {
+
+	# Getting the cookie
+	my $searchcookie = $cgi->cookie('KohaOpacRecentSearches');
+	if ($searchcookie && thaw(uri_unescape($searchcookie))) {
+	    my @recentSearches = @{thaw(uri_unescape($searchcookie))};
+	    if (@recentSearches) {
+
+		# As the dates are stored as unix timestamps, let's do some formatting
+		foreach my $asearch (@recentSearches) {
+
+		    # We create an iso date from the unix timestamp
+		    my $isodate = strftime "%Y-%m-%d", localtime($asearch->{'time'});
+
+		    # So we can create a C4::Dates object, to get the date formatted according to the dateformat syspref
+		    my $date = C4::Dates->new($isodate, "iso");
+		    my $sysprefdate = $date->output("syspref");
+		    
+		    # We also get the time of the day from the unix timestamp
+		    my $time = strftime " %H:%M:%S", localtime($asearch->{'time'});
+
+		    # And we got our human-readable date : 
+		    $asearch->{'time'} = $sysprefdate . $time;
+		}
+
+		$template->param(recentSearches => \@recentSearches);
+	    }
+	}
+    }
+} else {
+# And if the user is logged in, we deal with the database
+   
+    my $dbh = C4::Context->dbh;
+
+    # Deleting search history
+    if ($cgi->param('action') && $cgi->param('action') eq 'delete') {
+	my $query = "DELETE FROM search_history WHERE userid = ?";
+	my $sth   = $dbh->prepare($query);
+	$sth->execute($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 $date = C4::Dates->new();
+	my $dateformat = $date->DHTMLcalendar() . " %H:%i:%S"; # Current syspref date format + standard time format
+
+	# Getting the data with date format work done by mysql
+	my $query = "SELECT userid, sessionid, query_desc, query_cgi, total, DATE_FORMAT(time, \"$dateformat\") as time FROM search_history WHERE userid = ? AND sessionid = ?";
+	my $sth   = $dbh->prepare($query);
+	$sth->execute($loggedinuser, $cgi->cookie("CGISESSID"));
+	my $searches = $sth->fetchall_arrayref({});
+	$template->param(recentSearches => $searches);
+	
+	# Getting searches from previous sessions
+	$query = "SELECT COUNT(*) FROM search_history WHERE userid = ? AND sessionid != ?";
+	$sth   = $dbh->prepare($query);
+	$sth->execute($loggedinuser, $cgi->cookie("CGISESSID"));
+
+	# If at least one search from previous sessions has been performed
+        if ($sth->fetchrow_array > 0) {
+	    $query = "SELECT userid, sessionid, query_desc, query_cgi, total, DATE_FORMAT(time, \"$dateformat\") as time FROM search_history WHERE userid = ? AND sessionid != ?";
+	    $sth   = $dbh->prepare($query);
+	    $sth->execute($loggedinuser, $cgi->cookie("CGISESSID"));
+    	    my $previoussearches = $sth->fetchall_arrayref({});
+    	    $template->param(previousSearches => $previoussearches);
+	
+	}
+
+	$sth->finish;
+
+
+    }
+
+}
+output_html_with_http_headers $cgi, $cookie, $template->output;
+
+
diff --git a/opac/opac-search.pl b/opac/opac-search.pl
index 176b7ad..08b9c53 100755
--- a/opac/opac-search.pl
+++ b/opac/opac-search.pl
@@ -15,8 +15,10 @@ use C4::Search;
 use C4::Biblio;  # GetBiblioData
 use C4::Koha;
 use C4::Tags qw(get_tags);
-use POSIX qw(ceil floor strftime);
 use C4::Branch; # GetBranches
+use POSIX qw(ceil floor strftime);
+use URI::Escape;
+use Storable qw(thaw freeze);
 
 # create a new CGI object
 # FIXME: no_undef_params needs to be tested
@@ -437,7 +439,54 @@ for (my $i=0;$i<=@servers;$i++) {
 	if ($results_hashref->{$server}->{"hits"}){
 	    $total = $total + $results_hashref->{$server}->{"hits"};
 	}
-        ## If there's just one result, redirect to the detail page
+    > 
+ 	# Opac search history
+ 	my $newsearchcookie;
+ 	if (C4::Context->preference('EnableOpacSearchHistory')) {
+ 	    my @recentSearches; 
+ 
+ 	    # Getting the (maybe) already sent cookie
+ 	    my $searchcookie = $cgi->cookie('KohaOpacRecentSearches');
+ 	    if ($searchcookie){
+ 		$searchcookie = uri_unescape($searchcookie);
+ 		if (thaw($searchcookie)) {
+ 		    @recentSearches = @{thaw($searchcookie)};
+ 		}
+ 	    }
+ 
+ 	    # Adding the new search if needed
+ 	    if ($borrowernumber eq '') {
+ 	    # To a cookie (the user is not logged in)
+ 
+     		if ($params->{'offset'} eq '') {
+ 
+     		    push @recentSearches, {
+     					    "query_desc" => $query_desc || "unknown", 
+     					    "query_cgi"  => $query_cgi  || "unknown", 
+     					    "time"       => time(),
+     					    "total"      => $total
+     					  };
+     		    $template->param(ShowOpacRecentSearchLink => 1);
+     		}
+ 
+     		# Pushing the cookie back 
+     		$newsearchcookie = $cgi->cookie(
+ 					    -name => 'KohaOpacRecentSearches',
+ 					    # We uri_escape the whole freezed structure so we're sure we won't have any encoding problems
+ 					    -value => uri_escape(freeze(\@recentSearches)),
+ 					    -expires => ''
+ 			);
+ 			$cookie = [$cookie, $newsearchcookie];
+ 	    } 
+		else {
+ 	    # To the session (the user is logged in)
+ 			if ($params->{'offset'} eq '') {
+				AddSearchHistory($borrowernumber, $cgi->cookie("CGISESSID"), $query_desc, $query_cgi, $total);
+     		    $template->param(ShowOpacRecentSearchLink => 1);
+     		}
+ 	    }
+ 	}
+    ## If there's just one result, redirect to the detail page
         if ($total == 1) {         
             my $biblionumber=$newresults[0]->{biblionumber};
             if (C4::Context->preference('BiblioDefaultView') eq 'isbd') {
-- 
1.6.0.4




More information about the Koha-patches mailing list