Bug 6810: [QA Follow-up] Move test file to db_dependent
[koha.git] / C4 / Search / History.pm
1 package C4::Search::History;
2
3 use Modern::Perl;
4
5 use C4::Auth qw( get_session );
6 use C4::Context;
7 use Koha::DateUtils;
8
9 use JSON qw( encode_json decode_json );
10 use URI::Escape;
11 use Encode;
12
13 sub add {
14     my ($params)   = @_;
15     my $userid     = $params->{userid};
16     my $sessionid  = $params->{sessionid};
17     my $query_desc = $params->{query_desc};
18     my $query_cgi  = $params->{query_cgi};
19     my $total      = $params->{total} // 0;
20     my $type       = $params->{type} || 'biblio';
21
22     my $dbh = C4::Context->dbh;
23
24     # Add the request the user just made
25     my $query = q{
26         INSERT INTO search_history(
27             userid, sessionid, query_desc, query_cgi, type, total, time
28         ) VALUES(
29             ?, ?, ?, ?, ?, ?, NOW()
30         )
31     };
32     my $sth = $dbh->prepare($query);
33     $sth->execute( $userid, $sessionid, $query_desc, $query_cgi, $type,
34         $total );
35 }
36
37 sub add_to_session {
38     my ($params) = @_;
39     my $cgi = $params->{cgi};
40     my $query_desc = $params->{query_desc} || "unknown";
41     my $query_cgi  = $params->{query_cgi} || "unknown";
42     my $total      = $params->{total};
43     my $type       = $params->{type}                              || 'biblio';
44
45     # To a cookie (the user is not logged in)
46     my $now = dt_from_string;
47     my $id = $now->year . $now->month . $now->day . $now->hour . $now->minute . $now->second . int(rand(100));
48     my @recent_searches = get_from_session( { cgi => $cgi } );
49     push @recent_searches, {
50         query_desc => $query_desc,
51         query_cgi  => $query_cgi,
52         total      => "$total",
53         type       => $type,
54         time       => output_pref( { dt => $now, dateformat => 'iso', timeformat => '24hr' } ),
55         id         => $id,
56     };
57
58     shift @recent_searches if ( @recent_searches > 15 );
59     set_to_session( { cgi => $cgi, search_history => \@recent_searches } );
60 }
61
62 sub delete {
63     my ($params)  = @_;
64     my $id        = $params->{id};
65     my $userid    = $params->{userid};
66     my $sessionid = $params->{sessionid};
67     my $type      = $params->{type}     || q{};
68     my $previous  = $params->{previous} || 0;
69
70     unless ( ref( $id ) ) {
71         $id = $id ? [ $id ] : [];
72     }
73
74     unless ( $userid or @$id ) {
75         warn "ERROR: userid or id is required for history deletion";
76         return;
77     }
78
79     my $dbh   = C4::Context->dbh;
80     my $query = q{
81         DELETE FROM search_history
82         WHERE 1
83     };
84
85     $query .= q{ AND id IN ( } . join( q{,}, (q{?}) x @$id ) . q{ )}
86         if @$id;
87
88     $query .= q{
89         AND userid = ?
90     } if $userid;
91
92     if ($sessionid) {
93         $query .=
94           $previous
95           ? q{ AND sessionid != ?}
96           : q{ AND sessionid = ?};
97     }
98
99     $query .= q{ AND type = ?}
100       if $type;
101
102     $dbh->do(
103         $query, {},
104         ( @$id ? ( @$id ) : () ),
105         ( $userid ? $userid : () ),
106         ( $sessionid ? $sessionid : () ),
107         ( $type      ? $type      : () )
108     );
109 }
110
111 sub delete_from_cookie {
112     my ($params) = @_;
113     my $cookie   = $params->{cookie};
114     my $id       = $params->{id};
115
116     return unless $cookie;
117
118     unless ( ref( $id ) ) {
119         $id = $id ? [ $id ] : [];
120     }
121     return unless @$id;
122
123     my @searches;
124     if ( $cookie ){
125         $cookie = uri_unescape( $cookie );
126         if (decode_json( $cookie )) {
127             @searches = @{decode_json( $cookie )}
128         }
129     }
130
131     @searches = map {
132         my $search = $_;
133         ( grep { $_ != $search->{id} } @$id ) ? $search : ()
134     } @searches;
135
136     return uri_escape( encode_json( \@searches ) );
137
138 }
139
140 sub get {
141     my ($params)  = @_;
142     my $id        = $params->{id};
143     my $userid    = $params->{userid};
144     my $sessionid = $params->{sessionid};
145     my $type      = $params->{type};
146     my $previous  = $params->{previous};
147
148     unless ( ref( $id ) ) {
149         $id = $id ? [ $id ] : [];
150     }
151
152     unless ( $userid or @$id ) {
153         warn "ERROR: userid is required for history search";
154         return;
155     }
156
157     my $query = q{
158         SELECT *
159         FROM search_history
160         WHERE 1
161     };
162
163     $query .= q{ AND id IN ( } . join( q{,}, (q{?}) x @$id ) . q{ )}
164         if @$id;
165
166     $query .= q{
167         AND userid = ?
168     } if $userid;
169
170     if ($sessionid) {
171         $query .=
172           $previous
173           ? q{ AND sessionid != ?}
174           : q{ AND sessionid = ?};
175     }
176
177     $query .= q{ AND type = ?}
178       if $type;
179
180     my $dbh = C4::Context->dbh;
181     my $sth = $dbh->prepare($query);
182     $sth->execute(
183         ( @$id ? ( @$id ) : () ),
184         ( $userid ? $userid : () ),
185         ( $sessionid ? $sessionid : () ),
186         ( $type      ? $type      : () )
187     );
188     return $sth->fetchall_arrayref( {} );
189 }
190
191 sub get_from_session {
192     my ($params)  = @_;
193     my $cgi       = $params->{cgi};
194     my $sessionID = $cgi->cookie('CGISESSID');
195     return () unless $sessionID;
196     my $session = C4::Auth::get_session($sessionID);
197     return () unless $session and $session->param('search_history');
198     my $obj =
199       eval { decode_json( uri_unescape( $session->param('search_history') ) ) };
200     return () unless defined $obj;
201     return () unless ref $obj eq 'ARRAY';
202     return @{$obj};
203 }
204
205 sub set_to_session {
206     my ($params)       = @_;
207     my $cgi            = $params->{cgi};
208     my $search_history = $params->{search_history};
209     my $sessionID      = $cgi->cookie('CGISESSID');
210     return () unless $sessionID;
211     my $session = C4::Auth::get_session($sessionID);
212     return () unless $session;
213     $session->param( 'search_history',
214         uri_escape( encode_json($search_history) ) );
215 }
216
217 1;
218
219 __END__
220
221 =pod
222
223 =head1 NAME
224
225 C4::Search::History - Manage search history
226
227 =head1 DESCRIPTION
228
229 This module provides some routines for the search history management.
230 It deals with session or database.
231
232 =head1 ROUTINES
233
234 =head2 add
235
236     C4::Search::History::add({
237         userid => $userid,
238         sessionid => $cgi->cookie("CGIESSID"),
239         query_desc => $query_desc,
240         query_cgi => $query_cgi,
241         total => $total,
242         type => $type,
243     });
244
245 type is "biblio" or "authority".
246
247 Add a new search to the user's history.
248
249 =head2 add_to_session
250
251     my $value = C4::Search::History::add_to_session({
252         cgi => $cgi,
253         query_desc => $query_desc,
254         query_cgi => $query_cgi,
255         total => $total,
256         type => $type,
257     });
258
259 Add a search to the session. The number of searches to keep is hardcoded to 15.
260
261 =head2 delete
262
263     C4::Search::History::delete({
264         userid => $loggedinuser,
265         sessionid => $sessionid,
266         type => $type,
267         previous => $previous
268     });
269
270 Delete searches in the database.
271 If the sessionid is missing all searches for all sessions will be deleted.
272 It is possible to delete searches for current session or all previous sessions using the previous flag.
273 If the type ("biblio" or "authority") is missing, all type will be deleted.
274 To delete *all* searches for a given userid, just pass a userid.
275
276 =head2 get
277
278     my $searches C4::Search::History::get({
279         userid => $userid,
280         sessionsid => $sessionid,
281         type => $type,
282         previous => $previous
283     });
284
285 Return a list of searches for a given userid.
286 If a sessionid is given, searches are limited to the matching session.
287 type and previous follow the same behavior as the delete routine.
288
289 =head2 get_from_session
290
291     my $searches = C4::Search::History::get_from_session({
292         cgi => $cgi
293     });
294
295 Return all searches present for the given session.
296
297 =head2 set_to_session
298
299     C4::Search::History::set_to_session({
300         cgi => $cgi,
301         search_history => $search_history
302     });
303
304 Store searches into the session.
305
306 =head1 AUTHORS
307
308 Jonathan Druart <jonathan.druart@biblibre.com>
309
310 =head1 LICENSE
311
312 This file is part of Koha.
313
314 Copyright 2013 BibLibre SARL
315
316 Koha is free software; you can redistribute it and/or modify it
317 under the terms of the GNU General Public License as published by
318 the Free Software Foundation; either version 3 of the License, or
319 (at your option) any later version.
320
321 Koha is distributed in the hope that it will be useful, but
322 WITHOUT ANY WARRANTY; without even the implied warranty of
323 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
324 GNU General Public License for more details.
325
326 You should have received a copy of the GNU General Public License
327 along with Koha; if not, see <http://www.gnu.org/licenses>.