]> git.proxmox.com Git - pmg-api.git/blobdiff - PMG/API2/Statistics.pm
add rbl count statistics API
[pmg-api.git] / PMG / API2 / Statistics.pm
index 500d824bf8581a77568f10360d5f40da09940957..3953aea1b2eff9b5c2981e7ef1571c82e643e606 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 use Data::Dumper;
 use JSON;
+use Time::Local;
 
 use PVE::Tools;
 use PVE::SafeSyslog;
@@ -14,6 +15,7 @@ use PMG::RESTEnvironment;
 use PVE::JSONSchema qw(get_standard_option);
 
 use PMG::Utils;
+use PMG::Config;
 use PMG::RuleDB;
 use PMG::Statistic;
 
@@ -41,13 +43,15 @@ __PACKAGE__->register_method ({
        my ($param) = @_;
 
        return [
+           { name => "contact" },
            { name => "domains" },
            { name => "mail" },
            { name => "mailcount" },
            { name => "maildistribution" },
            { name => "spamscores" },
            { name => "sender" },
-           { name => "senderdetails" },
+           { name => "rblcount" },
+           { name => "receiver" },
            { name => "virus" },
        ];
     }});
@@ -84,15 +88,250 @@ my $decode_orderby = sub {
     return $sorters;
 };
 
