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