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

(-)a/Koha/Notice/Message.pm (+36 lines)
Lines 18-23 package Koha::Notice::Message; Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Koha::Database;
20
use Koha::Database;
21
use Koha::Patron::Debarments qw( AddDebarment );
21
22
22
use base qw(Koha::Object);
23
use base qw(Koha::Object);
23
24
Lines 62-68 sub html_content { Link Here
62
  </body>
63
  </body>
63
</html>
64
</html>
64
EOS
65
EOS
66
}
67
68
69
=head3 restrict_patron_when_notice_fails
70
71
    $failed_notice->restrict_patron_when_notice_fails;
72
73
Places a restriction (debarment) on patrons with failed SMS and email notices.
74
75
=cut
76
77
sub restrict_patron_when_notice_fails {
78
    my ($self) = @_;
65
79
80
    # Set the appropriate restriction (debarment) comment depending if the failed
81
    # message is a SMS or email notice. If the failed notice is neither then
82
    # return without placing a restriction
83
    my $comment;
84
    if ( $self->message_transport_type eq 'email' ) {
85
        $comment = 'Email address invalid';
86
    } elsif ( $self->message_transport_type eq 'sms' ) {
87
        $comment = 'SMS number invalid';
88
    } else {
89
        return;
90
    }
91
92
    AddDebarment(
93
        {
94
            borrowernumber => $self->borrowernumber,
95
            type           => 'SUSPENSION',
96
            comment        => $comment,
97
            expiration     => undef,
98
        }
99
    );
100
101
    return $self;
66
}
102
}
67
103
68
=head3 type
104
=head3 type
(-)a/Koha/Notice/Messages.pm (-1 / +21 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
        {
51
            time_queued => { -between => \"DATE_SUB(NOW(), INTERVAL $days DAY) AND NOW()" },
52
            status      => "failed",
53
        }
54
    );
55
}
56
37
=head3 type
57
=head3 type
38
58
39
=cut
59
=cut
(-)a/installer/data/mysql/atomicupdate/bug_23295-add_RestrictPatronsWithFailedNotices_syspref.pl (+17 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number  => "23295",
5
    description => "Automatically debar patrons if SMS or email notice fail",
6
    up          => sub {
7
        my ($args) = @_;
8
        my ( $dbh, $out ) = @$args{qw(dbh out)};
9
10
        $dbh->do(
11
            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') }
12
        );
13
14
        say $out "Added system preference 'RestrictPatronsWithFailedNotices'";
15
    },
16
};
17
(-)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 388-393 Patrons: Link Here
388
               1: "must have"
388
               1: "must have"
389
               0: "doesn't need"
389
               0: "doesn't need"
390
         - a guarantor when adding the patron.
390
         - a guarantor when adding the patron.
391
     -
392
         - pref: RestrictPatronsWithFailedNotices
393
           choices:
394
               1: Apply
395
               0: "Don't apply"
396
         - "a restriction to a patron when their email and SMS messages fail to send at the Koha level."
397
         - "<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."
391
398
392
    Privacy:
399
    Privacy:
393
     -
400
     -
(-)a/misc/cronjobs/restrict_patrons_with_failed_notices.pl (+168 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
62
                unless ( $failed_notice->message_transport_type eq 'sms'
63
                || $failed_notice->message_transport_type eq 'email' );
64
65
            # If failed sms or email notice has no recipient patron then skip to next failed
66
            # notice
67
            next unless $failed_notice->borrowernumber;
68
69
            # Find the patron recipient of the failed SMS or email notice.
70
            my $patron = Koha::Patrons->find( $failed_notice->borrowernumber );
71
72
            # Check if patron of failed SMS or email notice is already restricted due to having
73
            # this happen before. If they are already restricted due to having invalid SMS or
74
            # email address don't apply a new restriction (debarment) to their account.
75
            if ( $patron->restrictions->search( { comment => 'SMS number invalid' } )->count > 0 ) {
76
                say "Patron "
77
                    . $patron->borrowernumber . ":" . " "
78
                    . $patron->firstname . " "
79
                    . $patron->surname . " "
80
                    . "is currently restricted due to having an invalid SMS number. No new restriction applied"
81
                    if $verbose;
82
                next;
83
            } elsif ( $patron->restrictions->search( { comment => 'Email address invalid' } )->count > 0 ) {
84
                say "Patron "
85
                    . $patron->borrowernumber . ":" . " "
86
                    . $patron->firstname . " "
87
                    . $patron->surname . " "
88
                    . "is currently restricted due to having an invalid email address. No new restriction applied"
89
                    if $verbose;
90
                next;
91
            }
92
            if ($confirm) {
93
94
                # Patron has not been previously restricted for having failed SMS
95
                # or email addresses apply a restriction now.
96
                say "Applying restriction to patron "
97
                    . $patron->borrowernumber . ":" . " "
98
                    . $patron->firstname . " "
99
                    . $patron->surname
100
                    if $verbose;
101
                $failed_notice->restrict_patron_when_notice_fails;
102
            }
103
        }
104
    } else {
105
        say "There are no failed SMS or email notices" if $verbose;
106
    }
