summaryrefslogtreecommitdiffstats
path: root/extensions/PhabBugz/lib/WebService.pm
blob: 0d88114f6c80b9bb3c6a74b89cefa4e5218ccc38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# 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::PhabBugz::WebService;

use 5.10.1;
use strict;
use warnings;

use base qw(Bugzilla::WebService);

use Bugzilla::Attachment;
use Bugzilla::Bug;
use Bugzilla::BugMail;
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Extension::Push::Util qw(is_public);
use Bugzilla::User;
use Bugzilla::Util qw(correct_urlbase detaint_natural);
use Bugzilla::WebService::Constants;

use Bugzilla::Extension::PhabBugz::Util qw(
    create_revision_attachment
    create_private_revision_policy
    edit_revision_policy
    get_bug_role_phids
    get_project_phid
    get_revisions_by_ids
    intersect
    make_revision_public
    request
);

use MIME::Base64 qw(decode_base64);

use constant PUBLIC_METHODS => qw(
    revision
);

sub revision {
    my ($self, $params) = @_;

    # Phabricator only supports sending credentials via HTTP Basic Auth
    # so we exploit that function to pass in an API key as the password
    # of basic auth. BMO does not support basic auth but does support
    # use of API keys.
    my $http_auth = Bugzilla->cgi->http('Authorization');
    $http_auth =~ s/^Basic\s+//;
    $http_auth = decode_base64($http_auth);
    my ($login, $api_key) = split(':', $http_auth);
    $params->{'Bugzilla_login'} = $login;
    $params->{'Bugzilla_api_key'} = $api_key;

    my $user = Bugzilla->login(LOGIN_REQUIRED);

    unless (defined $params->{revision} && detaint_natural($params->{revision})) {
        ThrowCodeError('param_required', { param => 'revision' })
    }

    # Obtain more information about the revision from Phabricator
    my $revision_id = $params->{revision};
    my @revisions = get_revisions_by_ids([$revision_id]);
    my $revision = $revisions[0];

    my $revision_phid  = $revision->{phid};
    my $revision_title = $revision->{fields}{title} || 'Unknown Description';
    my $bug_id         = $revision->{fields}{'bugzilla.bug-id'};

    my $bug = Bugzilla::Bug->check($bug_id);

    # If bug is public then remove privacy policy
    my $result;
    if (is_public($bug)) {
        $result = make_revision_public($revision_id);
    }
    # else bug is private
    else {
        my $phab_sync_groups = Bugzilla->params->{phabricator_sync_groups}
            || ThrowUserError('invalid_phabricator_sync_groups');
        my $sync_group_names = [ split('[,\s]+', $phab_sync_groups) ];

        my $bug_groups = $bug->groups_in;
        my $bug_group_names = [ map { $_->name } @$bug_groups ];

        my @set_groups = intersect($bug_group_names, $sync_group_names);

        # If bug privacy groups do not have any matching synchronized groups,
        # then leave revision private and it will have be dealt with manually.
        if (!@set_groups) {
            ThrowUserError('invalid_phabricator_sync_groups');
        }

        my $policy_phid = create_private_revision_policy($bug, \@set_groups);
        my $subscribers = get_bug_role_phids($bug);
        $result = edit_revision_policy($revision_phid, $policy_phid, $subscribers);
    }

    my $attachment = create_revision_attachment($bug, $revision_id, $revision_title);

    Bugzilla::BugMail::Send($bug_id, { changer => $user });

    return {
        result          => $result,
        attachment_id   => $attachment->id,
        attachment_link => correct_urlbase() . "attachment.cgi?id=" . $attachment->id
    };
}

sub rest_resources {
    return [
        qr{^/phabbugz/revision/([^/]+)$}, {
            POST => {
                method => 'revision',
                params => sub {
                    return { revision => $_[0] };
                }
            }
        }
    ];
}

1;