]> git.proxmox.com Git - pmg-api.git/blob - src/PMG/API2/Statistics.pm
adc7650b17548ecf52c5c85648e0206118a0a798
[pmg-api.git] / src / PMG / API2 / Statistics.pm
1 package PMG::API2::Statistics;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6 use JSON;
7 use Time::Local;
8
9 use PVE::Tools;
10 use PVE::SafeSyslog;
11 use PVE::INotify;
12 use PVE::Exception qw(raise_param_exc);
13 use PVE::RESTHandler;
14 use PMG::RESTEnvironment;
15 use PVE::JSONSchema qw(get_standard_option);
16
17 use PMG::Utils;
18 use PMG::Config;
19 use PMG::RuleDB;
20 use PMG::Statistic;
21
22 use base qw(PVE::RESTHandler);
23
24 __PACKAGE__->register_method ({
25 name => 'index',
26 path => '',
27 method => 'GET',
28 description => "Directory index.",
29 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
30 parameters => {
31 additionalProperties => 0,
32 properties => {},
33 },
34 returns => {
35 type => 'array',
36 items => {
37 type => "object",
38 properties => {},
39 },
40 links => [ { rel => 'child', href => "{name}" } ],
41 },
42 code => sub {
43 my ($param) = @_;
44
45 return [
46 { name => "contact" },
47 { name => "domains" },
48 { name => "mail" },
49 { name => "mailcount" },
50 { name => "recent" },
51 { name => "recentreceivers" },
52 { name => "maildistribution" },
53 { name => "spamscores" },
54 { name => "sender" },
55 { name => "rblcount" },
56 { name => "receiver" },
57 { name => "virus" },
58 ];
59 }});
60
61 my $decode_orderby = sub {
62 my ($orderby, $allowed_props) = @_;
63
64 my $sorters;
65
66 eval { $sorters = decode_json($orderby); };
67 if (my $err = $@) {
68 raise_param_exc({ orderby => 'invalid JSON'});
69 }
70
71 my $schema = {
72 type => 'array',
73 items => {
74 type => "object",
75 properties => {
76 property => {
77 type => 'string',
78 enum => $allowed_props,
79 },
80 direction => {
81 type => 'string',
82 enum => ['ASC', 'DESC'],
83 },
84 },
85 },
86 };
87
88 PVE::JSONSchema::validate($sorters, $schema, "Parameter 'orderby' verification failed\n");
89
90 return $sorters;
91 };
92
93 my $api_properties = {
94 orderby => {
95 description => "Remote sorting configuration(JSON, ExtJS compatible).",
96 type => 'string',
97 optional => 1,
98 maxLength => 4096,
99 },
100 };
101
102 my $default_properties = sub {
103 my ($prop) = @_;
104
105 $prop //= {};
106
107 $prop->{starttime} = get_standard_option('pmg-starttime');
108 $prop->{endtime} = get_standard_option('pmg-endtime');
109
110 $prop->{year} = {
111 description => "Year. Defaults to current year. You will get statistics for the whole year if you do not specify a month or day.",
112 type => 'integer',
113 minimum => 1900,
114 maximum => 3000,
115 optional => 1,
116 };
117
118 $prop->{month} = {
119 description => "Month. You will get statistics for the whole month if you do not specify a day.",
120 type => 'integer',
121 minimum => 1,
122 maximum => 12,
123 optional => 1,
124 };
125
126 $prop->{day} = {
127 description => "Day of month. Get statistics for a single day.",
128 type => 'integer',
129 minimum => 1,
130 maximum => 31,
131 optional => 1,
132 };
133
134 return $prop;
135 };
136
137 my $extract_start_end = sub {
138 my ($param) = @_;
139
140 my $has_ymd;
141 foreach my $k (qw(year month day)) {
142 if (defined($param->{$k})) {
143 $has_ymd = $k;
144 last;
145 }
146 }
147 my $has_se;
148 foreach my $k (qw(starttime endtime)) {
149 if (defined($param->{$k})) {
150 $has_se = $k;
151 last;
152 }
153 }
154
155 raise_param_exc({ $has_se => "parameter conflicts with parameter '$has_ymd'"})
156 if $has_se && $has_ymd;
157
158 my $start;
159 my $end;
160
161 if ($has_ymd) {
162 my (undef, undef, undef, undef, $month, $year) = localtime(time());
163 $month += 1;
164 $year = $param->{year} if defined($param->{year});
165 if (defined($param->{day})) {
166 my $day = $param->{day};
167 $month = $param->{month} if defined($param->{month});
168 $start = timelocal(0, 0, 0, $day, $month - 1, $year);
169 $end = timelocal(59, 59, 23, $day, $month - 1, $year);
170 } elsif (defined($param->{month})) {
171 my $month = $param->{month};
172 if ($month < 12) {
173 $start = timelocal(0, 0, 0, 1, $month - 1, $year);
174 $end = timelocal(0, 0, 0, 1, $month, $year);
175 } else {
176 $start = timelocal(0, 0, 0, 1, 11, $year);
177 $end = timelocal(0, 0, 0, 1, 0, $year + 1);
178 }
179 } else {
180 $start = timelocal(0, 0, 0, 1, 0, $year);
181 $end = timelocal(0, 0, 0, 1, 0, $year + 1);
182 }
183 } else {
184 $start = $param->{starttime} // (time - 86400);
185 $end = $param->{endtime} // ($start + 86400);
186 }
187
188 return ($start, $end);
189 };
190
191 my $userstat_limit = 2000; # hardcoded limit
192
193 __PACKAGE__->register_method ({
194 name => 'contact',
195 path => 'contact',
196 method => 'GET',
197 description => "Contact Address Statistics.",
198 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
199 parameters => {
200 additionalProperties => 0,
201 properties => $default_properties->({
202 filter => {
203 description => "Contact address filter.",
204 type => 'string',
205 maxLength => 512,
206 optional => 1,
207 },
208 orderby => $api_properties->{orderby},
209 }),
210 },
211 returns => {
212 type => 'array',
213 items => {
214 type => "object",
215 properties => {
216 contact => {
217 description => "Contact email.",
218 type => 'string',
219 },
220 count => {
221 description => "Mail count.",
222 type => 'number',
223 optional => 1,
224 },
225 bytes => {
226 description => "Mail traffic (Bytes).",
227 type => 'number',
228 },
229 viruscount => {
230 description => "Number of sent virus mails.",
231 type => 'number',
232 optional => 1,
233 },
234 },
235 },
236 links => [ { rel => 'child', href => "{contact}" } ],
237 },
238 code => sub {
239 my ($param) = @_;
240
241 my ($start, $end) = $extract_start_end->($param);
242
243 my $cfg = PMG::Config->new();
244 my $advfilter = $cfg->get('admin', 'advfilter');
245
246 my $stat = PMG::Statistic->new($start, $end);
247 my $rdb = PMG::RuleDB->new();
248
249 my $sorters = [];
250 if ($param->{orderby}) {
251 my $props = ['contact', 'count', 'bytes', 'viruscount'];
252 $sorters = $decode_orderby->($param->{orderby}, $props);
253 }
254
255 my $res = $stat->user_stat_contact($rdb, $userstat_limit, $sorters, $param->{filter}, $advfilter);
256
257 return $res;
258 }});
259
260 __PACKAGE__->register_method ({
261 name => 'contactdetails',
262 path => 'contact/{contact}',
263 method => 'GET',
264 description => "Detailed Contact Statistics.",
265 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
266 parameters => {
267 additionalProperties => 0,
268 properties => $default_properties->({
269 contact => get_standard_option('pmg-email-address', {
270 description => "Contact email address.",
271 }),
272 filter => {
273 description => "Sender address filter.",
274 type => 'string',
275 maxLength => 512,
276 optional => 1,
277 },
278 orderby => $api_properties->{orderby},
279 }),
280 },
281 returns => {
282 type => 'array',
283 items => {
284 type => "object",
285 properties => {
286 time => {
287 description => "Receive time stamp",
288 type => 'integer',
289 },
290 sender => {
291 description => "Sender email.",
292 type => 'string',
293 },
294 bytes => {
295 description => "Mail traffic (Bytes).",
296 type => 'number',
297 },
298 blocked => {
299 description => "Mail was blocked.",
300 type => 'boolean',
301 },
302 spamlevel => {
303 description => "Spam score.",
304 type => 'number',
305 },
306 virusinfo => {
307 description => "Virus name.",
308 type => 'string',
309 optional => 1,
310 },
311 },
312 },
313 },
314 code => sub {
315 my ($param) = @_;
316
317 my $restenv = PMG::RESTEnvironment->get();
318 my $cinfo = $restenv->{cinfo};
319
320 my ($start, $end) = $extract_start_end->($param);
321
322 my $stat = PMG::Statistic->new($start, $end);
323 my $rdb = PMG::RuleDB->new();
324
325 my $sorters = [];
326 if ($param->{orderby}) {
327 my $props = ['time', 'sender', 'bytes', 'blocked', 'spamlevel', 'virusinfo'];
328 $sorters = $decode_orderby->($param->{orderby}, $props);
329 }
330
331 return $stat->user_stat_contact_details(
332 $rdb, $param->{contact}, $userstat_limit, $sorters, $param->{filter});
333 }});
334
335 __PACKAGE__->register_method ({
336 name => 'sender',
337 path => 'sender',
338 method => 'GET',
339 description => "Sender Address Statistics.",
340 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
341 parameters => {
342 additionalProperties => 0,
343 properties => $default_properties->({
344 filter => {
345 description => "Sender address filter.",
346 type => 'string',
347 maxLength => 512,
348 optional => 1,
349 },
350 orderby => $api_properties->{orderby},
351 }),
352 },
353 returns => {
354 type => 'array',
355 items => {
356 type => "object",
357 properties => {
358 sender => {
359 description => "Sender email.",
360 type => 'string',
361 },
362 count => {
363 description => "Mail count.",
364 type => 'number',
365 optional => 1,
366 },
367 bytes => {
368 description => "Mail traffic (Bytes).",
369 type => 'number',
370 },
371 viruscount => {
372 description => "Number of sent virus mails.",
373 type => 'number',
374 optional => 1,
375 },
376 },
377 },
378 links => [ { rel => 'child', href => "{sender}" } ],
379 },
380 code => sub {
381 my ($param) = @_;
382
383 my ($start, $end) = $extract_start_end->($param);
384
385 my $stat = PMG::Statistic->new($start, $end);
386 my $rdb = PMG::RuleDB->new();
387
388 my $sorters = [];
389 if ($param->{orderby}) {
390 my $props = ['sender', 'count', 'bytes', 'viruscount'];
391 $sorters = $decode_orderby->($param->{orderby}, $props);
392 }
393
394 my $res = $stat->user_stat_sender($rdb, $userstat_limit, $sorters, $param->{filter});
395
396 return $res;
397 }});
398
399 __PACKAGE__->register_method ({
400 name => 'senderdetails',
401 path => 'sender/{sender}',
402 method => 'GET',
403 description => "Detailed Sender Statistics.",
404 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
405 parameters => {
406 additionalProperties => 0,
407 properties => $default_properties->({
408 sender => get_standard_option('pmg-email-address', {
409 description => "Sender email address.",
410 }),
411 filter => {
412 description => "Receiver address filter.",
413 type => 'string',
414 maxLength => 512,
415 optional => 1,
416 },
417 orderby => $api_properties->{orderby},
418 }),
419 },
420 returns => {
421 type => 'array',
422 items => {
423 type => "object",
424 properties => {
425 time => {
426 description => "Receive time stamp",
427 type => 'integer',
428 },
429 receiver => {
430 description => "Receiver email.",
431 type => 'string',
432 },
433 bytes => {
434 description => "Mail traffic (Bytes).",
435 type => 'number',
436 },
437 blocked => {
438 description => "Mail was blocked.",
439 type => 'boolean',
440 },
441 spamlevel => {
442 description => "Spam score.",
443 type => 'number',
444 },
445 virusinfo => {
446 description => "Virus name.",
447 type => 'string',
448 optional => 1,
449 },
450 },
451 },
452 },
453 code => sub {
454 my ($param) = @_;
455
456 my $restenv = PMG::RESTEnvironment->get();
457 my $cinfo = $restenv->{cinfo};
458
459 my ($start, $end) = $extract_start_end->($param);
460
461 my $stat = PMG::Statistic->new($start, $end);
462 my $rdb = PMG::RuleDB->new();
463
464 my $sorters = [];
465 if ($param->{orderby}) {
466 my $props = ['time', 'receiver', 'bytes', 'blocked', 'spamlevel', 'virusinfo'];
467 $sorters = $decode_orderby->($param->{orderby}, $props);
468 }
469
470 return $stat->user_stat_sender_details(
471 $rdb, $param->{sender}, $userstat_limit, $sorters, $param->{filter});
472 }});
473
474 __PACKAGE__->register_method ({
475 name => 'receiver',
476 path => 'receiver',
477 method => 'GET',
478 description => "Receiver Address Statistics.",
479 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
480 parameters => {
481 additionalProperties => 0,
482 properties => $default_properties->({
483 filter => {
484 description => "Receiver address filter.",
485 type => 'string',
486 maxLength => 512,
487 optional => 1,
488 },
489 orderby => $api_properties->{orderby},
490 }),
491 },
492 returns => {
493 type => 'array',
494 items => {
495 type => "object",
496 properties => {
497 receiver => {
498 description => "Sender email.",
499 type => 'string',
500 },
501 count => {
502 description => "Mail count.",
503 type => 'number',
504 optional => 1,
505 },
506 bytes => {
507 description => "Mail traffic (Bytes).",
508 type => 'number',
509 },
510 spamcount => {
511 description => "Number of sent spam mails.",
512 type => 'number',
513 optional => 1,
514 },
515 viruscount => {
516 description => "Number of sent virus mails.",
517 type => 'number',
518 optional => 1,
519 },
520 },
521 },
522 links => [ { rel => 'child', href => "{receiver}" } ],
523 },
524 code => sub {
525 my ($param) = @_;
526
527 my ($start, $end) = $extract_start_end->($param);
528
529 my $cfg = PMG::Config->new();
530 my $advfilter = $cfg->get('admin', 'advfilter');
531
532 my $stat = PMG::Statistic->new($start, $end);
533 my $rdb = PMG::RuleDB->new();
534
535 my $sorters = [];
536 if ($param->{orderby}) {
537 my $props = ['receiver', 'count', 'bytes', 'spamcount', 'viruscount'];
538 $sorters = $decode_orderby->($param->{orderby}, $props);
539 }
540
541 my $res = $stat->user_stat_receiver($rdb, $userstat_limit, $sorters, $param->{filter}, $advfilter);
542
543 return $res;
544 }});
545
546 __PACKAGE__->register_method ({
547 name => 'receiverdetails',
548 path => 'receiver/{receiver}',
549 method => 'GET',
550 description => "Detailed Receiver Statistics.",
551 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
552 parameters => {
553 additionalProperties => 0,
554 properties => $default_properties->({
555 receiver => get_standard_option('pmg-email-address', {
556 description => "Receiver email address.",
557 }),
558 filter => {
559 description => "Sender address filter.",
560 type => 'string',
561 maxLength => 512,
562 optional => 1,
563 },
564 orderby => $api_properties->{orderby},
565 }),
566 },
567 returns => {
568 type => 'array',
569 items => {
570 type => "object",
571 properties => {
572 time => {
573 description => "Receive time stamp",
574 type => 'integer',
575 },
576 sender => {
577 description => "Sender email.",
578 type => 'string',
579 },
580 bytes => {
581 description => "Mail traffic (Bytes).",
582 type => 'number',
583 },
584 blocked => {
585 description => "Mail was blocked.",
586 type => 'boolean',
587 },
588 spamlevel => {
589 description => "Spam score.",
590 type => 'number',
591 },
592 virusinfo => {
593 description => "Virus name.",
594 type => 'string',
595 optional => 1,
596 },
597 },
598 },
599 },
600 code => sub {
601 my ($param) = @_;
602
603 my $restenv = PMG::RESTEnvironment->get();
604 my $cinfo = $restenv->{cinfo};
605
606 my ($start, $end) = $extract_start_end->($param);
607
608 my $stat = PMG::Statistic->new($start, $end);
609 my $rdb = PMG::RuleDB->new();
610
611 my $sorters = [];
612 if ($param->{orderby}) {
613 my $props = ['time', 'sender', 'bytes', 'blocked', 'spamlevel', 'virusinfo'];
614 $sorters = $decode_orderby->($param->{orderby}, $props);
615 }
616
617 return $stat->user_stat_receiver_details(
618 $rdb, $param->{receiver}, $userstat_limit, $sorters, $param->{filter});
619 }});
620
621 __PACKAGE__->register_method ({
622 name => 'domains',
623 path => 'domains',
624 method => 'GET',
625 description => "Mail Domains Statistics.",
626 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
627 parameters => {
628 additionalProperties => 0,
629 properties => $default_properties->(),
630 },
631 returns => {
632 type => 'array',
633 items => {
634 type => "object",
635 properties => {
636 domain => {
637 description => "Domain name.",
638 type => 'string',
639 },
640 count_in => {
641 description => "Incoming mail count.",
642 type => 'number',
643 },
644 count_out => {
645 description => "Outgoing mail count.",
646 type => 'number',
647 },
648 spamcount_in => {
649 description => "Incoming spam mails.",
650 type => 'number',
651 },
652 spamcount_out => {
653 description => "Outgoing spam mails.",
654 type => 'number',
655 },
656 bytes_in => {
657 description => "Incoming mail traffic (Bytes).",
658 type => 'number',
659 },
660 bytes_out => {
661 description => "Outgoing mail traffic (Bytes).",
662 type => 'number',
663 },
664 viruscount_in => {
665 description => "Number of incoming virus mails.",
666 type => 'number',
667 },
668 viruscount_out => {
669 description => "Number of outgoing virus mails.",
670 type => 'number',
671 },
672 },
673 },
674 },
675 code => sub {
676 my ($param) = @_;
677
678 my ($start, $end) = $extract_start_end->($param);
679
680 my $stat = PMG::Statistic->new($start, $end);
681 my $rdb = PMG::RuleDB->new();
682
683 #PMG::Statistic::update_stats_domainstat_in($rdb->{dbh}, $cinfo);
684 #PMG::Statistic::update_stats_domainstat_out($rdb->{dbh}, $cinfo);
685
686 my $res = $stat->total_domain_stat($rdb);
687
688
689 return $res;
690 }});
691
692 __PACKAGE__->register_method ({
693 name => 'mail',
694 path => 'mail',
695 method => 'GET',
696 description => "General Mail Statistics.",
697 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
698 parameters => {
699 additionalProperties => 0,
700 properties => $default_properties->(),
701 },
702 returns => {
703 type => "object",
704 properties => {
705 avptime => {
706 description => "Average mail processing time in seconds.",
707 type => 'number',
708 },
709 bounces_in => {
710 description => "Incoming bounce mail count (sender = <>).",
711 type => 'number',
712 },
713 bounces_out => {
714 description => "Outgoing bounce mail count (sender = <>).",
715 type => 'number',
716 },
717 count => {
718 description => "Overall mail count (in and out).",
719 type => 'number',
720 },
721 count_in => {
722 description => "Incoming mail count.",
723 type => 'number',
724 },
725 count_out => {
726 description => "Outgoing mail count.",
727 type => 'number',
728 },
729 glcount => {
730 description => "Number of greylisted mails.",
731 type => 'number',
732 },
733 rbl_rejects => {
734 description => "Number of RBL rejects.",
735 type => 'integer',
736 },
737 pregreet_rejects => {
738 description => "PREGREET recject count.",
739 type => 'integer',
740 },
741 junk_in => {
742 description => "Incoming junk mail count (viruscount_in + spamcount_in + glcount + spfcount + rbl_rejects + pregreet_rejects).",
743 type => 'number',
744 },
745 junk_out => {
746 description => "Outgoing junk mail count (viruscount_out + spamcount_out).",
747 type => 'number',
748 },
749 spamcount_in => {
750 description => "Incoming spam mails.",
751 type => 'number',
752 },
753 spamcount_out => {
754 description => "Outgoing spam mails.",
755 type => 'number',
756 },
757 spfcount => {
758 description => "Mails rejected by SPF.",
759 type => 'number',
760 },
761 bytes_in => {
762 description => "Incoming mail traffic (bytes).",
763 type => 'number',
764 },
765 bytes_out => {
766 description => "Outgoing mail traffic (bytes).",
767 type => 'number',
768 },
769 viruscount_in => {
770 description => "Number of incoming virus mails.",
771 type => 'number',
772 },
773 viruscount_out => {
774 description => "Number of outgoing virus mails.",
775 type => 'number',
776 },
777 },
778 },
779 code => sub {
780 my ($param) = @_;
781
782 my ($start, $end) = $extract_start_end->($param);
783
784 my $stat = PMG::Statistic->new($start, $end);
785 my $rdb = PMG::RuleDB->new();
786
787 my $res = $stat->total_mail_stat($rdb);
788
789 my $rejects = $stat->postscreen_stat($rdb);
790
791 $res->{rbl_rejects} //= 0;
792 if (defined(my $rbl_rejects = $rejects->{rbl_rejects})) {
793 foreach my $k (qw(rbl_rejects junk_in count_in count)) {
794 $res->{$k} += $rbl_rejects;
795 }
796 }
797
798 $res->{pregreet_rejects} //= 0;
799 if (defined(my $pregreet_rejects = $rejects->{pregreet_rejects})) {
800 foreach my $k (qw(pregreet_rejects junk_in count_in count)) {
801 $res->{$k} += $pregreet_rejects;
802 }
803 }
804
805 return $res;
806 }});
807
808 __PACKAGE__->register_method ({
809 name => 'recent',
810 path => 'recent',
811 method => 'GET',
812 description => "Mail Count Statistics.",
813 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
814 parameters => {
815 additionalProperties => 0,
816 properties => {
817 hours => {
818 description => "How many hours you want to get",
819 type => 'integer',
820 minimum => 1,
821 maximum => 24,
822 optional => 1,
823 default => 12,
824 },
825 timespan => {
826 description => "The Timespan for one datapoint (in seconds)",
827 type => 'integer',
828 minimum => 1,
829 maximum => 1800,
830 optional => 1,
831 default => 1800,
832 },
833 },
834 },
835 returns => {
836 type => 'array',
837 items => {
838 type => "object",
839 properties => {
840 index => {
841 description => "Time index.",
842 type => 'integer',
843 },
844 time => {
845 description => "Time (Unix epoch).",
846 type => 'integer',
847 },
848 count => {
849 description => "Overall mail count (in and out).",
850 type => 'number',
851 },
852 count_in => {
853 description => "Incoming mail count.",
854 type => 'number',
855 },
856 count_out => {
857 description => "Outgoing mail count.",
858 type => 'number',
859 },
860 spam => {
861 description => "Overall spam mail count (in and out).",
862 type => 'number',
863 },
864 spam_in => {
865 description => "Incoming spam mails (spamcount_in + glcount + spfcount).",
866 type => 'number',
867 },
868 spam_out => {
869 description => "Outgoing spam mails.",
870 type => 'number',
871 },
872 bytes_in => {
873 description => "Number of incoming bytes mails.",
874 type => 'number',
875 },
876 bytes_out => {
877 description => "Number of outgoing bytes mails.",
878 type => 'number',
879 },
880 virus_in => {
881 description => "Number of incoming virus mails.",
882 type => 'number',
883 },
884 virus_out => {
885 description => "Number of outgoing virus mails.",
886 type => 'number',
887 },
888 timespan => {
889 description => "Timespan in seconds for one data point",
890 type => 'number',
891 }
892 },
893 },
894 },
895 code => sub {
896 my ($param) = @_;
897
898 my $hours = $param->{hours} // 12;
899 my $span = $param->{timespan} // 1800;
900
901 my $end = time();
902 my $start = $end - 3600*$hours;
903
904 my $stat = PMG::Statistic->new($start, $end);
905 my $rdb = PMG::RuleDB->new();
906
907 my $res = $stat->recent_mailcount($rdb, $span);
908
909 return $res;
910 }});
911
912 __PACKAGE__->register_method ({
913 name => 'recentreceivers',
914 path => 'recentreceivers',
915 method => 'GET',
916 description => "Top recent Mail Receivers (including spam)",
917 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
918 parameters => {
919 additionalProperties => 0,
920 properties => {
921 hours => {
922 description => "How many hours you want to get",
923 type => 'integer',
924 minimum => 1,
925 maximum => 24,
926 optional => 1,
927 default => 12,
928 },
929 limit => {
930 description => "The maximum number of receivers to return.",
931 type => 'integer',
932 minimum => 1,
933 maximum => 50,
934 optional => 1,
935 default => 5,
936 },
937 },
938 },
939 returns => {
940 type => 'array',
941 items => {
942 type => "object",
943 properties => {
944 count => {
945 description => "The count of incoming not blocked E-Mails",
946 type => 'integer',
947 },
948 receiver => {
949 description => "The receiver",
950 type => 'string',
951 },
952 },
953 },
954 },
955 code => sub {
956 my ($param) = @_;
957
958 my $hours = $param->{hours} // 12;
959
960 my $limit = $param->{limit} // 5;
961
962 my $end = time();
963 my $start = $end - 3600*$hours;
964
965 my $stat = PMG::Statistic->new($start, $end);
966 my $rdb = PMG::RuleDB->new();
967
968 my $res = $stat->recent_receivers($rdb, $limit);
969
970 return $res;
971 }});
972
973 __PACKAGE__->register_method ({
974 name => 'mailcount',
975 path => 'mailcount',
976 method => 'GET',
977 description => "Mail Count Statistics.",
978 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
979 parameters => {
980 additionalProperties => 0,
981 properties => $default_properties->({
982 timespan => {
983 description => "Return Mails/<timespan>, where <timespan> is specified in seconds.",
984 type => 'integer',
985 minimum => 3600,
986 maximum => 366*86400,
987 optional => 1,
988 default => 3600,
989 },
990 }),
991 },
992 returns => {
993 type => 'array',
994 items => {
995 type => "object",
996 properties => {
997 index => {
998 description => "Time index.",
999 type => 'integer',
1000 },
1001 time => {
1002 description => "Time (Unix epoch).",
1003 type => 'integer',
1004 },
1005 count => {
1006 description => "Overall mail count (in and out).",
1007 type => 'number',
1008 },
1009 count_in => {
1010 description => "Incoming mail count.",
1011 type => 'number',
1012 },
1013 count_out => {
1014 description => "Outgoing mail count.",
1015 type => 'number',
1016 },
1017 spamcount_in => {
1018 description => "Incoming spam mails (spamcount_in + glcount + spfcount + rbl_rejects + pregreet_rejects).",
1019 type => 'number',
1020 },
1021 spamcount_out => {
1022 description => "Outgoing spam mails.",
1023 type => 'number',
1024 },
1025 viruscount_in => {
1026 description => "Number of incoming virus mails.",
1027 type => 'number',
1028 },
1029 viruscount_out => {
1030 description => "Number of outgoing virus mails.",
1031 type => 'number',
1032 },
1033 rbl_rejects => {
1034 description => "Number of RBL rejects.",
1035 type => 'integer',
1036 },
1037 pregreet_rejects => {
1038 description => "PREGREET recject count.",
1039 type => 'integer',
1040 },
1041 bounces_in => {
1042 description => "Incoming bounce mail count (sender = <>).",
1043 type => 'number',
1044 },
1045 bounces_out => {
1046 description => "Outgoing bounce mail count (sender = <>).",
1047 type => 'number',
1048 },
1049 },
1050 },
1051 },
1052 code => sub {
1053 my ($param) = @_;
1054
1055 my ($start, $end) = $extract_start_end->($param);
1056
1057 my $span = $param->{timespan} // 3600;
1058
1059 my $count = ($end - $start)/$span;
1060
1061 die "too many entries - try to increase parameter 'span'\n" if $count > 5000;
1062
1063 my $stat = PMG::Statistic->new($start, $end);
1064 my $rdb = PMG::RuleDB->new();
1065
1066 #PMG::Statistic::update_stats_dailystat($rdb->{dbh}, $cinfo);
1067
1068 my $rejects = $stat->postscreen_stat_graph($rdb, $span);
1069
1070 my $res = $stat->traffic_stat_graph ($rdb, $span);
1071
1072 my $element_count = scalar(@$res);
1073
1074 for (my $i = 0; $i < $element_count; $i++) {
1075 my $el = $rejects->[$i];
1076 next if !$el;
1077 my $d = $res->[$i];
1078 foreach my $k ('rbl_rejects', 'pregreet_rejects') {
1079 my $count = $el->{$k} // 0;
1080 $d->{$k} = $count;
1081 foreach my $k (qw(count count_in spamcount_in)) {
1082 $d->{$k} += $count;
1083 }
1084 }
1085 }
1086
1087 return $res;
1088 }});
1089
1090 __PACKAGE__->register_method ({
1091 name => 'virus',
1092 path => 'virus',
1093 method => 'GET',
1094 description => "Get Statistics about detected Viruses.",
1095 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
1096 parameters => {
1097 additionalProperties => 0,
1098 properties => $default_properties->(),
1099 },
1100 returns => {
1101 type => 'array',
1102 items => {
1103 type => "object",
1104 properties => {
1105 name => {
1106 description => 'Virus name.',
1107 type => 'string',
1108 },
1109 count => {
1110 description => 'Detection count.',
1111 type => 'integer',
1112 },
1113 },
1114 }
1115 },
1116 code => sub {
1117 my ($param) = @_;
1118
1119 my ($start, $end) = $extract_start_end->($param);
1120
1121 my $stat = PMG::Statistic->new($start, $end);
1122 my $rdb = PMG::RuleDB->new();
1123
1124 my $res = $stat->total_virus_stat($rdb);
1125
1126 return $res;
1127 }});
1128
1129 __PACKAGE__->register_method ({
1130 name => 'spamscores',
1131 path => 'spamscores',
1132 method => 'GET',
1133 description => "Get the count of spam mails grouped by spam score. " .
1134 "Count for score 10 includes mails with spam score > 10.",
1135 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
1136 parameters => {
1137 additionalProperties => 0,
1138 properties => $default_properties->(),
1139 },
1140 returns => {
1141 type => 'array',
1142 items => {
1143 type => "object",
1144 properties => {
1145 level => {
1146 description => 'Spam level.',
1147 type => 'string',
1148 },
1149 count => {
1150 description => 'Detection count.',
1151 type => 'integer',
1152 },
1153 ratio => {
1154 description => 'Portion of overall mail count.',
1155 type => 'number',
1156 },
1157 },
1158 }
1159 },
1160 code => sub {
1161 my ($param) = @_;
1162
1163 my ($start, $end) = $extract_start_end->($param);
1164
1165 my $stat = PMG::Statistic->new($start, $end);
1166 my $rdb = PMG::RuleDB->new();
1167
1168 my $totalstat = $stat->total_mail_stat ($rdb);
1169 my $spamstat = $stat->total_spam_stat($rdb);
1170
1171 my $res = [];
1172
1173 my $count_in = $totalstat->{count_in};
1174
1175 my $levelcount = {};
1176 my $spamcount = 0;
1177 foreach my $ref (@$spamstat) {
1178 if (my $level = $ref->{spamlevel}) {
1179 next if $level < 1; # just to be sure
1180 $spamcount += $ref->{count};
1181 $level = 10 if $level > 10;
1182 $levelcount->{$level} += $ref->{count};
1183 }
1184 }
1185
1186 $levelcount->{0} = $count_in - $spamcount;
1187
1188 for (my $i = 0; $i <= 10; $i++) {
1189 my $count = $levelcount->{$i} // 0;
1190 my $ratio = $count_in ? $count/$count_in : 0;
1191 push @$res, { level => $i, count => $count, ratio => $ratio };
1192 }
1193
1194 return $res;
1195 }});
1196
1197 __PACKAGE__->register_method ({
1198 name => 'maildistribution',
1199 path => 'maildistribution',
1200 method => 'GET',
1201 description => "Get the count of spam mails grouped by spam score. " .
1202 "Count for score 10 includes mails with spam score > 10.",
1203 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
1204 parameters => {
1205 additionalProperties => 0,
1206 properties => $default_properties->(),
1207 },
1208 returns => {
1209 type => 'array',
1210 items => {
1211 type => "object",
1212 properties => {
1213 index => {
1214 description => "Hour (0-23).",
1215 type => 'integer',
1216 },
1217 count => {
1218 description => "Overall mail count (in and out).",
1219 type => 'number',
1220 },
1221 count_in => {
1222 description => "Incoming mail count.",
1223 type => 'number',
1224 },
1225 count_out => {
1226 description => "Outgoing mail count.",
1227 type => 'number',
1228 },
1229 spamcount_in => {
1230 description => "Incoming spam mails (spamcount_in + glcount + spfcount).",
1231 type => 'number',
1232 },
1233 spamcount_out => {
1234 description => "Outgoing spam mails.",
1235 type => 'number',
1236 },
1237 viruscount_in => {
1238 description => "Number of incoming virus mails.",
1239 type => 'number',
1240 },
1241 viruscount_out => {
1242 description => "Number of outgoing virus mails.",
1243 type => 'number',
1244 },
1245 bounces_in => {
1246 description => "Incoming bounce mail count (sender = <>).",
1247 type => 'number',
1248 },
1249 bounces_out => {
1250 description => "Outgoing bounce mail count (sender = <>).",
1251 type => 'number',
1252 },
1253 },
1254 },
1255 },
1256 code => sub {
1257 my ($param) = @_;
1258
1259 my ($start, $end) = $extract_start_end->($param);
1260
1261 my $stat = PMG::Statistic->new($start, $end);
1262 my $rdb = PMG::RuleDB->new();
1263
1264 #PMG::Statistic::update_stats_dailystat($rdb->{dbh}, $cinfo);
1265
1266 my $res = $stat->traffic_stat_day_dist ($rdb);
1267
1268 return $res;
1269 }});
1270
1271 __PACKAGE__->register_method ({
1272 name => 'rejectcount',
1273 path => 'rejectcount',
1274 method => 'GET',
1275 description => "Early SMTP reject count statistic (RBL, PREGREET rejects with postscreen)",
1276 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
1277 parameters => {
1278 additionalProperties => 0,
1279 properties => $default_properties->({
1280 timespan => {
1281 description => "Return RBL/PREGREET rejects/<timespan>, where <timespan> is specified in seconds.",
1282 type => 'integer',
1283 minimum => 3600,
1284 maximum => 366*86400,
1285 optional => 1,
1286 default => 3600,
1287 },
1288 }),
1289 },
1290 returns => {
1291 type => 'array',
1292 items => {
1293 type => "object",
1294 properties => {
1295 index => {
1296 description => "Time index.",
1297 type => 'integer',
1298 },
1299 time => {
1300 description => "Time (Unix epoch).",
1301 type => 'integer',
1302 },
1303 rbl_rejects => {
1304 description => "RBL recject count.",
1305 type => 'integer',
1306 },
1307 pregreet_rejects => {
1308 description => "PREGREET recject count.",
1309 type => 'integer',
1310 },
1311 },
1312 },
1313 },
1314 code => sub {
1315 my ($param) = @_;
1316
1317 my ($start, $end) = $extract_start_end->($param);
1318
1319 my $span = $param->{timespan} // 3600;
1320
1321 my $count = ($end - $start)/$span;
1322
1323 die "too many entries - try to increase parameter 'span'\n" if $count > 5000;
1324
1325 my $stat = PMG::Statistic->new($start, $end);
1326 my $rdb = PMG::RuleDB->new();
1327
1328 my $res = $stat->postscreen_stat_graph($rdb, $span);
1329
1330 return $res;
1331 }});
1332
1333 1;