Mail-DMARC
view release on metacpan or search on metacpan
lib/Mail/DMARC/Report/Store/SQL.pm view on Meta::CPAN
sub _negate_arg( $self, $val ) {
if ( substr( $val, 0, 1 ) eq '!' ) {
return ( '!=', substr( $val, 1 ) );
}
return ( '=', $val );
}
sub next_todo($self) {
if ( !exists $self->{_todo_list} ) {
$self->{_todo_list}
= $self->query( $self->grammar->select_todo_query, [ $self->time ] );
return if !$self->{_todo_list};
}
my $next_todo = shift @{ $self->{_todo_list} };
if ( !$next_todo ) {
delete $self->{_todo_list};
return;
}
my $agg = Mail::DMARC::Report::Aggregate->new();
$self->populate_agg_metadata( \$agg, \$next_todo );
my $pp = $self->get_report_policy_published( $next_todo->{rid} );
$pp->{domain} = $next_todo->{from_domain};
$agg->policy_published( Mail::DMARC::Policy->new(%$pp) );
$self->populate_agg_records( \$agg, $next_todo->{rid} );
return $agg;
}
sub retrieve_todo( $self, @args ) {
# this method extracts the data from the SQL tables and populates a
# list of Aggregate report objects with them.
my $reports
= $self->query( $self->grammar->select_todo_query, [ $self->time ] );
my @reports_todo;
return \@reports_todo if !@$reports;
foreach my $report ( @{$reports} ) {
my $agg = Mail::DMARC::Report::Aggregate->new();
$self->populate_agg_metadata( \$agg, \$report );
my $pp = $self->get_report_policy_published( $report->{rid} );
$pp->{domain} = $report->{from_domain};
$agg->policy_published( Mail::DMARC::Policy->new(%$pp) );
$self->populate_agg_records( \$agg, $report->{rid} );
push @reports_todo, $agg;
}
return \@reports_todo;
}
sub delete_report( $self, $report_id = undef ) {
$report_id or croak "missing report ID";
print "deleting report $report_id\n" if $self->verbose;
# deletes with FK don't cascade in SQLite? Clean each table manually
my $rows = $self->query( $self->grammar->report_record_id, [$report_id] );
my @row_ids = map { $_->{id} } @$rows;
if (@row_ids) {
foreach my $table (
qw/ report_record_spf report_record_dkim report_record_reason /)
{
print "deleting $table rows " . join( ',', @row_ids ) . "\n"
if $self->verbose;
eval {
$self->query( $self->grammar->delete_from_where_record_in($table),
\@row_ids );
};
# warn $@ if $@;
}
}
foreach my $table (qw/ report_policy_published report_record report_error /) {
print "deleting $table rows for report $report_id\n" if $self->verbose;
eval {
$self->query( $self->grammar->delete_from_where_report($table),
[$report_id] );
};
# warn $@ if $@;
}
# In MySQL, where FK constraints DO cascade, this is the only query needed
$self->query( $self->grammar->delete_report, [$report_id] );
return 1;
}
sub get_domain_id( $self, $domain ) {
croak "missing domain calling " . ( caller(0) )[3] if !$domain;
my $r = $self->query( $self->grammar->select_domain_id, [$domain] );
if ( $r && @$r ) {
return $r->[0]{id};
}
return $self->query( $self->grammar->insert_domain, [$domain] );
}
sub get_author_id( $self, $meta ) {
croak "missing author name" if !$meta->org_name;
my $r = $self->query( $self->grammar->select_author_id, [ $meta->org_name ] );
if ( $r && @$r ) {
return $r->[0]{id};
}
carp "missing email" if !$meta->email;
return $self->query( $self->grammar->insert_author,
[ $meta->org_name, $meta->email, $meta->extra_contact_info ] );
}
sub get_report_id( $self, $aggr ) {
my $meta = $aggr->metadata;
my $pol = $aggr->policy_published;
# check if report exists
my $author_id = $self->get_author_id($meta) or croak;
my $from_dom_id = $self->get_domain_id( $pol->domain ) or croak;
my $ids;
if ( $meta->report_id ) {
# reports arriving via the wire will have an author ID & report ID
$ids = $self->query( $self->grammar->select_report_id,
[ $meta->report_id, $author_id ] );
}
else {
# Reports submitted by our local MTA will not have a report ID
# They aggregate on the From domain, where the DMARC policy was discovered
$ids = $self->query(
$self->grammar->select_id_with_end,
[ $from_dom_id, $self->time, $author_id ]
);
}
if (@$ids) { # report already exists
return $self->{report_id} = $ids->[0]{id};
}
my $rid = $self->{report_id} = $self->query( $self->grammar->insert_report,
[ $from_dom_id, $meta->begin, $meta->end, $author_id, $meta->uuid ] )
or return;
$self->insert_policy_published( $rid, $pol );
return $rid;
}
( run in 3.115 seconds using v1.01-cache-2.11-cpan-df04353d9ac )