-my $orderby_param_desc = {
-    description => "Remote sorting (ExtJS compatible).",
-    type => 'string',
-    optional => 1,
-    maxLength => 4096,
+my $api_properties = {
+    orderby => {
+       description => "Remote sorting configuration(JSON, ExtJS compatible).",
+       type => 'string',
+       optional => 1,
+       maxLength => 4096,
+    },
+};
+
+my $default_properties = sub {
+    my ($prop) = @_;
+
+    $prop //= {};
+
+    $prop->{starttime} = get_standard_option('pmg-starttime');
+    $prop->{endtime} = get_standard_option('pmg-endtime');
+
+    $prop->{year} = {
+       description => "Year. Defaults to current year. You will get statistics for the whole year if you do not specify a month or day.",
+       type => 'integer',
+       minimum => 1900,
+       maximum => 3000,
+       optional => 1,
+    };
+
+    $prop->{month} = {
+       description => "Month. You will get statistics for the whole month if you do not specify a day.",
+       type => 'integer',
+       minimum => 1,
+       maximum => 12,
+       optional => 1,
+    };
+
+    $prop->{day} = {
+       description => "Day of month. Get statistics for a single day.",
+       type => 'integer',
+       minimum => 1,
+       maximum => 31,
+       optional => 1,
+    };
+
+    return $prop;
+};
+
+my $extract_start_end = sub {
+    my ($param) = @_;
+
+    my $has_ymd;
+    foreach my $k (qw(year month day)) {
+       if (defined($param->{$k})) {
+           $has_ymd = $k;
+           last;
+       }
+    }
+    my $has_se;
+    foreach my $k (qw(starttime endtime)) {
+       if (defined($param->{$k})) {
+           $has_se = $k;
+           last;
+       }
+    }
+
+    raise_param_exc({ $has_se => "parameter conflicts with parameter '$has_ymd'"})
+       if $has_se && $has_ymd;
+
+    my $start;
+    my $end;
+
+    if ($has_ymd) {
+       my (undef, undef, undef, undef, $month, $year) = localtime(time());
+       $month += 1;
+       $year = $param->{year} if defined($param->{year});
+       if (defined($param->{day})) {
+           $month = $param->{month} if defined($param->{month});
+           $start = timelocal(0, 0, 0, 1, $month - 1, $year);
+           $end = timelocal(0, 0, 0, 1, $month, $year);
+       } elsif (defined($param->{month})) {
+           my $month = $param->{month};
+           if ($month < 12) {
+               $start = timelocal(0, 0, 0, 1, $month - 1, $year);
+               $end = timelocal(0, 0, 0, 1, $month, $year);
+           } else {
+               $start = timelocal(0, 0, 0, 1, 11, $year);
+               $end = timelocal(0, 0, 0, 1, 0, $year + 1);
+           }
+       } else {
+           $start = timelocal(0, 0, 0, 1, 0, $year);
+           $end = timelocal(0, 0, 0, 1, 0, $year + 1);
+       }
+    } else {
+       $start = $param->{starttime} // (time - 86400);
+       $end = $param->{endtime} // ($start + 86400);
+    }
+
+    return ($start, $end);
 };
 
 my $userstat_limit = 2000; # hardcoded limit
 
+__PACKAGE__->register_method ({
+    name => 'contact',
+    path => 'contact',
+    method => 'GET',
+    description => "Contact Address Statistics.",
+    permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+    parameters => {
+       additionalProperties => 0,
+       properties => $default_properties->({
+           filter => {
+               description => "Contact address filter.",
+               type => 'string',
+               maxLength => 512,
+               optional => 1,
+           },
+           orderby => $api_properties->{orderby},
+       }),
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => "object",
+           properties => {
+               contact => {
+                   description => "Contact email.",
+                   type => 'string',
+               },
+               count => {
+                   description => "Mail count.",
+                   type => 'number',
+                   optional => 1,
+               },
+               bytes => {
+                   description => "Mail traffic (Bytes).",
+                   type => 'number',
+               },
+               viruscount => {
+                   description => "Number of sent virus mails.",
+                   type => 'number',
+                   optional => 1,
+               },
+           },
+       },
+       links => [ { rel => 'child', href => "{contact}" } ],
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       my ($start, $end) = $extract_start_end->($param);
+
+       my $cfg = PMG::Config->new();
+       my $advfilter = $cfg->get('admin', 'advfilter');
+
+       my $stat = PMG::Statistic->new($start, $end);
+       my $rdb = PMG::RuleDB->new();
+
+       my $sorters = [];
+       if ($param->{orderby}) {
+           my $props = ['contact', 'count', 'bytes', 'viruscount'];
+           $sorters = $decode_orderby->($param->{orderby}, $props);
+       }
+
+       my $res = $stat->user_stat_contact($rdb, $userstat_limit, $sorters, $param->{filter}, $advfilter);
+
+       return $res;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'contactdetails',
+    path => 'contact/{contact}',
+    method => 'GET',
+    description => "Detailed Contact Statistics.",
+    permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+    parameters => {
+       additionalProperties => 0,
+       properties => $default_properties->({
+           contact => get_standard_option('pmg-email-address', {
+               description => "Contact email address.",
+           }),
+           filter => {
+               description => "Sender address filter.",
+               type => 'string',
+               maxLength => 512,
+               optional => 1,
+           },
+           orderby => $api_properties->{orderby},
+       }),
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => "object",
+           properties => {
+               time => {
+                   description => "Receive time stamp",
+                   type => 'integer',
+               },
+               sender => {
+                   description => "Sender email.",
+                   type => 'string',
+               },
+               bytes => {
+                   description => "Mail traffic (Bytes).",
+                   type => 'number',
+               },
+               blocked => {
+                   description => "Mail was blocked.",
+                   type => 'boolean',
+               },
+               spamlevel => {
+                   description => "Spam score.",
+                   type => 'number',
+               },
+               virusinfo => {
+                   description => "Virus name.",
+                   type => 'string',
+                   optional => 1,
+               },
+           },
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       my ($start, $end) = $extract_start_end->($param);
+
+       my $stat = PMG::Statistic->new($start, $end);
+       my $rdb = PMG::RuleDB->new();
+
+       my $sorters = [];
+       if ($param->{orderby}) {
+           my $props = ['time', 'sender', 'bytes', 'blocked', 'spamlevel', 'virusinfo'];
+           $sorters = $decode_orderby->($param->{orderby}, $props);
+       }
+
+       return $stat->user_stat_contact_details(
+           $rdb, $param->{contact}, $userstat_limit, $sorters, $param->{filter});
+    }});
+
 __PACKAGE__->register_method ({
     name => 'sender',
     path => 'sender',
@@ -101,17 +340,15 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
+       properties => $default_properties->({
            filter => {
                description => "Sender address filter.",
                type => 'string',
                maxLength => 512,
                optional => 1,
            },
-           orderby => $orderby_param_desc,
-       },
+           orderby => $api_properties->{orderby},
+       }),
     },
     returns => {
        type => 'array',
@@ -146,8 +383,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
@@ -171,9 +407,7 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
+       properties => $default_properties->({
            sender => get_standard_option('pmg-email-address', {
                description => "Sender email address.",
            }),
@@ -183,8 +417,8 @@ __PACKAGE__->register_method ({
                maxLength => 512,
                optional => 1,
            },
-           orderby => $orderby_param_desc,
-       },
+           orderby => $api_properties->{orderby},
+       }),
     },
     returns => {
        type => 'array',
@@ -211,7 +445,7 @@ __PACKAGE__->register_method ({
                    description => "Spam score.",
                    type => 'number',
                },
-               virusname => {
+               virusinfo => {
                    description => "Virus name.",
                    type => 'string',
                    optional => 1,
@@ -225,15 +459,14 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
 
        my $sorters = [];
        if ($param->{orderby}) {
-           my $props = ['time', 'receiver', 'bytes', 'blocked', 'spamlevel', 'viruscount'];
+           my $props = ['time', 'receiver', 'bytes', 'blocked', 'spamlevel', 'virusinfo'];
            $sorters = $decode_orderby->($param->{orderby}, $props);
        }
 
@@ -241,6 +474,156 @@ __PACKAGE__->register_method ({
            $rdb, $param->{sender}, $userstat_limit, $sorters, $param->{filter});
     }});
 
+__PACKAGE__->register_method ({
+    name => 'receiver',
+    path => 'receiver',
+    method => 'GET',
+    description => "Receiver Address Statistics.",
+    permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+    parameters => {
+       additionalProperties => 0,
+       properties => $default_properties->({
+           filter => {
+               description => "Receiver address filter.",
+               type => 'string',
+               maxLength => 512,
+               optional => 1,
+           },
+           orderby => $api_properties->{orderby},
+       }),
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => "object",
+           properties => {
+               receiver => {
+                   description => "Sender email.",
+                   type => 'string',
+               },
+               count => {
+                   description => "Mail count.",
+                   type => 'number',
+                   optional => 1,
+               },
+               bytes => {
+                   description => "Mail traffic (Bytes).",
+                   type => 'number',
+               },
+               spamcount => {
+                   description => "Number of sent spam mails.",
+                   type => 'number',
+                   optional => 1,
+               },
+               viruscount => {
+                   description => "Number of sent virus mails.",
+                   type => 'number',
+                   optional => 1,
+               },
+           },
+       },
+       links => [ { rel => 'child', href => "{receiver}" } ],
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       my ($start, $end) = $extract_start_end->($param);
+
+       my $cfg = PMG::Config->new();
+       my $advfilter = $cfg->get('admin', 'advfilter');
+
+       my $stat = PMG::Statistic->new($start, $end);
+       my $rdb = PMG::RuleDB->new();
+
+       my $sorters = [];
+       if ($param->{orderby}) {
+           my $props = ['receiver', 'count', 'bytes', 'spamcount', 'viruscount'];
+           $sorters = $decode_orderby->($param->{orderby}, $props);
+       }
+
+       my $res = $stat->user_stat_receiver($rdb, $userstat_limit, $sorters, $param->{filter}, $advfilter);
+
+       return $res;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'receiverdetails',
+    path => 'receiver/{receiver}',
+    method => 'GET',
+    description => "Detailed Receiver Statistics.",
+    permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+    parameters => {
+       additionalProperties => 0,
+       properties => $default_properties->({
+           receiver => get_standard_option('pmg-email-address', {
+               description => "Receiver email address.",
+           }),
+           filter => {
+               description => "Sender address filter.",
+               type => 'string',
+               maxLength => 512,
+               optional => 1,
+           },
+           orderby => $api_properties->{orderby},
+       }),
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => "object",
+           properties => {
+               time => {
+                   description => "Receive time stamp",
+                   type => 'integer',
+               },
+               sender => {
+                   description => "Sender email.",
+                   type => 'string',
+               },
+               bytes => {
+                   description => "Mail traffic (Bytes).",
+                   type => 'number',
+               },
+               blocked => {
+                   description => "Mail was blocked.",
+                   type => 'boolean',
+               },
+               spamlevel => {
+                   description => "Spam score.",
+                   type => 'number',
+               },
+               virusinfo => {
+                   description => "Virus name.",
+                   type => 'string',
+                   optional => 1,
+               },
+           },
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       my ($start, $end) = $extract_start_end->($param);
+
+       my $stat = PMG::Statistic->new($start, $end);
+       my $rdb = PMG::RuleDB->new();
+
+       my $sorters = [];
+       if ($param->{orderby}) {
+           my $props = ['time', 'sender', 'bytes', 'blocked', 'spamlevel', 'virusinfo'];
+           $sorters = $decode_orderby->($param->{orderby}, $props);
+       }
+
+       return $stat->user_stat_receiver_details(
+           $rdb, $param->{receiver}, $userstat_limit, $sorters, $param->{filter});
+    }});
+
 __PACKAGE__->register_method ({
     name => 'domains',
     path => 'domains',
@@ -249,10 +632,7 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
-       },
+       properties => $default_properties->(),
     },
     returns => {
        type => 'array',
@@ -304,8 +684,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
@@ -327,10 +706,7 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
-       },
+       properties => $default_properties->(),
     },
     returns => {
        type => "object",
@@ -407,8 +783,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
@@ -426,18 +801,16 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
+       properties => $default_properties->({
            timespan => {
-               description => "Return Mails/<timespan>, when <timespan> is specified in seconds.",
+               description => "Return Mails/<timespan>, where <timespan> is specified in seconds.",
                type => 'integer',
                minimum => 3600,
                maximum => 366*86400,
                optional => 1,
                default => 3600,
-           }
-       },
+           },
+       }),
     },
     returns => {
        type => 'array',
@@ -497,8 +870,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $span = $param->{timespan} // 3600;
 
@@ -524,10 +896,7 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
-       },
+       properties => $default_properties->(),
     },
     returns => {
        type => 'array',
@@ -551,8 +920,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
@@ -571,10 +939,7 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
-       },
+       properties => $default_properties->(),
     },
     returns => {
        type => 'array',
@@ -602,8 +967,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
@@ -645,10 +1009,7 @@ __PACKAGE__->register_method ({
     permissions => { check => [ 'admin', 'qmanager', 'audit'] },
     parameters => {
        additionalProperties => 0,
-       properties => {
-           starttime => get_standard_option('pmg-starttime'),
-           endtime => get_standard_option('pmg-endtime'),
-       },
+       properties => $default_properties->(),
     },
     returns => {
        type => 'array',
@@ -704,8 +1065,7 @@ __PACKAGE__->register_method ({
        my $restenv = PMG::RESTEnvironment->get();
        my $cinfo = $restenv->{cinfo};
 
-       my $start = $param->{starttime} // (time - 86400);
-       my $end = $param->{endtime} // ($start + 86400);
+       my ($start, $end) = $extract_start_end->($param);
 
        my $stat = PMG::Statistic->new($start, $end);
        my $rdb = PMG::RuleDB->new();
@@ -717,4 +1077,65 @@ __PACKAGE__->register_method ({
        return $res;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'rblcount',
+    path => 'rblcount',
+    method => 'GET',
+    description => "Mail RBL Count Statistics.",
+    permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+    parameters => {
+       additionalProperties => 0,
+       properties => $default_properties->({
+           timespan => {
+               description => "Return RBL rejects/<timespan>, where <timespan> is specified in seconds.",
+               type => 'integer',
+               minimum => 3600,
+               maximum => 366*86400,
+               optional => 1,
+               default => 3600,
+           },
+       }),
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => "object",
+           properties => {
+               index => {
+                   description => "Time index.",
+                   type => 'integer',
+               },
+               time => {
+                   description => "Time (Unix epoch).",
+                   type => 'integer',
+               },
+               count => {
+                   description => "RBL recject count.",
+                   type => 'number',
+               },
+           },
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       my ($start, $end) = $extract_start_end->($param);
+
+       my $span = $param->{timespan} // 3600;
+
+       my $count = ($end - $start)/$span;
+
+       die "too many entries - try to increase parameter 'span'\n" if $count > 5000;
+
+       my $stat = PMG::Statistic->new($start, $end);
+       my $rdb = PMG::RuleDB->new();
+
+       my $res = $stat->rbl_count_stats($rdb, $span);
+
+       return $res;
+    }});
+
 1;