give modules default loggers so they are usable on their own (in tests)
[scpubgit/System-Introspector-Report.git] / lib / System / Introspector / Report / Publish / MediaWiki.pm
1 package System::Introspector::Report::Publish::MediaWiki;
2 use Moo;
3 use Try::Tiny;
4 use Log::Contextual::WarnLogger;
5 use Log::Contextual qw( :log ),
6   -default_logger => Log::Contextual::WarnLogger->new({
7     env_prefix => 'SI_REPORT_MEDIAWIKI',
8     levels      => [qw( error fatal warn )],
9   });
10
11 use aliased 'System::Introspector::Report::Publish::MediaWiki::Connection';
12
13 has page_options => (
14   is => 'ro',
15   default => sub { {} },
16   init_arg => 'page',
17 );
18
19 has connection => (is => 'ro', lazy => 1, builder => 1, handles => {
20   get_page => 'get',
21   put_page => 'put',
22 });
23
24 has api_uri         => (is => 'ro', required => 1);
25 has username        => (is => 'ro', required => 1);
26 has password        => (is => 'ro', required => 1);
27 has allow_create    => (is => 'ro', default => sub { 0 });
28 has http_auth       => (is => 'ro');
29 has http_realm      => (is => 'ro');
30
31 sub _build_producer { Producer->new }
32
33 sub _build_connection {
34   my ($self) = @_;
35   return Connection->new(
36     api_uri         => $self->api_uri,
37     username        => $self->username,
38     password        => $self->password,
39     allow_create    => $self->allow_create,
40     $self->http_auth ? (
41       http_auth  => 1,
42       http_realm => $self->http_realm,
43     ) : (),
44   );
45 }
46
47 sub publish {
48   my ($self, $reports) = @_;
49   my $pages = $self->page_options;
50   log_info {
51     sprintf "Pushing reports to MediaWiki at '%s'", $self->api_uri;
52   };
53   for my $page (sort keys %$pages) {
54     $self->_publish_page($reports, $page, $pages->{$page});
55   }
56   log_info { "Finished pushing to MediaWiki" };
57   return 1;
58 }
59
60 sub _sort_reports {
61   my ($self, $reports, $included) = @_;
62   my @matchers = map {
63     $self->_prepare_matcher_from($_);
64   } ref($included) ? @{$included} : $included;
65   my @grouped;
66   for my $report (@$reports) {
67     my ($group_idx) = grep {
68       $self->_match_id($report, $matchers[$_]);
69     } 0 .. $#matchers;
70     if (defined $group_idx) {
71       push @{$grouped[$group_idx]}, $report;
72     }
73   }
74   return [ map { (@$_) } @grouped ];
75 }
76
77 sub _publish_dynamic {
78   my ($self, $reports, $page_name, $key, $options) = @_;
79   my %reports_by_key;
80   for my $report (@$reports) {
81     my $value = $report->{meta}{$key};
82     next unless defined $value;
83     push @{ $reports_by_key{$value} ||= [] }, $report;
84   }
85   for my $value (keys %reports_by_key) {
86     (my $effective_page = $page_name)
87       =~ s{\%\(meta:\Q$key\E\)}{$value};
88     my $assoc = $reports_by_key{$value};
89     $self->_publish_page($assoc, $effective_page, $options);
90   }
91   return 1;
92 }
93
94 sub _publish_page {
95   my ($self, $reports, $page_name, $options) = @_;
96   if ($page_name =~ m{\%\(meta:(.+?)\)}) {
97     return $self->_publish_dynamic($reports, $page_name, $1, $options);
98   }
99   my $sorted = $self->_sort_reports($reports, $options->{report} || []);
100   unless (scalar @$sorted) {
101     log_debug { "Skipping page '$page_name': No reports to publish" };
102     return 1;
103   }
104   my $do_create = $options->{create};
105   return try {
106     my $page = $self->get_page($page_name);
107     if ($page->is_new and not $do_create) {
108       log_trace { "Skipping page '$page_name': Does not yet exist" };
109       return 1;
110     }
111     my $is_changed = $page->update($sorted);
112     unless ($is_changed) {
113       log_debug { "Not pushing page '$page_name': No changes" };
114       return 1;
115     }
116     log_debug { "Updating page '$page_name'" };
117     $self->put_page($page);
118     return 1;
119   }
120   catch {
121     log_error { "Error during page update: $_" };
122     return 1;
123   };
124 }
125
126 with $_ for qw(
127   System::Introspector::Report::Publish::API
128 );
129
130 1;