Mail-MtPolicyd

 view release on metacpan or  search on metacpan

lib/Mail/MtPolicyd/Plugin/Accounting.pm  view on Meta::CPAN

package Mail::MtPolicyd::Plugin::Accounting;

use Moose;
use namespace::autoclean;

our $VERSION = '2.05'; # VERSION
# ABSTRACT: mtpolicyd plugin for accounting in sql tables

extends 'Mail::MtPolicyd::Plugin';
with 'Mail::MtPolicyd::Plugin::Role::UserConfig' => {
	'uc_attributes' => [ 'enabled' ],
};

use Mail::MtPolicyd::Plugin::Result;

use Time::Piece;


has 'enabled' => ( is => 'rw', isa => 'Str', default => 'on' );

has 'fields' => ( is => 'rw', isa => 'Str', required => 1);
has '_fields' => ( is => 'ro', isa => 'ArrayRef', lazy => 1,
    default => sub {
        my $self = shift;
        return [ split('\s*,\s*', $self->fields) ];
    },
);

has 'time_pattern' => ( is => 'rw', isa => 'Str', default => '%Y-%m');

with 'Mail::MtPolicyd::Role::Connection' => {
  name => 'db',
  type => 'Sql',
};
with 'Mail::MtPolicyd::Plugin::Role::SqlUtils';

sub get_timekey {
    my $self = shift;
    return Time::Piece->new->strftime( $self->time_pattern );
}

has 'table_prefix' => ( is => 'rw', isa => 'Str', default => 'acct_');

sub run {
	my ( $self, $r ) = @_;
	my $session = $r->session;

	if( $self->get_uc( $session, 'enabled') eq 'off' ) {
		return;
	}

    if( $r->is_already_done( $self->name.'-acct' ) ) {
        $self->log( $r, 'accounting already done for this mail, skipping...');
        return;
	}

    my $metrics = $self->get_request_metrics( $r );

    foreach my $field ( @{$self->_fields} ) {
        my $key = $r->attr($field);
        if( ! defined $key || $key =~ /^\s*$/ ) {
            $self->log( $r, $field.' not defined in request, skipping...');
            next;
        }
        $self->log( $r, 'updating accounting info for '.$field.' '.$key);
        $self->update_accounting($field, $key, $metrics);
    }

	return;
}

sub init {
    my $self = shift;
    $self->check_sql_tables( %{$self->_table_definitions} );
    return;
}

has '_single_table_create' => ( is => 'ro', isa => 'HashRef', lazy => 1,
    default => sub { {
        'mysql' => 'CREATE TABLE %TABLE_NAME% (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `key` VARCHAR(255) NOT NULL,
    `time` VARCHAR(255) NOT NULL,
    `count` INT UNSIGNED NOT NULL,
    `count_rcpt` INT UNSIGNED NOT NULL,
    `size` INT UNSIGNED NOT NULL,
    `size_rcpt` INT UNSIGNED NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `time_key` (`key`, `time`),
    KEY(`key`),
    KEY(`time`)
  ) ENGINE=%MYSQL_ENGINE%  DEFAULT CHARSET=latin1',
        'SQLite' => 'CREATE TABLE %TABLE_NAME% (
    `id` INTEGER PRIMARY KEY AUTOINCREMENT,
    `key` VARCHAR(255) NOT NULL,
    `time` VARCHAR(255) NOT NULL,
    `count` INT UNSIGNED NOT NULL,
    `count_rcpt` INT UNSIGNED NOT NULL,
    `size` INT UNSIGNED NOT NULL,
    `size_rcpt` INT UNSIGNED NOT NULL
)',
    } }
);

sub get_table_name {
    my ( $self, $field ) = @_;
    return( $self->table_prefix . $field );
}

has '_table_definitions' => ( is => 'ro', isa => 'HashRef', lazy => 1,
    default => sub {
        my $self = shift;
        my $tables = {};
        foreach my $field ( @{$self->_fields} ) {
            my $table_name = $self->get_table_name($field);
            $tables->{$table_name} = $self->_single_table_create;
        }
        return $tables;
    },
);

sub get_request_metrics {
    my ( $self, $r ) = @_;
    my $recipient_count = $r->attr('recipient_count');
    my $size = $r->attr('size');
    my $metrics = {};
	my $rcpt_cnt = defined $recipient_count ? $recipient_count : 1;
	$metrics->{'size'} = defined $size ? $size : 0;
    $metrics->{'count'} = 1;
    $metrics->{'count_rcpt'} = $rcpt_cnt ? $rcpt_cnt : 1;
    $metrics->{'size_rcpt'} = $rcpt_cnt ? $size * $rcpt_cnt : $size;

    return( $metrics );
}

sub update_accounting {
    my ( $self, $field, $key, $metrics ) = @_;

    eval {
        $self->update_accounting_row($field, $key, $metrics);
    };
    if( $@ =~ /^accounting row does not exist/ ) {
        $self->insert_accounting_row($field, $key, $metrics);
    } elsif( $@ ) {
        die( $@ );
    }

    return;
}

sub insert_accounting_row {
    my ( $self, $field, $key, $metrics ) = @_;
    my $dbh = $self->_db_handle;
    my $table_name = $dbh->quote_identifier( $self->get_table_name($field) );
    my $values = {
        'key' => $key,
        'time' => $self->get_timekey,
        %$metrics,
    };
    my $col_str = join(', ', map {
        $dbh->quote_identifier($_)
    } keys %$values);
    my $values_str = join(', ', map {
        $dbh->quote($_)
    } values %$values);

    my $sql = "INSERT INTO $table_name ($col_str) VALUES ($values_str)";
    $self->execute_sql($sql);

    return;



( run in 0.962 second using v1.01-cache-2.11-cpan-97f6503c9c8 )