Bug 17970: Add tests to highlight the problem
[koha.git] / C4 / Log.pm
blobd8ea1686dab216e8c87b3236cf3a4cda779540f1
1 package C4::Log;
3 #package to deal with Logging Actions in DB
6 # Copyright 2000-2002 Katipo Communications
7 # Copyright 2011 MJ Ray and software.coop
9 # This file is part of Koha.
11 # Koha is free software; you can redistribute it and/or modify it
12 # under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # Koha is distributed in the hope that it will be useful, but
17 # WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 use strict;
25 use warnings;
27 use JSON qw( to_json );
29 use C4::Context;
30 use Koha::DateUtils;
31 use Koha::Logger;
33 use vars qw(@ISA @EXPORT);
35 BEGIN {
36 require Exporter;
37 @ISA = qw(Exporter);
38 @EXPORT = qw(&logaction &cronlogaction &GetLogStatus &displaylog &GetLogs);
41 =head1 NAME
43 C4::Log - Koha Log Facility functions
45 =head1 SYNOPSIS
47 use C4::Log;
49 =head1 DESCRIPTION
51 The functions in this module perform various functions in order to log all the operations done on the Database, including deleting and undeleting books, adding/editing members, etc.
53 =head1 FUNCTIONS
55 =over 2
57 =item logaction
59 &logaction($modulename, $actionname, $objectnumber, $infos);
61 Adds a record into action_logs table to report the different changes upon the database.
62 Each log entry includes the number of the user currently logged in. For batch
63 jobs, which operate without authenticating a user and setting up a session, the user
64 number is set to 0, which is the same as the superlibrarian's number.
66 =cut
69 sub logaction {
70 my ($modulename, $actionname, $objectnumber, $infos, $interface)=@_;
72 # Get ID of logged in user. if called from a batch job,
73 # no user session exists and C4::Context->userenv() returns
74 # the scalar '0'.
75 my $userenv = C4::Context->userenv();
76 my $usernumber = (ref($userenv) eq 'HASH') ? $userenv->{'number'} : 0;
77 $usernumber ||= 0;
78 $interface //= C4::Context->interface;
80 my $dbh = C4::Context->dbh;
81 my $sth=$dbh->prepare("Insert into action_logs (timestamp,user,module,action,object,info,interface) values (now(),?,?,?,?,?,?)");
82 $sth->execute($usernumber,$modulename,$actionname,$objectnumber,$infos,$interface);
83 $sth->finish;
85 my $logger = Koha::Logger->get(
87 interface => 'intranet',
88 category => "ActionLogs.$modulename.$actionname"
91 $logger->debug(
92 sub {
93 "ACTION LOG: " . to_json(
95 user => $usernumber,
96 module => $modulename,
97 action => $actionname,
98 object => $objectnumber,
99 info => $infos
106 =item cronlogaction
108 &cronlogaction($infos);
110 Convenience routine to add a record into action_logs table from a cron job.
111 Logs the path and name of the calling script plus the information privided by param $infos.
113 =cut
116 sub cronlogaction {
117 my ($infos)=@_;
118 my $loginfo = (caller(0))[1];
119 $loginfo .= ' ' . $infos if $infos;
120 logaction( 'CRONJOBS', 'Run', undef, $loginfo ) if C4::Context->preference('CronjobLog');
124 =item GetLogStatus
126 $status = GetLogStatus;
128 C<$status> is a hasref like this example:
129 $hash = {
130 BorrowersLog => 1,
131 CataloguingLog => 0,
132 IssueLog => 0,
136 =cut
139 sub GetLogStatus {
140 my %hash;
141 $hash{BorrowersLog} = C4::Context->preference("BorrowersLog");
142 $hash{CataloguingLog} = C4::Context->preference("CataloguingLog");
143 $hash{HoldsLog} = C4::Context->preference("HoldsLog");
144 $hash{IssueLog} = C4::Context->preference("IssueLog");
145 $hash{ReturnLog} = C4::Context->preference("ReturnLog");
146 $hash{SubscriptionLog} = C4::Context->preference("SubscriptionLog");
147 $hash{LetterLog} = C4::Context->preference("LetterLog");
148 $hash{FinesLog} = C4::Context->preference("FinesLog");
149 return \%hash;
152 =item displaylog
154 &displaylog($modulename, @filters);
155 $modulename is the name of the module on which the user wants to display logs
156 @filters is an optional table of hash containing :
157 - name : the name of the variable to filter
158 - value : the value of the filter.... May be with * joker
160 returns a table of hash containing who did what on which object at what time
162 =cut
165 sub displaylog {
166 my ($modulename, @filters) = @_;
167 my $dbh = C4::Context->dbh;
168 my $strsth=qq|
169 SELECT action_logs.timestamp, action_logs.action, action_logs.info,
170 borrowers.cardnumber, borrowers.surname, borrowers.firstname, borrowers.userid,
171 biblio.biblionumber, biblio.title, biblio.author
172 FROM action_logs
173 LEFT JOIN borrowers ON borrowers.borrowernumber=action_logs.user
174 LEFT JOIN biblio ON action_logs.object=biblio.biblionumber
175 WHERE action_logs.module = 'cataloguing'
177 my %filtermap = ();
178 if ($modulename eq "catalogue" or $modulename eq "acqui") {
179 %filtermap = (
180 user => 'borrowers.surname',
181 title => 'biblio.title',
182 author => 'biblio.author',
184 } elsif ($modulename eq "members") {
185 $strsth=qq|
186 SELECT action_logs.timestamp, action_logs.action, action_logs.info,
187 borrowers.cardnumber, borrowers.surname, borrowers.firstname, borrowers.userid,
188 bor2.cardnumber, bor2.surname, bor2.firstname, bor2.userid
189 FROM action_logs
190 LEFT JOIN borrowers ON borrowers.borrowernumber=action_logs.user
191 LEFT JOIN borrowers as bor2 ON action_logs.object=bor2.borrowernumber
192 WHERE action_logs.module = 'members'
194 %filtermap = (
195 user => 'borrowers.surname',
196 surname => 'bor2.surname',
197 firstname => 'bor2.firstname',
198 cardnumber => 'bor2.cardnumber',
200 } else {
201 return 0;
204 if (@filters) {
205 foreach my $filter (@filters) {
206 my $tempname = $filter->{name} or next;
207 (grep {/^$tempname$/} keys %filtermap) or next;
208 $filter->{value} =~ s/\*/%/g;
209 $strsth .= " AND " . $filtermap{$tempname} . " LIKE " . $filter->{value};
212 my $sth=$dbh->prepare($strsth);
213 $sth->execute;
214 my @results;
215 my $count;
216 my $hilighted=1;
217 while (my $data = $sth->fetchrow_hashref){
218 $data->{hilighted} = ($hilighted>0);
219 $data->{info} =~ s/\n/<br\/>/g;
220 $data->{day} = output_pref({ str => $data->{timestamp} });
221 push @results, $data;
222 $count++;
223 $hilighted = -$hilighted;
225 return ($count, \@results);
228 =item GetLogs
230 $logs = GetLogs($datefrom,$dateto,$user,\@modules,$action,$object,$info);
232 Return:
233 C<$logs> is a ref to a hash which containts all columns from action_logs
235 =cut
237 sub GetLogs {
238 my $datefrom = shift;
239 my $dateto = shift;
240 my $user = shift;
241 my $modules = shift;
242 my $action = shift;
243 my $object = shift;
244 my $info = shift;
245 my $interfaces = shift;
247 my $iso_datefrom = $datefrom ? output_pref({ dt => dt_from_string( $datefrom ), dateformat => 'iso', dateonly => 1 }) : undef;
248 my $iso_dateto = $dateto ? output_pref({ dt => dt_from_string( $dateto ), dateformat => 'iso', dateonly => 1 }) : undef;
250 $user ||= q{};
252 my $dbh = C4::Context->dbh;
253 my $query = "
254 SELECT *
255 FROM action_logs
256 WHERE 1
259 my @parameters;
260 $query .=
261 " AND DATE_FORMAT(timestamp, '%Y-%m-%d') >= \"" . $iso_datefrom . "\" "
262 if $iso_datefrom; #fix me - mysql specific
263 $query .=
264 " AND DATE_FORMAT(timestamp, '%Y-%m-%d') <= \"" . $iso_dateto . "\" "
265 if $iso_dateto;
266 if ( $user ne q{} ) {
267 $query .= " AND user = ? ";
268 push( @parameters, $user );
270 if ( $modules && scalar(@$modules) ) {
271 $query .=
272 " AND module IN (" . join( ",", map { "?" } @$modules ) . ") ";
273 push( @parameters, @$modules );
275 if ( $action && scalar(@$action) ) {
276 $query .= " AND action IN (" . join( ",", map { "?" } @$action ) . ") ";
277 push( @parameters, @$action );
279 if ($object) {
280 $query .= " AND object = ? ";
281 push( @parameters, $object );
283 if ($info) {
284 $query .= " AND info LIKE ? ";
285 push( @parameters, "%" . $info . "%" );
287 if ( $interfaces && scalar(@$interfaces) ) {
288 $query .=
289 " AND interface IN (" . join( ",", map { "?" } @$interfaces ) . ") ";
290 push( @parameters, @$interfaces );
293 my $sth = $dbh->prepare($query);
294 $sth->execute(@parameters);
296 my @logs;
297 while ( my $row = $sth->fetchrow_hashref ) {
298 push @logs, $row;
300 return \@logs;
304 __END__
306 =back
308 =head1 AUTHOR
310 Koha Development Team <http://koha-community.org/>
312 =cut