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

(-)a/Koha/Notice/Util.pm (-19 / +54 lines)
Lines 48-76 sub load_domain_limits { Link Here
48
                ? [ $entry->{domain} ]
48
                ? [ $entry->{domain} ]
49
                : $entry->{domain};
49
                : $entry->{domain};
50
            # Convert to hash structure by domain name
50
            # Convert to hash structure by domain name
51
            $domain_limits = { map { lc $_->{name}, { limit => $_->{limit}, unit => $_->{unit}, count => 0 }} @$domain_limits };
51
            $domain_limits = { map { _init_domain_entry($_); } @$domain_limits };
52
        }
52
        }
53
    }
53
    }
54
    return _fill_domain_counts($domain_limits);
54
    return $domain_limits;
55
}
56
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
61
62
    return if ref($config_entry) ne 'HASH' || !exists $config_entry->{name};
63
    my $elements;
64
    if( $config_entry->{belongs_to} ) {
65
        $elements = { belongs_to => lc $config_entry->{belongs_to} };
66
    } else {
67
        $elements = { limit => $config_entry->{limit}, unit => $config_entry->{unit}, count => undef };
68
    }
69
    return ( lc $config_entry->{name}, $elements );
55
}
70
}
56
71
57
=head2 exceeds_limit
72
=head2 exceeds_limit
58
73
59
    my $boolean = Koha::Notice::Util->exceeds_limit( $to_address, $domain_limits );
74
    my $boolean = Koha::Notice::Util->exceeds_limit({ to => $to_address, limits => $domain_limits, incr => 1|0 });
