summaryrefslogtreecommitdiffstats
path: root/extensions/Push/lib
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2014-05-19 06:44:19 +0200
committerDylan William Hardison <dylan@hardison.net>2014-05-21 21:29:48 +0200
commite1aea961a9dd83d6d14b4e45cbf4a70b00fbe18c (patch)
tree1305d5d3e61639142801114bd728bb57e6b09ad0 /extensions/Push/lib
parent3d93c5919c4286c036d2cd0986387cecfdfeae60 (diff)
downloadbugzilla-e1aea961a9dd83d6d14b4e45cbf4a70b00fbe18c.tar.gz
bugzilla-e1aea961a9dd83d6d14b4e45cbf4a70b00fbe18c.tar.xz
Bug 993223 - Notify Review Board when a bug is made confidential
r=glob
Diffstat (limited to 'extensions/Push/lib')
-rw-r--r--extensions/Push/lib/Connector/ReviewBoard.pm187
-rw-r--r--extensions/Push/lib/Connector/ReviewBoard/Client.pm67
-rw-r--r--extensions/Push/lib/Connector/ReviewBoard/Resource.pm38
-rw-r--r--extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm28
4 files changed, 320 insertions, 0 deletions
diff --git a/extensions/Push/lib/Connector/ReviewBoard.pm b/extensions/Push/lib/Connector/ReviewBoard.pm
new file mode 100644
index 000000000..b5d1a9214
--- /dev/null
+++ b/extensions/Push/lib/Connector/ReviewBoard.pm
@@ -0,0 +1,187 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::Push::Connector::ReviewBoard;
+
+use strict;
+use warnings;
+
+use base 'Bugzilla::Extension::Push::Connector::Base';
+
+use Bugzilla::Constants;
+use Bugzilla::Extension::Push::Constants;
+use Bugzilla::Extension::Push::Util;
+use Bugzilla::Bug;
+use Bugzilla::Attachment;
+use Bugzilla::Extension::Push::Connector::ReviewBoard::Client;
+
+use JSON 'decode_json';
+use DateTime;
+use Scalar::Util 'blessed';
+
+use constant RB_CONTENT_TYPE => 'text/x-review-board-request';
+
+sub client {
+ my $self = shift;
+
+ $self->{client} //= Bugzilla::Extension::Push::Connector::ReviewBoard::Client->new(
+ base_uri => $self->config->{base_uri},
+ username => $self->config->{username},
+ password => $self->config->{password},
+ $self->config->{proxy} ? (proxy => $self->config->{proxy}) : (),
+ );
+
+ return $self->{client};
+}
+
+sub options {
+ return (
+ {
+ name => 'base_uri',
+ label => 'Base URI for ReviewBoard',
+ type => 'string',
+ default => 'https://reviewboard.allizom.org',
+ required => 1,
+ },
+ {
+ name => 'username',
+ label => 'Username',
+ type => 'string',
+ default => 'guest',
+ required => 1,
+ },
+ {
+ name => 'password',
+ label => 'Password',
+ type => 'password',
+ default => 'guest',
+ required => 1,
+ },
+ {
+ name => 'proxy',
+ label => 'Proxy',
+ type => 'string',
+ },
+ );
+}
+
+sub stop {
+ my ($self) = @_;
+}
+
+sub should_send {
+ my ($self, $message) = @_;
+
+ if ($message->routing_key =~ /^(?:attachment|bug)\.modify:.*\bis_private\b/) {
+ my $payload = $message->payload_decoded();
+ my $target = $payload->{event}->{target};
+
+ if ($target ne 'bug' && exists $payload->{$target}->{bug}) {
+ return 0 if $payload->{$target}->{bug}->{is_private};
+ return 0 if $payload->{$target}->{content_type} ne RB_CONTENT_TYPE;
+ }
+
+ return $payload->{$target}->{is_private} ? 1 : 0;
+ }
+ else {
+ # We're not interested in the message.
+ return 0;
+ }
+}
+
+sub send {
+ my ($self, $message) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $config = $self->config;
+
+ eval {
+ my $payload = $message->payload_decoded();
+ my $target = $payload->{event}->{target};
+
+ if (my $method = $self->can("_process_$target")) {
+ $self->$method($payload->{$target});
+ }
+ };
+ if ($@) {
+ return (PUSH_RESULT_TRANSIENT, clean_error($@));
+ }
+
+ return PUSH_RESULT_OK;
+}
+
+sub _process_attachment {
+ my ($self, $payload_target) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $attachment = blessed($payload_target)
+ ? $payload_target
+ : Bugzilla::Attachment->new({ id => $payload_target->{id}, cache => 1 });
+
+ if ($attachment) {
+ my $content = $attachment->data;
+ my $base_uri = quotemeta($self->config->{base_uri});
+ if (my ($id) = $content =~ m|$base_uri/r/([0-9]+)|) {
+ my $resp = $self->client->review_request->delete($id);
+ my $content = $resp->decoded_content;
+ my $status = $resp->code;
+ my $result = $content && decode_json($content) ;
+
+ if ($status == 204) {
+ # Success, review request deleted!
+ $logger->debug("Deleted review request $id");
+ }
+ elsif ($status == 404) {
+ # API error 100 - Does Not Exist
+ $logger->debug("Does Not Exist: Review Request $id does not exist");
+ }
+ elsif ($status == 403) {
+ # API error 101 - Permission Denied
+ $logger->error("Permission Denied: ReviewBoard Push Connector may be misconfigured");
+ die $result->{err}{msg};
+ }
+ elsif ($status == 401) {
+ # API error 103 - Not logged in
+ $logger->error("Not logged in: ReviewBoard Push Connector may be misconfigured");
+ die $result->{err}{msg};
+ }
+ else {
+ if ($result) {
+ my $code = $result->{err}{code};
+ my $msg = $result->{err}{msg};
+ $logger->error("Unexpected API Error: ($code) $msg");
+ die $msg;
+ }
+ else {
+ $logger->error("Unexpected HTTP Response $status");
+ die "HTTP Status: $status";
+ }
+ }
+ }
+ else {
+ $logger->error("Cannot find link: ReviewBoard Push Connector may be misconfigured");
+ die "Unable to find link in $content";
+ }
+ }
+ else {
+ $logger->error("Cannot find attachment with id = $payload_target->{id}");
+ }
+}
+
+sub _process_bug {
+ my ($self, $payload_target) = @_;
+
+ Bugzilla->set_user(Bugzilla::User->super_user);
+ my $bug = Bugzilla::Bug->new({ id => $payload_target->{id}, cache => 1 });
+ my @attachments = @{ $bug->attachments };
+ Bugzilla->logout;
+
+ foreach my $attachment (@attachments) {
+ next if $attachment->contenttype ne RB_CONTENT_TYPE;
+ $self->_process_attachment($attachment);
+ }
+}
+
+1;
diff --git a/extensions/Push/lib/Connector/ReviewBoard/Client.pm b/extensions/Push/lib/Connector/ReviewBoard/Client.pm
new file mode 100644
index 000000000..7ec4938d2
--- /dev/null
+++ b/extensions/Push/lib/Connector/ReviewBoard/Client.pm
@@ -0,0 +1,67 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::Push::Connector::ReviewBoard::Client;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use Carp qw(croak);
+use LWP::UserAgent;
+use Scalar::Util qw(blessed);
+use URI;
+
+use Bugzilla::Extension::Push::Connector::ReviewBoard::ReviewRequest;
+
+sub new {
+ my ($class, %params) = @_;
+
+ croak "->new() is a class method" if blessed($class);
+ return bless(\%params, $class);
+}
+
+sub username { $_[0]->{username} }
+sub password { $_[0]->{password} }
+sub base_uri { $_[0]->{base_uri} }
+sub realm { $_[0]->{realm} // 'Web API' }
+sub proxy { $_[0]->{proxy} }
+
+sub _netloc {
+ my $self = shift;
+
+ my $uri = URI->new($self->base_uri);
+ return $uri->host . ':' . $uri->port;
+}
+
+sub useragent {
+ my $self = shift;
+
+ unless ($self->{useragent}) {
+ my $ua = LWP::UserAgent->new(agent => Bugzilla->params->{urlbase});
+ $ua->credentials(
+ $self->_netloc,
+ $self->realm,
+ $self->username,
+ $self->password,
+ );
+ $ua->proxy('https', $self->proxy) if $self->proxy;
+ $ua->timeout(10);
+
+ $self->{useragent} = $ua;
+ }
+
+ return $self->{useragent};
+}
+
+sub review_request {
+ my $self = shift;
+
+ return Bugzilla::Extension::Push::Connector::ReviewBoard::ReviewRequest->new(client => $self, @_);
+}
+
+1;
diff --git a/extensions/Push/lib/Connector/ReviewBoard/Resource.pm b/extensions/Push/lib/Connector/ReviewBoard/Resource.pm
new file mode 100644
index 000000000..3f8d434ce
--- /dev/null
+++ b/extensions/Push/lib/Connector/ReviewBoard/Resource.pm
@@ -0,0 +1,38 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::Push::Connector::ReviewBoard::Resource;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use URI;
+use Carp qw(croak confess);
+use Scalar::Util qw(blessed);
+
+sub new {
+ my ($class, %params) = @_;
+
+ croak "->new() is a class method" if blessed($class);
+ return bless(\%params, $class);
+}
+
+sub client { $_[0]->{client} }
+
+sub path { confess 'Unimplemented'; }
+
+sub uri {
+ my ($self, @path) = @_;
+
+ my $uri = URI->new($self->client->base_uri);
+ $uri->path(join('/', $self->path, @path) . '/');
+
+ return $uri;
+}
+
+1;
diff --git a/extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm b/extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm
new file mode 100644
index 000000000..32bebfbe8
--- /dev/null
+++ b/extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm
@@ -0,0 +1,28 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::Push::Connector::ReviewBoard::ReviewRequest;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use base 'Bugzilla::Extension::Push::Connector::ReviewBoard::Resource';
+
+# Reference: http://www.reviewboard.org/docs/manual/dev/webapi/2.0/resources/review-request/
+
+sub path {
+ return '/api/review-requests';
+}
+
+sub delete {
+ my ($self, $id) = @_;
+
+ return $self->client->useragent->delete($self->uri($id));
+}
+
+1;