107
}
108
109
exit(0);
110
111
__END__
112
113
=head1 NAME
114
115
restrict_patrons_with_failed_notices.pl
116
117
=head1 SYNOPSIS
118
119
./restrict_patrons_with_failed_notices.pl -h
120
121
Use this script to creates a debarment for all patrons with failed SMS and email notices.
122
123
The 'RestrictPatronsWithFailedNotices' syspref must be enabled for this script to place restrictions to patrons accounts.
124
125
=head1 OPTIONS
126
127
=over 8
128
129
=item B<-h|--help>
130
131
Prints this help message
132
133
=item B<-v|--verbose>
134
135
Set the verbose flag
136
137
=item B<-c|--confirm>
138
139
The script will alter the database placing a restriction on patrons with failed SMS and email notices.
140
141
=back
142
143
=head1 AUTHOR
144
145
Alex Buckley <alexbuckley@catalyst.net.nz>
146
147
=head1 COPYRIGHT
148
149
Copyright 2019 Catalyst IT
150
151
=head1 LICENSE
152
153
This file is part of Koha.
154
155
Koha is free software; you can redistribute it and/or modify it
156
under the terms of the GNU General Public License as published by
157
the Free Software Foundation; either version 3 of the License, or
158
(at your option) any later version.
159
160
Koha is distributed in the hope that it will be useful, but
161
WITHOUT ANY WARRANTY; without even the implied warranty of
162
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
163
GNU General Public License for more details.
164
165
You should have received a copy of the GNU General Public License
166
along with Koha; if not, see <http://www.gnu.org/licenses>.
167
168
=cut
(-)a/t/db_dependent/Koha/Notices.t (-3 / +99 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
    {
79
        firstname      => 'Jane',
80
        surname        => 'Smith',
81
        categorycode   => $patron_category,
82
        branchcode     => $library->{branchcode},
83
        smsalertnumber => '123',
84
    }
85
)->store;
86
my $borrowernumber = $patron->borrowernumber;
87
88
# With all notices removed from the message_queue table confirm get_failed_notices() returns 0
89
my @failed_notices = Koha::Notice::Messages->get_failed_notices->as_list;
90
is( @failed_notices, 0, 'No failed notices currently exist' );
91
92
# Add a failed notice to the message_queue table
93
my $message = Koha::Notice::Message->new(
94
    {
95
        borrowernumber         => $borrowernumber,
96
        subject                => 'subject',
97
        content                => 'content',
98
        message_transport_type => 'sms',
99
        status                 => 'failed',
100
        letter_code            => 'just_a_code',
101
        time_queued            => \"NOW()",
102
    }
103
)->store;
104
105
# With one failed notice in the message_queue table confirm get_failed_notices() returns 1
106
my @failed_notices2 = Koha::Notice::Messages->get_failed_notices->as_list;
107
is( @failed_notices2, 1, 'One failed notice currently exists' );
108
109
# Change failed notice status to 'pending'
110
$message->update( { status => 'pending' } );
111
112
# With the 1 failed notice in the message_queue table marked 'pending' confirm get_failed_notices() returns 0
113
my @failed_notices3 = Koha::Notice::Messages->get_failed_notices->as_list;
114
is( @failed_notices3, 0, 'No failed notices currently existing, now the notice has been marked pending' );
115
116
## Tests for Koha::Notice::Message::restrict_patron_when_notice_fails
117
118
# Empty the borrower_debarments table
119
my $dbh = C4::Context->dbh;
120
$dbh->do(q|DELETE FROM borrower_debarments|);
121
122
# Change the status of the notice back to 'failed'
123
$message->update( { status => 'failed' } );
124
125
my @failed_notices4 = Koha::Notice::Messages->get_failed_notices->as_list;
126
127
# There should be one failed notice
128
if (@failed_notices4) {
129
130
    # Restrict the borrower who has the failed notice
131
    foreach my $failed_notice (@failed_notices4) {
132
        if ( $failed_notice->message_transport_type eq 'sms' || $failed_notice->message_transport_type eq 'email' ) {
133
            $failed_notice->restrict_patron_when_notice_fails;
134
        }
135
    }
136
}
137
138
# Confirm that the restrict_patron_when_notice_fails() has added a restriction to the patron
139
is(
140
    $patron->restrictions->search( { comment => 'SMS number invalid' } )->count, 1,
141
    "Patron has a restriction placed on them"
142
);
143
144
# Restrict the borrower who has the failed notice
145
foreach my $failed_notice (@failed_notices4) {
146
    if ( $failed_notice->message_transport_type eq 'sms' || $failed_notice->message_transport_type eq 'email' ) {
147
148
        # If the borrower already has a debarment for failed SMS or email notice then don't apply
149
        # a new debarment to their account
150
        if ( $patron->restrictions->search( { comment => 'SMS number invalid' } )->count > 0 ) {
151
            next;
152
        } elsif ( $patron->restrictions->search( { comment => 'Email address invalid' } )->count > 0 ) {
153
            next;
154
        }
155
156
        # Place the debarment if the borrower doesn't already have one for failed SMS or email
157
        # notice
158
        $failed_notice->restrict_patron_when_notice_fails;
159
    }
160
}
161
162
# Confirm that no new debarment is added to the borrower
163
is(
164
    $patron->restrictions->search( { comment => 'SMS number invalid' } )->count, 1,
165
    "No new restriction has been placed on the patron"
166
);
167
70
subtest 'find_effective_template' => sub {
168
subtest 'find_effective_template' => sub {
71
    plan tests => 7;
169
    plan tests => 7;
72
170
Lines 135-138 subtest 'find_effective_template' => sub { Link Here
135
};
233
};
136
234
137
$schema->storage->txn_rollback;
235
$schema->storage->txn_rollback;
138
139
- 

Return to bug 23295