1 package Koha::Notice::Util;
3 # Copyright Rijksmuseum 2023
5 # This file is part of Koha.
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.
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.
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>.
21 use Data::Dumper qw/Dumper/;
24 use Koha::DateUtils qw/dt_from_string/;
25 use Koha::Notice::Messages;
29 Koha::Notice::Util - Utility class related to Koha notice messages
33 =head2 load_domain_limits
35 my $domain_limits = Koha::Notice::Util->load_domain_limits;
39 sub load_domain_limits {
43 my $entry = C4::Context->config('message_domain_limits');
44 if( ref($entry) eq 'HASH' ) {
45 if( exists $entry->{domain} ) {
46 # Turn single hash entry into array
47 $domain_limits = ref($entry->{domain}) eq 'HASH'
48 ? [ $entry->{domain} ]
50 # Convert to hash structure by domain name
51 $domain_limits = { map { _init_domain_entry($_); } @$domain_limits };
54 return $domain_limits;
57 sub _init_domain_entry {
58 my ( $config_entry ) = @_;
59 # Return either a hash like ( name => { limit => , unit =>, count => } ) for regular entries
60 # or return a hash like ( name => { belongs_to => } ) for a domain that is part of a group
62 return if ref($config_entry) ne 'HASH' || !exists $config_entry->{name};
64 if( $config_entry->{belongs_to} ) {
65 $elements = { belongs_to => lc $config_entry->{belongs_to} };
67 $elements = { limit => $config_entry->{limit}, unit => $config_entry->{unit}, count => undef };
69 return ( lc $config_entry->{name}, $elements );
74 my $boolean = Koha::Notice::Util->exceeds_limit({ to => $to_address, limits => $domain_limits, incr => 1|0 });
79 my ( $class, $params ) = @_;
80 my $domain_limits = $params->{limits} or return 0; # no limits at all
81 my $to_address = $params->{to} or return 0; # no address, no limit exceeded
82 my $incr = $params->{incr} // 1; # by default we increment
85 $domain = lc $1 if $to_address && $to_address =~ /@(\H+)/;
86 return 0 if !$domain || !exists $domain_limits->{$domain};
88 # Keep in mind that domain may be part of group count
89 my $group = $domain_limits->{$domain}->{belongs_to} // $domain;
90 _get_domain_count( $domain, $group, $domain_limits ) if !defined $domain_limits->{$group}->{count};
91 return 1 if $domain_limits->{$group}->{count} >= $domain_limits->{$group}->{limit};
94 $domain_limits->{$group}->{count}++;
95 warn "Sending messages: domain $group reached limit of ".
96 $domain_limits->{$group}->{limit}. '/'. $domain_limits->{$group}->{unit}
97 if $domain_limits->{$group}->{count} == $domain_limits->{$group}->{limit};
102 =head1 PRIVATE METHODS
106 sub _get_domain_count {
107 my ( $domain, $group, $limits ) = @_;
109 # Check if there are group members too
111 push @domains, $domain if $domain eq $group;
114 my $belongs = $limits->{$_}->{belongs_to} // q{};
115 $belongs eq $group ? $_ : ();
119 my $start_dt = _convert_unit( undef, $limits->{$group}->{unit} );
120 foreach my $domain ( @domains ) {
121 $sum += Koha::Notice::Messages->search(
123 message_transport_type => 'email',
125 to_address => { 'LIKE', '%' . $domain },
127 )->filter_by_last_update( { timestamp_column_name => 'updated_on', from => $start_dt } )->count;
129 $limits->{$group}->{count} = $sum;
132 sub _convert_unit { # unit should be like \d+(m|h|d)
133 my ( $dt, $unit ) = @_;
134 $dt //= dt_from_string();
135 if( $unit && $unit =~ /(\d+)([mhd])/ ) {
136 my $abbrev = { m => 'minutes', h => 'hours', d => 'days' };
137 foreach my $h ( 0, 1 ) { # try hour before too when subtract fails (like: change to summertime)
138 eval { $dt->subtract( hours => $h )->subtract( $abbrev->{$2} => $1 ) } and last;