File Coverage

blib/lib/App/SpamcupNG/Summary.pm
Criterion Covered Total %
statement 75 75 100.0
branch 15 16 93.7
condition 4 6 66.6
subroutine 16 16 100.0
pod 6 6 100.0
total 116 119 97.4


line stmt bran cond sub pod time code
1             package App::SpamcupNG::Summary;
2 7     7   250587 use warnings;
  7         32  
  7         230  
3 7     7   38 use strict;
  7         13  
  7         160  
4 7     7   459 use parent qw(Class::Accessor);
  7         305  
  7         39  
5 7     7   18182 use Hash::Util 'lock_keys';
  7         5700  
  7         56  
6 7     7   496 use Carp 'confess';
  7         15  
  7         318  
7 7     7   3289 use Set::Tiny 0.04;
  7         9598  
  7         331  
8              
9 7     7   2984 use App::SpamcupNG::Summary::Receiver;
  7         16  
  7         37  
10              
11             our $VERSION = '0.016'; # VERSION
12              
13             =pod
14              
15             =head1 NAME
16              
17             App::SpamcupNG::Summary - class to summarise SPAM report data
18              
19             =head1 SYNOPSIS
20              
21             use App::SpamcupNG::Summary;
22             my $summary = App::SpamcupNG::Summary->new;
23             $summary->set_age(16);
24              
25             =head1 DESCRIPTION
26              
27             This class is used internally to store SPAM report data that can latter be
28             saved to generate reports.
29              
30             This class is also based on L<Class::Accessor> and uses
31             C<follow_best_practice>.
32              
33             =head1 ATTRIBUTES
34              
35             =over
36              
37             =item tracking_id: the SPAM report unique tracking ID.
38              
39             =item mailer: the e-mail header C<X-Mailer>, if available. Might be C<undef>.
40              
41             =item content_type: the e-mail header C<Content-Type>, if available. Might be C<undef>.
42              
43             =item age: the time elapsed since the SPAM e-mail was received.
44              
45             =item age_unit: the time elapsed unit since the SPAM e-mail was received.
46              
47             =item contacts: an array reference with the "best contacts" found in the report.
48              
49             =item receivers: an array reference with L<App::SpamcupNG::Summary::Receiver> instances.
50              
51             =back
52              
53             Sometimes the C<receivers> addresses will not real ones, but "counters" that
54             will not be used for the report, but only for Spamcop statistics.
55              
56             =cut
57              
58             __PACKAGE__->follow_best_practice;
59             my $fields = Set::Tiny->new(
60             (
61             'tracking_id', 'mailer', 'content_type', 'age',
62             'age_unit', 'contacts', 'receivers', 'charset'
63             )
64             );
65             my $ro_fields = Set::Tiny->new(qw(receivers));
66              
67             __PACKAGE__->mk_accessors( ( $fields->difference($ro_fields) )->members );
68             __PACKAGE__->mk_ro_accessors( $ro_fields->members );
69              
70             =head1 METHODS
71              
72             =head2 new
73              
74             Creates a new instance. No parameter is required or expected.
75              
76             =cut
77              
78             sub new {
79 3     3 1 310 my ( $class, $attribs_ref ) = @_;
80 3         34 my $self = {
81             tracking_id => undef,
82             mailer => undef,
83             content_type => undef,
84             age => undef,
85             age_unit => undef,
86             contacts => undef,
87             receivers => undef,
88             charset => undef
89             };
90 3         9 bless $self, $class;
91 3         8 lock_keys( %{$self} );
  3         39  
92 3         63 return $self;
93             }
94              
95             =head2 as_text
96              
97             Returns the summary attributes as strings, separated by commas.
98              
99             If some of attributes are C<undef>, the string C<not avaialable> will be used
100             instead.
101              
102             =cut
103              
104             sub as_text {
105 4     4 1 9 my $self = shift;
106 4         8 my @simple;
107              
108             # Set::Tiny->members is not ordered and we need that to have deterministic text
109 4         11 my @fields = sort( $fields->members );
110 4         52 my $complex = Set::Tiny->new(qw(contacts receivers age));
111              
112 4         40 foreach my $field (@fields) {
113 32 100       118 next if ( $complex->has( ($field) ) );
114 20         104 push( @simple, $field );
115             }
116              
117 4   66     9 my @dump = map { $_ . '=' . ( $self->{$_} || $self->na ) } @simple;
  20         57  
118              
119             # age can be zero
120 4 100       11 if ( defined( $self->{age} ) ) {
121 3         8 push( @dump, 'age=' . $self->{age} );
122             }
123             else {
124 1         2 push( @dump, 'age=' . $self->na );
125             }
126              
127 4         9 foreach my $key (qw(receivers contacts)) {
128 8 100       21 if ( $self->{$key} ) {
129              
130 6 100       15 if ( $key eq 'contacts' ) {
131             push( @dump,
132 3         8 ( "$key=(" . join( ';', @{ $self->{$key} } ) . ')' ) );
  3         8  
133 3         7 next;
134             }
135              
136 3         7 push( @dump, $self->_receivers_as_text );
137              
138             }
139             else {
140 2         5 push( @dump, "$key=()" );
141             }
142             }
143              
144 4         43 return join( ',', @dump );
145             }
146              
147             =head2 tracking_url
148              
149             Returns the tracking URL of the SPAM report as a string.
150              
151             =cut
152              
153             sub tracking_url {
154 1     1 1 321 my $self = shift;
155 1         7 return 'https://www.spamcop.net/sc?id=' . $self->{tracking_id};
156             }
157              
158             =head2 to_text
159              
160             Getter for attributes that returns the value as a string.
161              
162             If the attribute value is C<undef>, the string return by C<na()> will be used
163             instead.
164              
165             Expects as parameter the name of the parameter, returns a string.
166              
167             =cut
168              
169             sub _receivers_as_text {
170 5     5   11 my $self = shift;
171 5         9 my @receivers;
172              
173 5         8 foreach my $receiver ( @{ $self->{receivers} } ) {
  5         13  
174 9         29 push( @receivers, '(' . $receiver->as_text . ')' );
175             }
176              
177 5         25 return "receivers=(" . join( ';', @receivers ) . ')';
178             }
179              
180             sub _contacts_as_text {
181 2     2   4 my $self = shift;
182 1         8 return '(' . join( ';', @{ $self->{contacts} } ) . ')'
183 2 100       8 if ( $self->{contacts} );
184 1         7 return '()';
185             }
186              
187             sub to_text {
188 8     8 1 679 my ( $self, $attrib ) = @_;
189 8 100       38 return $self->_receivers_as_text if ( $attrib eq 'receivers' );
190 6 100       22 return $self->_contacts_as_text if ( $attrib eq 'contacts' );
191 4   66     25 return $self->{$attrib} || $self->na;
192             }
193              
194             =head2 na
195              
196             Returns the "not available" string. Can be used as class method.
197              
198             =cut
199              
200             sub na {
201 11     11 1 47 return 'not available';
202             }
203              
204             sub _fields {
205 2     2   1108 my @fields = sort( $fields->members );
206 2         36 return \@fields;
207             }
208              
209             =head2 set_receivers
210              
211             Setter for the C<receivers> attribute.
212              
213             Expects as parameter an array reference, with inner array references inside.
214              
215             Returns "true" (1) if everything goes fine.
216              
217             =cut
218              
219             sub set_receivers {
220 4     4 1 1322 my ( $self, $receivers_ref ) = @_;
221 4 50       24 confess 'An array reference is expected as parameter'
222             unless ( ref($receivers_ref) eq 'ARRAY' );
223 4         12 my @items;
224              
225 4         8 foreach my $receiver_ref ( @{$receivers_ref} ) {
  4         11  
226 8         60 push( @items, App::SpamcupNG::Summary::Receiver->new($receiver_ref) );
227             }
228              
229 4         22 $self->{receivers} = \@items;
230 4         23 return 1;
231             }
232              
233             =head1 SEE ALSO
234              
235             =over
236              
237             =item *
238              
239             L<Class::Accessor>
240              
241             =back
242              
243             =head1 AUTHOR
244              
245             Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>
246              
247             =head1 COPYRIGHT AND LICENSE
248              
249             This software is copyright (c) 2018 of Alceu Rodrigues de Freitas Junior,
250             E<lt>arfreitas@cpan.orgE<gt>
251              
252             This file is part of App-SpamcupNG distribution.
253              
254             App-SpamcupNG is free software: you can redistribute it and/or modify it under
255             the terms of the GNU General Public License as published by the Free Software
256             Foundation, either version 3 of the License, or (at your option) any later
257             version.
258              
259             App-SpamcupNG is distributed in the hope that it will be useful, but WITHOUT
260             ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
261             FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
262              
263             You should have received a copy of the GNU General Public License along with
264             App-SpamcupNG. If not, see <http://www.gnu.org/licenses/>.
265              
266             =cut
267              
268             1;