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

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

Return to bug 23295