60
75
61
=cut
76
=cut
62
77
63
sub exceeds_limit {
78
sub exceeds_limit {
64
    my ( $class, $to_address, $domain_limits ) = @_;
79
    my ( $class, $params ) = @_;
65
    return 0 if !$domain_limits;
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
83
66
    my $domain = q{};
84
    my $domain = q{};
67
    $domain = lc $1 if $to_address && $to_address =~ /@(.*)/;
85
    $domain = lc $1 if $to_address && $to_address =~ /@(\H+)/;
68
    return 0 if !exists $domain_limits->{$domain};
86
    return 0 if !$domain || !exists $domain_limits->{$domain};
69
    return 1 if $domain_limits->{$domain}->{count} >= $domain_limits->{$domain}->{limit};
87
70
    $domain_limits->{$domain}->{count}++;
88
    # Keep in mind that domain may be part of group count
71
    warn "Sending messages: domain $domain reached limit of ".
89
    my $group = $domain_limits->{$domain}->{belongs_to} // $domain;
72
        $domain_limits->{$domain}->{limit}. '/'. $domain_limits->{$domain}->{unit}
90
    _get_domain_count( $domain, $group, $domain_limits ) if !defined $domain_limits->{$group}->{count};
73
        if $domain_limits->{$domain}->{count} == $domain_limits->{$domain}->{limit};
91
    return 1 if $domain_limits->{$group}->{count} >= $domain_limits->{$group}->{limit};
92
93
    if( $incr ) {
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};
98
    }
74
    return 0;
99
    return 0;
75
}
100
}
76
101
Lines 78-97 sub exceeds_limit { Link Here
78
103
79
=cut
104
=cut
80
105
81
sub _fill_domain_counts {
106
sub _get_domain_count {
82
    my ( $limits ) = @_;
107
    my ( $domain, $group, $limits ) = @_;
83
    return $limits if !$limits;
108
109
    # Check if there are group members too
110
    my @domains;
111
    push @domains, $domain if $domain eq $group;
112
    push @domains, map
113
    {
114
        my $belongs = $limits->{$_}->{belongs_to} // q{};
115
        $belongs eq $group ? $_ : ();
116
    } keys %$limits;
117
118
    my $sum = 0;
84
    my $dt_parser = Koha::Database->new->schema->storage->datetime_parser;
119
    my $dt_parser = Koha::Database->new->schema->storage->datetime_parser;
85
    foreach my $domain ( keys %$limits ) {
120
    my $start_dt = _convert_unit( undef, $limits->{$group}->{unit} );
86
        my $start_dt = _convert_unit( undef, $limits->{$domain}->{unit} );
121
    foreach my $domain ( @domains ) {
87
        $limits->{$domain}->{count} = Koha::Notice::Messages->search({
122
        $sum += Koha::Notice::Messages->search({
88
            message_transport_type => 'email',
123
            message_transport_type => 'email',
89
            status => 'sent',
124
            status => 'sent',
90
            to_address => { 'LIKE', '%'.$domain },
125
            to_address => { 'LIKE', '%'.$domain },
91
            updated_on => { '>=', $dt_parser->format_datetime($start_dt) }, # FIXME Would be nice if possible via filter_by_last_update
126
            updated_on => { '>=', $dt_parser->format_datetime($start_dt) }, # FIXME Would be nice if possible via filter_by_last_update
92
        })->count;
127
        })->count;
93
    }
128
    }
94
    return $limits;
129
    $limits->{$group}->{count} = $sum;
95
}
130
}
96
131
97
sub _convert_unit { # unit should be like \d+(m|h|d)
132
sub _convert_unit { # unit should be like \d+(m|h|d)
(-)a/t/db_dependent/Koha/Notice_Util.t (-19 / +41 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
#use Data::Dumper qw/Dumper/;
21
#use Data::Dumper qw/Dumper/;
22
use Test::More tests => 2;
22
use Test::More tests => 4;
23
use Test::MockModule;
23
use Test::MockModule;
24
use Test::Warn;
24
use Test::Warn;
25
25
Lines 37-43 $schema->storage->txn_begin; Link Here
37
my $builder = t::lib::TestBuilder->new;
37
my $builder = t::lib::TestBuilder->new;
38
38
39
subtest 'load_domain_limits' => sub {
39
subtest 'load_domain_limits' => sub {
40
    plan tests => 12;
40
    plan tests => 8;
41
41
42
    my $domain_limits;
42
    my $domain_limits;
43
    t::lib::Mocks::mock_config( 'message_domain_limits', undef );
43
    t::lib::Mocks::mock_config( 'message_domain_limits', undef );
Lines 55-77 subtest 'load_domain_limits' => sub { Link Here
55
    $domain_limits = Koha::Notice::Util->load_domain_limits;
55
    $domain_limits = Koha::Notice::Util->load_domain_limits;
56
    is( keys %$domain_limits, 2, 'koha-conf contains two domains' );
56
    is( keys %$domain_limits, 2, 'koha-conf contains two domains' );
57
    is( $domain_limits->{b}->{limit}, 3, 'check limit of second entry' );
57
    is( $domain_limits->{b}->{limit}, 3, 'check limit of second entry' );
58
    is( $domain_limits->{b}->{count}, undef, 'check if count still undefined' );
59
};
60
61
subtest 'counting in exceeds_limit' => sub {
62
    plan tests => 3;
58
63
64
    my $domain_limits;
59
    # Check counting
65
    # Check counting
60
    my @values = ( message_transport_type => 'email', status => 'sent' );
66
    my @values = ( message_transport_type => 'email', status => 'sent' );
61
    my $today = dt_from_string();
67
    my $today = dt_from_string();
68
    #FIXME Why are the three following build calls so slow?
62
    $builder->build_object({ class => 'Koha::Notice::Messages',
69
    $builder->build_object({ class => 'Koha::Notice::Messages',
63
        value => { @values, to_address => 'a@A', updated_on => $today->clone->subtract( hours => 36 ) }});
70
        value => { @values, to_address => 'a@A', updated_on => $today->clone->subtract( hours => 36 ) }});
64
    $builder->build_object({ class => 'Koha::Notice::Messages',
71
    $builder->build_object({ class => 'Koha::Notice::Messages',
65
        value => { @values, to_address => 'b@A', updated_on => $today->clone->subtract( hours => 49 ) }});
72
        value => { @values, to_address => 'b@A', updated_on => $today->clone->subtract( hours => 49 ) }});
66
    $builder->build_object({ class => 'Koha::Notice::Messages',
73
    $builder->build_object({ class => 'Koha::Notice::Messages',
67
        value => { @values, to_address => 'c@A', updated_on => $today->clone->subtract( days => 3 ) }});
74
        value => { @values, to_address => 'c@A', updated_on => $today->clone->subtract( days => 3 ) }});
68
    $domain_limits = Koha::Notice::Util->load_domain_limits;
75
69
    is( $domain_limits->{a}->{count}, 1, 'Three messages to A, 1 within unit of 2d' );
76
    $domain_limits = Koha::Notice::Util->load_domain_limits; # still using last mocked config A:2/2d
77
    Koha::Notice::Util->exceeds_limit({ to => '@A', limits => $domain_limits, incr => 0 }); # force counting
78
    is( $domain_limits->{a}->{count}, 1, '1 message to A within unit of 2d' );
70
    t::lib::Mocks::mock_config( 'message_domain_limits',
79
    t::lib::Mocks::mock_config( 'message_domain_limits',
71
        { domain => [ { name => 'A', limit => 2, unit => '50h' }, { name => 'B', limit => 3, unit => '3h' } ] },
80
        { domain => [ { name => 'A', limit => 2, unit => '50h' }, { name => 'B', limit => 3, unit => '3h' } ] },
72
    );
81
    );
73
    $domain_limits = Koha::Notice::Util->load_domain_limits;
82
    $domain_limits = Koha::Notice::Util->load_domain_limits;
74
    is( $domain_limits->{a}->{count}, 2, 'Three messages to A, 2 within unit of 50h' );
83
    Koha::Notice::Util->exceeds_limit({ to => 'x@A ', limits => $domain_limits, incr => 0 }); # force counting
84
    is( $domain_limits->{a}->{count}, 2, '2 messages to A within unit of 50h' );
85
    # Check count for B; if counted, there would be 0 or higher, otherwise undef
86
    ok( !defined $domain_limits->{b}->{count}, 'Prove that we did not count b if not asked for' );
87
};
88
89
subtest '_convert_unit' => sub {
90
    plan tests => 3;
75
91
76
    # Date subtraction - edge case (start of summer time)
92
    # Date subtraction - edge case (start of summer time)
77
    my $mock_context = Test::MockModule->new('C4::Context');
93
    my $mock_context = Test::MockModule->new('C4::Context');
Lines 84-109 subtest 'load_domain_limits' => sub { Link Here
84
    $mock_context->unmock('tz');
100
    $mock_context->unmock('tz');
85
};
101
};
86
102
87
subtest 'exceeds_limit' => sub {
103
subtest 'exceeds_limit with group domains' => sub {
88
    plan tests => 6;
104
    plan tests => 12;
89
105
90
    my $domain_limits;
106
    my $domain_limits;
91
92
    t::lib::Mocks::mock_config( 'message_domain_limits', undef );
107
    t::lib::Mocks::mock_config( 'message_domain_limits', undef );
93
    $domain_limits = Koha::Notice::Util->load_domain_limits;
108
    $domain_limits = Koha::Notice::Util->load_domain_limits;
94
    is( Koha::Notice::Util->exceeds_limit( 'marcel@koha.nl', $domain_limits ), 0, 'False when having no limits' );
109
    is( Koha::Notice::Util->exceeds_limit({ to => 'marcel@koha.nl', limits => $domain_limits }), 0, 'False when having no limits' );
95
110
96
    t::lib::Mocks::mock_config( 'message_domain_limits',
111
    t::lib::Mocks::mock_config( 'message_domain_limits', { domain => [
97
        { domain => [ { name => 'A', limit => 0, unit => '1d' }, { name => 'B', limit => 1, unit => '5h' } ] },
112
        { name => 'A', limit => 3, unit => '5m' },
98
    );
113
        { name => 'B', limit => 2, unit => '5m' },
114
        { name => 'C', belongs_to => 'A' },
115
    ]});
99
    $domain_limits = Koha::Notice::Util->load_domain_limits;
116
    $domain_limits = Koha::Notice::Util->load_domain_limits;
100
    is( Koha::Notice::Util->exceeds_limit( '1@A', $domain_limits ), 1, 'Limit for A already reached' );
101
    my $result;
117
    my $result;
102
    warning_like { $result = Koha::Notice::Util->exceeds_limit( '2@B', $domain_limits ) }
118
    is( Koha::Notice::Util->exceeds_limit({ to => '1@A', limits => $domain_limits }), 0, 'First message to A' );
103
        qr/Sending messages: domain b reached limit/, 'Check warn for reaching limit';
119
    is( Koha::Notice::Util->exceeds_limit({ to => '2@C', limits => $domain_limits }), 0, 'Second message to A (via C)' );
104
    is( $result, 0, 'Limit for B not yet exceeded' );
120
    ok( !exists $domain_limits->{c}->{count}, 'No count exists for grouped domain' );
105
    is( Koha::Notice::Util->exceeds_limit( '3@B', $domain_limits ), 1, 'Limit for B already reached' );
121
    warning_like { $result = Koha::Notice::Util->exceeds_limit({ to => '3@A', limits => $domain_limits }) }
106
    is( Koha::Notice::Util->exceeds_limit( '4@C', $domain_limits ), 0, 'No limits for C' );
122
        qr/Sending messages: domain a reached limit/, 'Check warn for reaching limit A';
123
    is( $result, 0, 'Limit for A reached, not exceeded' );
124
    is( Koha::Notice::Util->exceeds_limit({ to => '4@C', limits => $domain_limits }), 1, 'Limit for A exceeded (via C)' );
125
    is( Koha::Notice::Util->exceeds_limit({ to => '5@B', limits => $domain_limits }), 0, 'First message to B' );
126
    is( $domain_limits->{b}->{count}, 1, 'Count B updated' );
127
    is( Koha::Notice::Util->exceeds_limit({ to => '5@B', limits => $domain_limits, incr => 0 }), 0, 'Test incr flag' );
128
    is( $domain_limits->{b}->{count}, 1, 'Count B still 1' );
129
    is( Koha::Notice::Util->exceeds_limit({ to => '6@D', limits => $domain_limits }), 0, 'No limits for D' );
107
};
130
};
108
131
109
$schema->storage->txn_rollback;
132
$schema->storage->txn_rollback;
110
- 

Return to bug 33360