File Coverage

blib/lib/Mail/MtPolicyd/Plugin/Quota.pm
Criterion Covered Total %
statement 41 49 83.6
branch 6 12 50.0
condition 2 6 33.3
subroutine 8 8 100.0
pod 1 4 25.0
total 58 79 73.4


line stmt bran cond sub pod time code
1             package Mail::MtPolicyd::Plugin::Quota;
2              
3 2     2   2375 use Moose;
  2         5  
  2         16  
4 2     2   13533 use namespace::autoclean;
  2         6  
  2         25  
5              
6             our $VERSION = '1.23'; # VERSION
7             # ABSTRACT: mtpolicyd plugin for accounting in sql tables
8              
9             extends 'Mail::MtPolicyd::Plugin';
10             with 'Mail::MtPolicyd::Plugin::Role::UserConfig' => {
11             'uc_attributes' => [
12             'enabled', 'field', 'threshold', 'action', 'metric'
13             ],
14             };
15             with 'Mail::MtPolicyd::Plugin::Role::SqlUtils';
16             with 'Mail::MtPolicyd::Plugin::Role::PluginChain';
17              
18 2     2   278 use Mail::MtPolicyd::Plugin::Result;
  2         5  
  2         51  
19 2     2   943 use Time::Piece;
  2         10680  
  2         23  
20              
21              
22             has 'enabled' => ( is => 'rw', isa => 'Str', default => 'on' );
23              
24             has 'field' => ( is => 'rw', isa => 'Str', required => 1);
25             has 'metric' => ( is => 'rw', isa => 'Str', required => 1);
26             has 'time_pattern' => ( is => 'rw', isa => 'Str', default => '%Y-%m');
27             has 'threshold' => ( is => 'rw', isa => 'Int', required => 1);
28             has 'action' => ( is => 'rw', isa => 'Str', default => 'defer smtp traffic quota has been exceeded');
29              
30             sub get_timekey {
31 2     2 0 3 my $self = shift;
32 2         11 return Time::Piece->new->strftime( $self->time_pattern );
33             }
34              
35             has 'table_prefix' => ( is => 'rw', isa => 'Str', default => 'acct_');
36              
37             sub run {
38 2     2 1 70 my ( $self, $r ) = @_;
39 2         75 my $session = $r->session;
40              
41 2 50       9 if( $self->get_uc( $session, 'enabled') eq 'off' ) {
42 0         0 return;
43             }
44 2         15 my $field = $self->get_uc( $session, 'field');
45 2         8 my $metric = $self->get_uc( $session, 'metric');
46 2         10 my $action = $self->get_uc( $session, 'action');
47 2         9 my $threshold = $self->get_uc( $session, 'threshold');
48              
49 2         105 my $key = $r->attr( $field );
50 2 50 33     19 if( ! defined $key || $key =~ /^\s*$/ ) {
51 0         0 $self->log( $r, 'field '.$field.' is empty in request. skipping quota check.');
52 0         0 return;
53             }
54              
55 2         8 my $count = $self->get_accounting_count( $r,
56             $field, $metric, $key );
57              
58 2 100       8 if( $count >= $threshold ) {
59 1 50       5 if( defined $action ) {
60 1         53 return Mail::MtPolicyd::Plugin::Result->new(
61             action => $action,
62             abort => 1,
63             );
64             }
65 0 0       0 if( defined $self->chain ) {
66 0         0 my $chain_result = $self->chain->run( $r );
67 0         0 return( @{$chain_result->plugin_results} );
  0         0  
68             }
69             }
70              
71 1         7 return;
72             }
73              
74              
75             sub get_table_name {
76 2     2 0 5 my ( $self, $field ) = @_;
77 2         85 return( $self->table_prefix . $field );
78             }
79              
80             sub get_accounting_count {
81 2     2 0 6 my ( $self, $r, $field, $metric, $key ) = @_;
82 2         11 my $dbh = Mail::MtPolicyd::SqlConnection->instance->dbh;
83 2         59 my $where = {
84             'key' => $key,
85             'time' => $self->get_timekey,
86             };
87 2         71 my $table_name = $dbh->quote_identifier( $self->get_table_name($field) );
88             my $where_str = join(' AND ', map {
89 2         48 $dbh->quote_identifier($_).'='.$dbh->quote($where->{$_})
  4         73  
90             } keys %$where );
91 2         75 my $column_name = $dbh->quote_identifier( $metric );
92 2         51 my $sql = "SELECT $column_name FROM $table_name WHERE $where_str";
93              
94 2         20 my $count = $dbh->selectrow_array($sql);
95              
96 2 50 33     251 if( defined $count && $count =~ /^\d+$/ ) {
97 2         9 return $count;
98             }
99 0           return;
100             }
101              
102             __PACKAGE__->meta->make_immutable;
103              
104             1;
105              
106             __END__
107              
108             =pod
109              
110             =encoding UTF-8
111              
112             =head1 NAME
113              
114             Mail::MtPolicyd::Plugin::Quota - mtpolicyd plugin for accounting in sql tables
115              
116             =head1 VERSION
117              
118             version 1.23
119              
120             =head1 DESCRIPTION
121              
122             This plugin can be used to do accounting based on request fields.
123              
124             =head1 Example
125              
126             <Plugin quota-clients>
127             module = "Quota"
128             table_prefix = "acct_"
129              
130             # per month
131             time_pattern = "%Y-%m"
132             # per ip
133             field = "client_address"
134             # allow 1000 mails
135             metric = "count"
136             threshold = 1000
137             action = "defer you exceeded your monthly limit, please insert coin"
138             </Plugin>
139              
140             =head1 Configuration
141              
142             =head2 Parameters
143              
144             The module takes the following parameters:
145              
146             =over
147              
148             =item (uc_)enabled (default: on)
149              
150             Enable/disable this check.
151              
152             =item (uc_)field (required)
153              
154             The field used for accounting/quota.
155              
156             =item (uc_)metric (required)
157              
158             The metric on which the quota should be based.
159              
160             The Accounting module stores the following metrics:
161              
162             =over
163              
164             =item count
165              
166             Number of mails recivied.
167              
168             =item count_rcpt
169              
170             Number of mails recivied multiplied with number of recipients.
171              
172             =item size
173              
174             Size of mails recivied.
175              
176             =item size_rcpt
177              
178             Size of mails recivied multiplied with number of recipients.
179              
180             =back
181              
182             =item time_pattern (default: "%Y-%m")
183              
184             A format string for building the time key used to store counters.
185              
186             Default is to build counters on a monthly base.
187              
188             For example use:
189              
190             * "%Y-%W" for weekly
191             * "%Y-%m-%d" for daily
192              
193             See "man date" for format string sequences.
194              
195             You must use the same time_pattern as used in for the Accounting module.
196              
197             =item threshold (required)
198              
199             The quota limit.
200              
201             =item action (default: defer smtp traffic quota has been exceeded)
202              
203             The action to return when the quota limit has been reached.
204              
205             =item table_prefix (default: "acct_")
206              
207             A prefix to add to every table.
208              
209             The table name will be the prefix + field_name.
210              
211             =back
212              
213             =head1 AUTHOR
214              
215             Markus Benning <ich@markusbenning.de>
216              
217             =head1 COPYRIGHT AND LICENSE
218              
219             This software is Copyright (c) 2014 by Markus Benning <ich@markusbenning.de>.
220              
221             This is free software, licensed under:
222              
223             The GNU General Public License, Version 2, June 1991
224              
225             =cut