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

(-)a/Koha/Notice/Message.pm (+36 lines)
Lines 20-25 use Modern::Perl; Link Here
20
use Carp;
20
use Carp;
21
21
22
use Koha::Database;
22
use Koha::Database;
23
use Koha::Patron::Debarments;
23
24
24
use base qw(Koha::Object);
25
use base qw(Koha::Object);
25
26
Lines 33-38 Koha::Notice::Message - Koha notice message Object class, related to the message Link Here
33
34
34
=cut
35
=cut
35
36
37
=head3 restrict_patron_when_notice_fails
38
39
    $failed_notice->restrict_patron_when_notice_fails;
40
41
Places a restriction (debarment) on patrons with failed SMS and email notices.
42
43
=cut
44
45
sub restrict_patron_when_notice_fails {
46
    my ( $self ) = @_;
47
48
    # Set the appropriate restriction (debarment) comment depending if the failed
49
    # message is a SMS or email notice. If the failed notice is neither then
50
    # return without placing a restriction
51
    my $comment;
52
    if ($self->message_transport_type eq 'email') {
53
        $comment = 'Email address invalid';
54
    } elsif ($self->message_transport_type eq 'sms') {
55
        $comment = 'SMS number invalid';
56
    } else {
57
        return;
58
    }
59
60
    AddDebarment(
61
        {
62
            borrowernumber => $self->borrowernumber,
63
            type           => 'SUSPENSION',
64
            comment        => $comment,
65
            expiration     => undef,
66
        }
67
    );
68
69
    return $self;
70
}
71
36
=head3 type
72
=head3 type
37
73
38
=cut
74
=cut
(-)a/Koha/Notice/Messages.pm (-1 / +19 lines)
Lines 20-26 use Modern::Perl; Link Here
20
use Carp;
20
use Carp;
21
21
22
use Koha::Database;
22
use Koha::Database;
23
24
use Koha::Notice::Message;
23
use Koha::Notice::Message;
25
24
26
use base qw(Koha::Objects);
25
use base qw(Koha::Objects);
Lines 35-40 Koha::Notice::Message - Koha notice message Object class, related to the message Link Here
35
34
36
=cut
35
=cut
37
36
37
=head3 get_failed_notices
38
39
    my $failed_notices = Koha::Notice::Messages->get_failed_notices({ days => 7 });
40
41
Returns a hashref of all notices that have failed to send in the last X days, as specified in the 'days' parameter.
42
If not specified, will default to the last 7 days.
43
44
=cut
45
46
sub get_failed_notices {
47
    my ( $self, $params ) = @_;
48
    my $days = $params->{days} ? $params->{days} : 7;
49
50
    return $self->search({
51
        time_queued => { -between => \"DATE_SUB(NOW(), INTERVAL $days DAY) AND NOW()" },
52
        status => "failed",
53
    });
54
}
55
38
=head3 type
56
=head3 type
39
57
40
=cut
58
=cut
(-)a/installer/data/mysql/atomicupdate/bug_23295-add_RestrictPatronsWithFailedNotices_syspref.perl (+6 lines)
Line 0 Link Here
1
$DBversion = 'XXX';
2
if ( CheckVersion( $DBversion ) ) {
3
    $dbh->do(q{ INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type) VALUES ('RestrictPatronsWithFailedNotices', '0', NULL, 'If enabled then when SMS and email notices fail sending at the Koha level then a debarment will be applied to a patrons account', 'YesNo') });
4
5
    NewVersion( $DBversion, 23295, "Add RestrictPatronsWithFailedNotices system preference" );
