View | Details | Raw Unified | Return to bug 20750
Collapse All | Expand All

(-)a/C4/Log.pm (+1 lines)
Lines 142-147 sub GetLogStatus { Link Here
142
    $hash{CataloguingLog}  = C4::Context->preference("CataloguingLog");
142
    $hash{CataloguingLog}  = C4::Context->preference("CataloguingLog");
143
    $hash{HoldsLog}        = C4::Context->preference("HoldsLog");
143
    $hash{HoldsLog}        = C4::Context->preference("HoldsLog");
144
    $hash{IssueLog}        = C4::Context->preference("IssueLog");
144
    $hash{IssueLog}        = C4::Context->preference("IssueLog");
145
    $hash{IllLog}          = C4::Context->preference("IllLog");
145
    $hash{ReturnLog}       = C4::Context->preference("ReturnLog");
146
    $hash{ReturnLog}       = C4::Context->preference("ReturnLog");
146
    $hash{SubscriptionLog} = C4::Context->preference("SubscriptionLog");
147
    $hash{SubscriptionLog} = C4::Context->preference("SubscriptionLog");
147
    $hash{LetterLog}       = C4::Context->preference("LetterLog");
148
    $hash{LetterLog}       = C4::Context->preference("LetterLog");
(-)a/Koha/Illrequest.pm (-1 / +73 lines)
Lines 30-35 use Koha::Database; Link Here
30
use Koha::Email;
30
use Koha::Email;
31
use Koha::Exceptions::Ill;
31
use Koha::Exceptions::Ill;
32
use Koha::Illrequestattributes;
32
use Koha::Illrequestattributes;
33
use Koha::Illrequest::Logger;
33
use Koha::Patron;
34
use Koha::Patron;
34
35
35
use base qw(Koha::Object);
36
use base qw(Koha::Object);
Lines 119-124 sub illrequestattributes { Link Here
119
    );
120
    );
120
}
121
}
121
122
123
=head3 logs
124
125
=cut
126
127
sub logs {
128
    my ( $self ) = @_;
129
    my $logger = Koha::Illrequest::Logger->new;
130
    return $logger->get_request_logs($self);
131
}
132
122
=head3 patron
133
=head3 patron
123
134
124
=cut
135
=cut
Lines 151-157 sub load_backend { Link Here
151
    my $location = join "/", @raw, $backend_name, "Base.pm";    # File to load
162
    my $location = join "/", @raw, $backend_name, "Base.pm";    # File to load
152
    my $backend_class = join "::", @raw, $backend_name, "Base"; # Package name
163
    my $backend_class = join "::", @raw, $backend_name, "Base"; # Package name
153
    require $location;
164
    require $location;
154
    $self->{_my_backend} = $backend_class->new({ config => $self->_config });
165
    $self->{_my_backend} = $backend_class->new({
166
        config => $self->_config,
167
        logger => Koha::Illrequest::Logger->new
168
    });
155
    return $self;
169
    return $self;
156
}
170
}
157
171
Lines 984-989 sub _censor { Link Here
984
    return $params;
998
    return $params;
985
}
999
}
986
1000
1001
=head3 status
1002
1003
    $Illrequest->status('CANREQ');
1004
1005
Overloaded I<status> method that, in addition to setting the request status
1006
records the fact that the status has changed
1007
1008
=cut
1009
1010
sub status {
1011
    my ( $self, $new_status ) = @_;
1012
1013
    my $current_status = $self->SUPER::status;
1014
1015
    if ($new_status) {
1016
        # Keep a record of the previous status before we change it,
1017
        # we might need it
1018
        $self->{previous_status} = $current_status;
1019
        my $ret = $self->SUPER::status($new_status)->store;
1020
        if ($ret) {
1021
            my $logger = Koha::Illrequest::Logger->new;
1022
            $logger->log_status_change(
1023
                $self,
1024
                $new_status
1025
            );
1026
        } else {
1027
            delete $self->{previous_status};
1028
        }
1029
        return $ret;
1030
    } else {
1031
        return $current_status;
1032
    }
1033
}
1034
1035
=head3 store
1036
1037
    $Illrequest->store;