6
}
(-)a/installer/data/mysql/mandatory/sysprefs.sql (+1 lines)
Lines 563-568 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
563
('RESTOAuth2ClientCredentials','0',NULL,'If enabled, the OAuth2 client credentials flow is enabled for the REST API.','YesNo'),
563
('RESTOAuth2ClientCredentials','0',NULL,'If enabled, the OAuth2 client credentials flow is enabled for the REST API.','YesNo'),
564
('RESTPublicAnonymousRequests','1',NULL,'If enabled, the API will allow anonymous access to public routes that don\'t require authenticated access.','YesNo'),
564
('RESTPublicAnonymousRequests','1',NULL,'If enabled, the API will allow anonymous access to public routes that don\'t require authenticated access.','YesNo'),
565
('RESTPublicAPI','1',NULL,'If enabled, the REST API will expose the /public endpoints.','YesNo'),
565
('RESTPublicAPI','1',NULL,'If enabled, the REST API will expose the /public endpoints.','YesNo'),
566
('RestrictPatronsWithFailedNotices', '0', NULL, 'If enabled then when SMS and email notices fail sending at the Koha level then a debarment will be applied to a patrons account', 'YesNo'),
566
('RestrictedPageLocalIPs','',NULL,'Beginning of IP addresses considered as local (comma separated ex: "127.0.0,127.0.2")','Free'),
567
('RestrictedPageLocalIPs','',NULL,'Beginning of IP addresses considered as local (comma separated ex: "127.0.0,127.0.2")','Free'),
567
('RestrictedPageContent','',NULL,'HTML content of the restricted page','TextArea'),
568
('RestrictedPageContent','',NULL,'HTML content of the restricted page','TextArea'),
568
('RestrictedPageTitle','',NULL,'Title of the restricted page (breadcrumb and header)','Free'),
569
('RestrictedPageTitle','',NULL,'Title of the restricted page (breadcrumb and header)','Free'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (+8 lines)
Lines 304-309 Patrons: Link Here
304
               yes: Allow
304
               yes: Allow
305
               no: "Don't allow"
305
               no: "Don't allow"
306
         - staff to set the ability for a patron's fines to be viewed by linked patrons in the OPAC.
306
         - staff to set the ability for a patron's fines to be viewed by linked patrons in the OPAC.
307
    -
308
         - pref: RestrictPatronsWithFailedNotices
309
           choices:
310
               yes: Apply
311
               no: "Don't apply"
312
         - "a restriction to a patron when their email and SMS messages fail to send at the Koha level."
313
         - "<br><strong>NOTE:</strong> This system preference requires the <code>misc/cronjobs/restrict_patrons_with_failed_notices.pl</code> cronjob. Ask your system administrator to schedule it."
314
307
    Privacy:
315
    Privacy:
308
     -
316
     -
309
         - Use the following URL
317
         - Use the following URL
(-)a/misc/cronjobs/restrict_patrons_with_failed_notices.pl (+152 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2020 Catalyst IT
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Getopt::Long;
23
use Pod::Usage;
24
use C4::Log;
25
26
use C4::Context;
27
use Koha::Patron::Debarments;
28
use Koha::Patrons;
29
use C4::Letters;
30
use Koha::Notice::Message;
31
32
# Getting options
33
my ($help, $verbose, $confirm);
34
GetOptions(
35
    'h|help'    => \$help,
36
    'v|verbose' => \$verbose,
37
    'c|confirm' => \$confirm,
38
);
39
40
pod2usage(1) if $help;
41
42
if ( !C4::Context->preference('RestrictPatronsWithFailedNotices') and $verbose ) {
43
    warn <<'END_WARN';
44
45
The 'RestrictPatronsWithFailedNotices' system preference is disabled.
46
This script requires the 'RestrictPatronsWithFailedNotices' system preference to be enabled.
47
Exiting cronjob
48
49
END_WARN
50
}
51
cronlogaction();
52
53
my @failed_notices = Koha::Notice::Messages->get_failed_notices({ days => 7 });
54
55
if ( C4::Context->preference('RestrictPatronsWithFailedNotices') ) {
56
   if ( @failed_notices ) {
57
        say "There are borrowers with failed SMS or email notices" if $verbose;
58
59
        foreach my $failed_notice ( @failed_notices ) {
60
61
            # If failed notice is not a sms or email notice then skip to next failed notice
62
            next unless ($failed_notice->message_transport_type eq 'sms' || $failed_notice->message_transport_type eq 'email');
63
64
            # If failed sms or email notice has no recipient patron then skip to next failed
65
            # notice
66
            next unless $failed_notice->borrowernumber;
67
68
            # Find the patron recipient of the failed SMS or email notice.
69
            my $patron  = Koha::Patrons->find( $failed_notice->borrowernumber );
70
71
            # Check if patron of failed SMS or email notice is already restricted due to having
72
            # this happen before. If they are already restricted due to having invalid SMS or
73
            # email address don't apply a new restriction (debarment) to their account.
74
            if ( @{ Koha::Patron::Debarments::GetDebarments({ borrowernumber => $patron->borrowernumber, comment  => 'SMS number invalid' }) } ) {
75
                say "Patron " . $patron->borrowernumber . ":" . " " . $patron->firstname . " " . $patron->surname . " " . "is currently restricted due to having an invalid SMS number. No new restriction applied" if $verbose;
76
                next;
77
            } elsif ( @{ Koha::Patron::Debarments::GetDebarments({ borrowernumber => $patron->borrowernumber, comment  => 'Email address invalid' }) }) {
78
                say "Patron " . $patron->borrowernumber . ":" . " " . $patron->firstname . " " . $patron->surname . " " . "is currently restricted due to having an invalid email address. No new restriction applied" if $verbose;
79
                next;
80
            }
81
            if ($confirm) {
82
                # Patron has not been previously restricted for having failed SMS
83
                # or email addresses apply a restriction now.
84
                say "Applying restriction to patron " . $patron->borrowernumber . ":" . " " . $patron->firstname . " " . $patron->surname if $verbose;
85
                $failed_notice->restrict_patron_when_notice_fails;
86
            }
87
        }
88
   } else {
89
        say "There are no failed SMS or email notices" if $verbose;
90
   }
91
}
92
93
exit(0);
94
95
__END__
96
97
=head1 NAME
98
99
restrict_patrons_with_failed_notices.pl
100
101
=head1 SYNOPSIS
102
103
./restrict_patrons_with_failed_notices.pl -h
104
105
Use this script to creates a debarment for all patrons with failed SMS and email notices.
106
107
The 'RestrictPatronsWithFailedNotices' syspref must be enabled for this script to place restrictions to patrons accounts.
108
109
=head1 OPTIONS
110
111
=over 8
112
113
=item B<-h|--help>
114
115
Prints this help message
116
117
=item B<-v|--verbose>
118
119
Set the verbose flag
120
121
=item B<-c|--confirm>
122
123
The script will alter the database placing a restriction on patrons with failed SMS and email notices.
124
125
=back
126
127
=head1 AUTHOR
128
129
Alex Buckley <alexbuckley@catalyst.net.nz>
130
131
=head1 COPYRIGHT
132
133
Copyright 2019 Catalyst IT
134
135
=head1 LICENSE
136
137
This file is part of Koha.
138
139
Koha is free software; you can redistribute it and/or modify it
140
under the terms of the GNU General Public License as published by
141
the Free Software Foundation; either version 3 of the License, or
142
(at your option) any later version.
143
144
Koha is distributed in the hope that it will be useful, but
145
WITHOUT ANY WARRANTY; without even the implied warranty of
146
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
147
GNU General Public License for more details.
148
149
You should have received a copy of the GNU General Public License
150
along with Koha; if not, see <http://www.gnu.org/licenses>.
151
152
=cut
(-)a/t/db_dependent/Koha/Notices.t (-3 / +88 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 3;
22
use Test::More tests => 8;
23
23
24
use Koha::Notice::Templates;
24
use Koha::Notice::Templates;
25
use Koha::Database;
25
use Koha::Database;
Lines 66-70 $retrieved_template->delete; Link Here
66
is( Koha::Notice::Templates->search->count,
66
is( Koha::Notice::Templates->search->count,
67
    $nb_of_templates, 'Delete should have deleted the template' );
67
    $nb_of_templates, 'Delete should have deleted the template' );
68
68
69
$schema->storage->txn_rollback;
69
## Tests for Koha::Notice::Messages->get_failed_notices
70
71
# Remove all existing messages in the message_queue
72
Koha::Notice::Messages->delete;
73
74
# Make a patron
75
my $patron_category = $builder->build({ source => 'Category' })->{categorycode};
76
my $borrowernumber = Koha::Patron->new({
77
   firstname    => 'Jane',
78
   surname      => 'Smith',
79
   categorycode => $patron_category,
80
   branchcode   => $library->{branchcode},
81
   smsalertnumber => '123',
82
})->store->borrowernumber;
83
84
# With all notices removed from the message_queue table confirm get_failed_notices() returns 0
85
my @failed_notices = Koha::Notice::Messages->get_failed_notices();
86
is( @failed_notices, 0, 'No failed notices currently exist');
87
88
# Add a failed notice to the message_queue table
89
my $message = Koha::Notice::Message->new({
90
    borrowernumber => $borrowernumber,
91
    subject => 'subject',
92
    content => 'content',
93
    message_transport_type => 'sms',
94
    status => 'failed',
95
    letter_code => 'just_a_code',
96
    time_queued => \"NOW()",
97
})->store;
98
99
# With one failed notice in the message_queue table confirm get_failed_notices() returns 1
100
my @failed_notices2 = Koha::Notice::Messages->get_failed_notices();
101
is( @failed_notices2, 1, 'One failed notice currently exists');
102
103
# Change failed notice status to 'pending'
104
$message->update({ status => 'pending' });
105
106
# With the 1 failed notice in the message_queue table marked 'pending' confirm get_failed_notices() returns 0
107
my @failed_notices3 = Koha::Notice::Messages->get_failed_notices();
108
is( @failed_notices3, 0, 'No failed notices currently existing, now the notice has been marked pending');
109
110
111
## Tests for Koha::Notice::Message::restrict_patron_when_notice_fails
112
113
# Empty the borrower_debarments table
114
my $dbh = C4::Context->dbh;
115
$dbh->do(q|DELETE FROM borrower_debarments|);
70
116
71
- 
117
# Change the status of the notice back to 'failed'
118
$message->update({ status => 'failed' });
119
120
my @failed_notices4 = Koha::Notice::Messages->get_failed_notices();
121
122
# There should be one failed notice
123
if (@failed_notices4) {
124
    # Restrict the borrower who has the failed notice
125
    foreach my $failed_notice (@failed_notices4) {
126
        if ($failed_notice->message_transport_type eq 'sms' || $failed_notice->message_transport_type eq 'email') {
127
            $failed_notice->restrict_patron_when_notice_fails;
128
        }
129
    }
130
}
131
132
# Confirm that the restrict_patron_when_notice_fails() has added a restriction to the patron
133
is(@{ Koha::Patron::Debarments::GetDebarments({ borrowernumber => $borrowernumber, comment  => 'SMS number invalid' })}, 1, "Patron has a restriction placed on them");
134
135
# Restrict the borrower who has the failed notice
136
foreach my $failed_notice (@failed_notices4) {
137
    if ($failed_notice->message_transport_type eq 'sms' || $failed_notice->message_transport_type eq 'email') {
138
139
        # If the borrower already has a debarment for failed SMS or email notice then don't apply
140
        # a new debarment to their account
141
        if ( @{ Koha::Patron::Debarments::GetDebarments({ borrowernumber => $borrowernumber, comment  => 'SMS number invalid' }) } ) {
142
            next;
143
        } elsif ( @{ Koha::Patron::Debarments::GetDebarments({ borrowernumber => $borrowernumber, comment  => 'Email address invalid' }) }) {
144
            next;
145
        }
146
147
        # Place the debarment if the borrower doesn't already have one for failed SMS or email
148
        # notice
149
        $failed_notice->restrict_patron_when_notice_fails;
150
    }
151
}
152
153
# Confirm that no new debarment is added to the borrower
154
is(@{ Koha::Patron::Debarments::GetDebarments({ borrowernumber => $borrowernumber, comment  => 'SMS number invalid' })}, 1, "No new restriction has been placed on the patron");
155
156
$schema->storage->txn_rollback;

Return to bug 23295