1038
1039
Overloaded I<store> method that, in addition to performing the 'store',
1040
possibly records the fact that something happened
1041
1042
=cut
1043
1044
sub store {
1045
    my ( $self, $attrs ) = @_;
1046
1047
    my $ret = $self->SUPER::store;
1048
1049
    $attrs->{log_origin} = 'core';
1050
1051
    if ($ret && defined $attrs) {
1052
        my $logger = Koha::Illrequest::Logger->new;
1053
        $logger->log_maybe($self, $attrs);
1054
    }
1055
1056
    return $ret;
1057
}
1058
987
=head3 TO_JSON
1059
=head3 TO_JSON
988
1060
989
    $json = $illrequest->TO_JSON
1061
    $json = $illrequest->TO_JSON
(-)a/Koha/Illrequest/Logger.pm (+242 lines)
Line 0 Link Here
1
package Koha::Illrequest::Logger;
2
3
# Copyright 2018 PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use JSON qw( to_json from_json );
22
23
use C4::Context;
24
use C4::Templates;
25
use C4::Log qw( logaction GetLogs );
26
27
=head1 NAME
28
29
Koha::Illrequest::Logger - Koha ILL Action / Event logger
30
31
=head1 SYNOPSIS
32
33
Object-oriented class that provides event logging functionality for
34
ILL requests
35
36
=head1 DESCRIPTION
37
38
This class provides the ability to log arbitrary actions or events
39
relating to Illrequest to the action log.
40
41
=head1 API
42
43
=head2 Class Methods
44
45
=head3 new
46
47
    my $config = Koha::Illrequest::Logger->new();
48
49
Create a new Koha::Illrequest::Logger object, with skeleton logging data
50
We also set up data of what can be logged, how to do it and how to display
51
log entries we get back out
52
53
=cut
54
55
sub new {
56
    my ( $class ) = @_;
57
    my $self  = {};
58
59
    $self->{data} = {
60
        modulename => 'ILL'
61
    };
62
63
    $self->{loggers} = {
64
        status => sub {
65
            $self->log_status_change(@_);
66
        }
67
    };
68
69
    my ( $htdocs, $theme, $lang, $base ) =
70
        C4::Templates::_get_template_file('ill/log/', 'intranet');
71
72
    $self->{templates} = {
73
        STATUS_CHANGE => $base . 'status_change.tt'
74
    };
75
76
    bless $self, $class;
77
78
    return $self;
79
}
80
81
=head3 log_maybe
82
83
    Koha::IllRequest::Logger->log_maybe($attrs);
84
85
Receive request object and an attributes hashref (which may or may
86
not be defined) If the hashref contains a key matching our "loggers" hashref
87
then we want to log it
88
89
=cut
90
91
sub log_maybe {
92
    my ($self, $req, $attrs) = @_;
93
94
    if (defined $req && defined $attrs) {
95
        foreach my $key (keys %{ $attrs }) {
96
            if (defined($self->{loggers}->{$key})) {
97
                $self->{loggers}->{$key}($req, $attrs->{$key});
98
            }
99
        }
100
    }
101
}
102
103
=head3 log_status_change
104
105
    Koha::IllRequest::Logger->log_status_change();
106
107
Log a request's status change
108
109
=cut
110
111
sub log_status_change {
112
    my ( $self, $req, $new_status ) = @_;
113
114
    $self->set_data({
115
        actionname   => 'STATUS_CHANGE',
116
        objectnumber => $req->id,
117
        infos        => to_json({
118
            log_origin    => 'core',
119
            status_before => $req->{previous_status},
120
            status_after  => $new_status
121
        })
122
    });
123
124
    $self->log_something();
125
}
126
127
=head3 log_something
128
129
    Koha::IllRequest::Logger->log_something();
130
131
If we have the required data set, log an action
132
133
=cut
134
135
sub log_something {
136
    my ( $self ) = @_;
137
138
    if (
139
        defined $self->{data}->{modulename} &&
140
        defined $self->{data}->{actionname} &&
141
        defined $self->{data}->{objectnumber} &&
142
        defined $self->{data}->{infos} &&
143
        C4::Context->preference("IllLog")
144
    ) {
145
        logaction(
146
            $self->{data}->{modulename},
147
            $self->{data}->{actionname},
148
            $self->{data}->{objectnumber},
149
            $self->{data}->{infos}
150
        );
151
    }
152
}
153
154
=head3 set_data
155
156
    Koha::IllRequest::Logger->set_data({
157
        key  => 'value',
158
        key2 => 'value2'
159
    });
160
161
Set arbitrary data propert(ies) on the logger object
162
163
=cut
164
165
sub set_data {
166
    my ( $self, $data ) = @_;
167
168
    foreach my $key (keys %{ $data }) {
169
        $self->{data}->{$key} = $data->{$key};
170
    }
171
}
172
173
=head3 get_log_template
174
175
    $template_path = get_log_template($origin, $action);
176
177
Given a log's origin and action, get the appropriate display template
178
179
=cut
180
181
sub get_log_template {
182
    my ($self, $req, $params) = @_;
183
184
    my $origin = $params->{origin};
185
    my $action = $params->{action};
186
187
    if ($origin eq 'core') {
188
        # It's a core log, so we can just get the template path from
189
        # the hashref above
190
        return $self->{templates}->{$action};
191
    } else {
192
        # It's probably a backend log, so we need to get the path to the
193
        # template from the backend
194
        my $backend =$req->{_my_backend};
195
        return $backend->get_log_template_path($action);
196
    }
197
}
198
199
=head3 get_request_logs
200
201
    $requestlogs = Koha::IllRequest::Logger->get_request_logs($request_id);
202
203
Get all logged actions for a given request
204
205
=cut
206
207
sub get_request_logs {
208
    my ( $self, $request ) = @_;
209
210
    my $logs = GetLogs(
211
        undef,
212
        undef,
213
        undef,
214
        ['ILL'],
215
        undef,
216
        $request->id,
217
        undef,
218
        undef
219
    );
220
    foreach my $log(@{$logs}) {
221
        $log->{info} = from_json($log->{info});
222
        $log->{template} = $self->get_log_template(
223
        $request,
224
            {
225
                origin => $log->{info}->{log_origin},
226
                action => $log->{action}
227
            }
228
        );
229
    }
230
231
    my @sorted = sort {$$b{'timestamp'} <=> $$a{'timestamp'}} @{$logs};
232
233
    return \@sorted;
234
}
235
236
=head1 AUTHOR
237
238
Andrew Isherwood <andrew.isherwood@ptfs-europe.com>
239
240
=cut
241
242
1;
(-)a/installer/data/mysql/atomicupdate/bug_20750-add_illlog_preference.perl (+7 lines)
Line 0 Link Here
1
$DBversion = 'XXX';  # will be replaced by the RM
2
if( CheckVersion( $DBversion ) ) {
3
    $dbh->do( "INSERT IGNORE INTO systempreferences (variable, value, explanation, type) VALUES ('IllLog', 1, 'If ON, log information about ILL requests', 'YesNo')" );
4
5
    SetVersion( $DBversion );
6
    print "Upgrade to $DBversion done (Bug 20750 - Allow timestamped auditing of ILL request events)\n";
7
}
(-)a/installer/data/mysql/en/optional/ill_logging_pref.sql (+1 lines)
Line 0 Link Here
1
INSERT IGNORE INTO systempreferences (variable, value, explanation, type) VALUES ('IllLog', 1, 'If ON, log information about ILL requests', 'YesNo');
(-)a/installer/data/mysql/en/optional/ill_logging_pref.txt (+1 lines)
Line 0 Link Here
1
System preference to determine if logging of ILL requests should occur
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 203-208 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
203
('IDreamBooksResults','0','','Display IDreamBooks.com rating in search results','YesNo'),
203
('IDreamBooksResults','0','','Display IDreamBooks.com rating in search results','YesNo'),
204
('IDreamBooksReviews','0','','Display book review snippets from IDreamBooks.com','YesNo'),
204
('IDreamBooksReviews','0','','Display book review snippets from IDreamBooks.com','YesNo'),
205
('IdRef','0','','Disable/enable the IdRef webservice from the OPAC detail page.','YesNo'),
205
('IdRef','0','','Disable/enable the IdRef webservice from the OPAC detail page.','YesNo'),
206
('IllLog', 1, '', 'If ON, log information about ILL requests', 'YesNo'),
206
('ILLModule','0','If ON, enables the interlibrary loans module.','','YesNo'),
207
('ILLModule','0','If ON, enables the interlibrary loans module.','','YesNo'),
207
('ILLModuleCopyrightClearance','','70|10','Enter text to enable the copyright clearance stage of request creation. Text will be displayed','Textarea'),
208
('ILLModuleCopyrightClearance','','70|10','Enter text to enable the copyright clearance stage of request creation. Text will be displayed','Textarea'),
208
('ILS-DI','0','','Enables ILS-DI services at OPAC.','YesNo'),
209
('ILS-DI','0','','Enables ILS-DI services at OPAC.','YesNo'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref (+6 lines)
Lines 37-42 Logging: Link Here
37
                  off: "Don't log"
37
                  off: "Don't log"
38
            - any actions on holds (create, cancel, suspend, resume, etc).
38
            - any actions on holds (create, cancel, suspend, resume, etc).
39
        -
39
        -
40
            - pref: IllLog
41
              choices:
42
                  on: Log
43
                  off: "Don't log"
44
            - when changes to ILL requests take place
45
        -
40
            - pref: IssueLog
46
            - pref: IssueLog
41
              choices:
47
              choices:
42
                  on: Log
48
                  on: Log
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt (+34 lines)
Lines 193-198 Link Here
193
            }
193
            }
194
        };
194
        };
195
195
196
        // Display the modal containing request supplier metadata
197
        $('#ill-request-display-log').on('click', function(e) {
198
            e.preventDefault();
199
            $('#requestLog').modal({show:true});
200
        });
201
196
        // Toggle request attributes in Illview
202
        // Toggle request attributes in Illview
197
        $('#toggle_requestattributes').on('click', function(e) {
203
        $('#toggle_requestattributes').on('click', function(e) {
198
            e.preventDefault();
204
            e.preventDefault();
Lines 496-501 Link Here
496
                                </a>
502
                                </a>
497
                            [% END %]
503
                            [% END %]
498
                        [% END %]
504
                        [% END %]
505
                        <a title="Display request log" id="ill-request-display-log" class="btn btn-sm btn-default pull-right" href="#">
506
                            <span class="fa fa-calendar"></span>
507
                            Display request log
508
                        </a>
499
                    </div>
509
                    </div>
500
                    <div id="ill-view-panel" class="panel panel-default">
510
                    <div id="ill-view-panel" class="panel panel-default">
501
                        <div class="panel-heading">
511
                        <div class="panel-heading">
Lines 577-582 Link Here
577
                        </div>
587
                        </div>
578
                    </div>
588
                    </div>
579
589
590
                    <div id="requestLog" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="dataPreviewLabel" aria-hidden="true">
591
                        <div class="modal-dialog">
592
                            <div class="modal-content">
593
                                <div class="modal-header">
594
                                    <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
595
                                    <h3 id="requestLogLabel"> Request log</h3>
596
                                </div>
597
                                <div class="modal-body">
598
                                [% IF request.logs.size > 0 %]
599
                                    [% FOREACH log IN request.logs %]
600
                                        [% tpl = log.template %]
601
                                        [% INCLUDE $tpl %]
602
                                    [% END %]
603
                                [% ELSE %]
604
                                    There are no recorded logs for this request
605
                                [% END %]
606
                                </div>
607
                                <div class="modal-footer">
608
                                    <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
609
                                </div>
610
                            </div>
611
                        </div>
612
                    </div>
613
580
                [% ELSIF query_type == 'illlist' %]
614
                [% ELSIF query_type == 'illlist' %]
581
                    <!-- illlist -->
615
                    <!-- illlist -->
582
                    <h1>View ILL requests</h1>
616
                    <h1>View ILL requests</h1>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/status_change.tt (+7 lines)
Line 0 Link Here
1
<p>
2
[% log.timestamp | $KohaDates with_hours => 1 %] : <b>Status changed </b>
3
[% IF log.info.status_before %]
4
from &quot;[% request.capabilities(log.info.status_before).name %]&quot;
5
[% END %]
6
to &quot;[% request.capabilities(log.info.status_after).name %]&quot;
7
</p>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt (-1 / +4 lines)
Lines 27-32 Link Here
27
[%        CASE 'ACQUISITIONS' %]Acquisitions
27
[%        CASE 'ACQUISITIONS' %]Acquisitions
28
[%        CASE 'SERIAL'       %]Serials
28
[%        CASE 'SERIAL'       %]Serials
29
[%        CASE 'HOLDS'        %]Holds
29
[%        CASE 'HOLDS'        %]Holds
30
[%        CASE 'ILL'          %]Interlibrary loans
30
[%        CASE 'CIRCULATION'  %]Circulation
31
[%        CASE 'CIRCULATION'  %]Circulation
31
[%        CASE 'LETTER'       %]Letter
32
[%        CASE 'LETTER'       %]Letter
32
[%        CASE 'FINES'        %]Fines
33
[%        CASE 'FINES'        %]Fines
Lines 52-57 Link Here
52
[%        CASE 'CHANGE PASS' %]Change password
53
[%        CASE 'CHANGE PASS' %]Change password
53
[%        CASE 'ADDCIRCMESSAGE' %]Add circulation message
54
[%        CASE 'ADDCIRCMESSAGE' %]Add circulation message
54
[%        CASE 'DELCIRCMESSAGE' %]Delete circulation message
55
[%        CASE 'DELCIRCMESSAGE' %]Delete circulation message
56
[%        CASE 'STATUS_CHANGE'  %]Change ILL request status
57
[%        CASE 'BLDSS_STATUS_CHECK'  %]Check ILL request status with BLDSS
55
[%        CASE 'Run'    %]Run
58
[%        CASE 'Run'    %]Run
56
[%        CASE %][% action %]
59
[%        CASE %][% action %]
57
[%    END %]
60
[%    END %]
Lines 101-107 Link Here
101
                                    [% ELSE %]
104
                                    [% ELSE %]
102
                                        <option value="">All</option>
105
                                        <option value="">All</option>
103
                                    [% END %]
106
                                    [% END %]
104
                                    [% FOREACH modx IN [ 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'CIRCULATION' 'LETTER' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS' ] %]
107
                                    [% FOREACH modx IN [ 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'LETTER' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS' ] %]
105
                                        [% IF modules.grep(modx).size %]
108
                                        [% IF modules.grep(modx).size %]
106
                                            <option value="[% modx %]" selected="selected">[% PROCESS translate_log_module module=modx %]</option>
109
                                            <option value="[% modx %]" selected="selected">[% PROCESS translate_log_module module=modx %]</option>
107
                                        [% ELSE %]
110
                                        [% ELSE %]
(-)a/t/Log.t (-1 / +1 lines)
Lines 16-21 BEGIN { Link Here
16
t::lib::Mocks::mock_preference('BorrowersLog', 1);
16
t::lib::Mocks::mock_preference('BorrowersLog', 1);
17
t::lib::Mocks::mock_preference('CataloguingLog', 1);
17
t::lib::Mocks::mock_preference('CataloguingLog', 1);
18
t::lib::Mocks::mock_preference('IssueLog', 1);
18
t::lib::Mocks::mock_preference('IssueLog', 1);
19
t::lib::Mocks::mock_preference('IllLog', 1);
19
t::lib::Mocks::mock_preference('ReturnLog', 1);
20
t::lib::Mocks::mock_preference('ReturnLog', 1);
20
t::lib::Mocks::mock_preference('SubscriptionLog', 1);
21
t::lib::Mocks::mock_preference('SubscriptionLog', 1);
21
t::lib::Mocks::mock_preference('LetterLog', 1);
22
t::lib::Mocks::mock_preference('LetterLog', 1);
22
- 

Return to bug 20750