diff options
Diffstat (limited to 'extensions/PhabBugz/lib/Util.pm')
-rw-r--r-- | extensions/PhabBugz/lib/Util.pm | 457 |
1 files changed, 99 insertions, 358 deletions
diff --git a/extensions/PhabBugz/lib/Util.pm b/extensions/PhabBugz/lib/Util.pm index 844d8c0b5..d25f62f68 100644 --- a/extensions/PhabBugz/lib/Util.pm +++ b/extensions/PhabBugz/lib/Util.pm @@ -21,63 +21,26 @@ use Bugzilla::Extension::PhabBugz::Constants; use JSON::XS qw(encode_json decode_json); use List::Util qw(first); use LWP::UserAgent; +use Taint::Util qw(untaint); +use Try::Tiny; use base qw(Exporter); our @EXPORT = qw( - add_comment_to_revision add_security_sync_comments create_revision_attachment - create_private_revision_policy - create_project - edit_revision_policy get_attachment_revisions get_bug_role_phids - get_members_by_bmo_id - get_members_by_phid - get_phab_bmo_ids - get_project_phid - get_revisions_by_ids - get_revisions_by_phids + get_needs_review get_security_sync_groups intersect is_attachment_phab_revision - make_revision_private - make_revision_public request set_phab_user - set_project_members - set_revision_subscribers ); -sub get_revisions_by_ids { - my ($ids) = @_; - return _get_revisions({ ids => $ids }); -} - -sub get_revisions_by_phids { - my ($phids) = @_; - return _get_revisions({ phids => $phids }); -} - -sub _get_revisions { - my ($constraints) = @_; - - my $data = { - queryKey => 'all', - constraints => $constraints - }; - - my $result = request('differential.revision.search', $data); - - ThrowUserError('invalid_phabricator_revision_id') - unless (exists $result->{result}{data} && @{ $result->{result}{data} }); - - return $result->{result}{data}; -} - sub create_revision_attachment { - my ( $bug, $revision, $timestamp ) = @_; + my ( $bug, $revision, $timestamp, $submitter ) = @_; my $phab_base_uri = Bugzilla->params->{phabricator_base_uri}; ThrowUserError('invalid_phabricator_uri') unless $phab_base_uri; @@ -97,22 +60,38 @@ sub create_revision_attachment { ($timestamp) = Bugzilla->dbh->selectrow_array("SELECT NOW()"); } - my $attachment = Bugzilla::Attachment->create( - { - bug => $bug, - creation_ts => $timestamp, - data => $revision_uri, - description => $revision->title, - filename => 'phabricator-D' . $revision->id . '-url.txt', - ispatch => 0, - isprivate => 0, - mimetype => PHAB_CONTENT_TYPE, + # If submitter, then switch to that user when creating attachment + my ($old_user, $attachment); + try { + if ($submitter) { + $old_user = Bugzilla->user; + $submitter->{groups} = [ Bugzilla::Group->get_all ]; # We need to always be able to add attachment + Bugzilla->set_user($submitter); } - ); - # Insert a comment about the new attachment into the database. - $bug->add_comment($revision->summary, { type => CMT_ATTACHMENT_CREATED, - extra_data => $attachment->id }); + $attachment = Bugzilla::Attachment->create( + { + bug => $bug, + creation_ts => $timestamp, + data => $revision_uri, + description => $revision->title, + filename => 'phabricator-D' . $revision->id . '-url.txt', + ispatch => 0, + isprivate => 0, + mimetype => PHAB_CONTENT_TYPE, + } + ); + + # Insert a comment about the new attachment into the database. + $bug->add_comment($revision->summary, { type => CMT_ATTACHMENT_CREATED, + extra_data => $attachment->id }); + } + catch { + die $_; + } + finally { + Bugzilla->set_user($old_user) if $old_user; + }; return $attachment; } @@ -132,321 +111,47 @@ sub get_bug_role_phids { push(@bug_users, $bug->qa_contact) if $bug->qa_contact; push(@bug_users, @{ $bug->cc_users }) if @{ $bug->cc_users }; - return get_members_by_bmo_id(\@bug_users); -} - -sub create_private_revision_policy { - my ($bug, $groups) = @_; - - my $data = { - objectType => 'DREV', - default => 'deny', - policy => [ - { - action => 'allow', - rule => 'PhabricatorSubscriptionsSubscribersPolicyRule', - } - ] - }; - - if(scalar @$groups gt 0) { - my $project_phids = []; - foreach my $group (@$groups) { - my $phid = get_project_phid('bmo-' . $group); - push(@$project_phids, $phid) if $phid; - } - - ThrowUserError('invalid_phabricator_sync_groups') unless @$project_phids; - - push(@{ $data->{policy} }, - { - action => 'allow', - rule => 'PhabricatorProjectsPolicyRule', - value => $project_phids, - } - ); - } - else { - my $secure_revision = Bugzilla::Extension::PhabBugz::Project->new_from_query({ - name => 'secure-revision' - }); - push(@{ $data->{policy} }, - { - action => 'allow', - value => $secure_revision->phid, - } - ); - } - - my $result = request('policy.create', $data); - return $result->{result}{phid}; -} - -sub make_revision_public { - my ($revision_phid) = @_; - return request('differential.revision.edit', { - transactions => [ - { - type => 'view', - value => 'public' - }, - { - type => 'edit', - value => 'users' - } - ], - objectIdentifier => $revision_phid - }); -} - -sub make_revision_private { - my ($revision_phid) = @_; - - my $secure_revision = Bugzilla::Extension::PhabBugz::Project->new_from_query({ - name => 'secure-revision' - }); - - return request('differential.revision.edit', { - transactions => [ - { - type => "view", - value => $secure_revision->phid - }, - { - type => "edit", - value => $secure_revision->phid - } - ], - objectIdentifier => $revision_phid - }); -} - -sub edit_revision_policy { - my ($revision_phid, $policy_phid, $subscribers) = @_; - - my $data = { - transactions => [ - { - type => 'view', - value => $policy_phid - }, - { - type => 'edit', - value => $policy_phid - } - ], - objectIdentifier => $revision_phid - }; - - if (@$subscribers) { - push(@{ $data->{transactions} }, { - type => 'subscribers.set', - value => $subscribers - }); - } - - return request('differential.revision.edit', $data); -} - -sub set_revision_subscribers { - my ($revision_phid, $subscribers) = @_; - - my $data = { - transactions => [ - { - type => 'subscribers.set', - value => $subscribers - } - ], - objectIdentifier => $revision_phid - }; - - return request('differential.revision.edit', $data); -} - -sub add_comment_to_revision { - my ($revision_phid, $comment) = @_; - - my $data = { - transactions => [ - { - type => 'comment', - value => $comment - } - ], - objectIdentifier => $revision_phid - }; - return request('differential.revision.edit', $data); -} - -sub get_project_phid { - my $project = shift; - my $memcache = Bugzilla->memcached; - - # Check memcache - my $project_phid = $memcache->get_config({ key => "phab_project_phid_" . $project }); - if (!$project_phid) { - my $data = { - queryKey => 'all', - constraints => { - name => $project - } - }; - - my $result = request('project.search', $data); - return undef - unless (exists $result->{result}{data} && @{ $result->{result}{data} }); - - $project_phid = $result->{result}{data}[0]{phid}; - $memcache->set_config({ key => "phab_project_phid_" . $project, data => $project_phid }); - } - return $project_phid; -} - -sub create_project { - my ($project, $description, $members) = @_; - - my $secure_revision = Bugzilla::Extension::PhabBugz::Project->new_from_query({ - name => 'secure-revision' - }); - - my $data = { - transactions => [ - { type => 'name', value => $project }, - { type => 'description', value => $description }, - { type => 'edit', value => $secure_revision->phid }. - { type => 'join', value => $secure_revision->phid }, - { type => 'view', value => $secure_revision->phid }, - { type => 'icon', value => 'group' }, - { type => 'color', value => 'red' } - ] - }; - - my $result = request('project.edit', $data); - return $result->{result}{object}{phid}; -} - -sub set_project_members { - my ($project_id, $phab_user_ids) = @_; - - my $data = { - objectIdentifier => $project_id, - transactions => [ - { type => 'members.set', value => $phab_user_ids } - ] - }; - - my $result = request('project.edit', $data); - return $result->{result}{object}{phid}; -} - -sub get_members_by_bmo_id { - my $users = shift; - - my $result = get_phab_bmo_ids({ ids => [ map { $_->id } @$users ] }); - - my @phab_ids; - foreach my $user (@$result) { - push(@phab_ids, $user->{phid}) - if ($user->{phid} && $user->{phid} =~ /^PHID-USER/); - } - - return \@phab_ids; -} - -sub get_members_by_phid { - my $phids = shift; - - my $result = get_phab_bmo_ids({ phids => $phids }); - - my @bmo_ids; - foreach my $user (@$result) { - push(@bmo_ids, $user->{id}) - if ($user->{phid} && $user->{phid} =~ /^PHID-USER/); - } - - return \@bmo_ids; -} - -sub get_phab_bmo_ids { - my ($params) = @_; - my $memcache = Bugzilla->memcached; - - # Try to find the values in memcache first - my @results; - if ($params->{ids}) { - my @bmo_ids = @{ $params->{ids} }; - for (my $i = 0; $i < @bmo_ids; $i++) { - my $phid = $memcache->get({ key => "phab_user_bmo_id_" . $bmo_ids[$i] }); - if ($phid) { - push(@results, { - id => $bmo_ids[$i], - phid => $phid - }); - splice(@bmo_ids, $i, 1); - } - } - $params->{ids} = \@bmo_ids; - } - - if ($params->{phids}) { - my @phids = @{ $params->{phids} }; - for (my $i = 0; $i < @phids; $i++) { - my $bmo_id = $memcache->get({ key => "phab_user_phid_" . $phids[$i] }); - if ($bmo_id) { - push(@results, { - id => $bmo_id, - phid => $phids[$i] - }); - splice(@phids, $i, 1); - } + my $phab_users = + Bugzilla::Extension::PhabBugz::User->match( + { + ids => [ map { $_->id } @bug_users ] } - $params->{phids} = \@phids; - } - - my $result = request('bugzilla.account.search', $params); - - # Store new values in memcache for later retrieval - foreach my $user (@{ $result->{result} }) { - $memcache->set({ key => "phab_user_bmo_id_" . $user->{id}, - value => $user->{phid} }); - $memcache->set({ key => "phab_user_phid_" . $user->{phid}, - value => $user->{id} }); - push(@results, $user); - } + ); - return \@results; + return [ map { $_->phid } @{ $phab_users } ]; } sub is_attachment_phab_revision { my ($attachment) = @_; - return ($attachment->contenttype eq PHAB_CONTENT_TYPE - && $attachment->attacher->login eq PHAB_AUTOMATION_USER) ? 1 : 0; + return $attachment->contenttype eq PHAB_CONTENT_TYPE; } sub get_attachment_revisions { my $bug = shift; - my $revisions; - my @attachments = grep { is_attachment_phab_revision($_) } @{ $bug->attachments() }; - if (@attachments) { - my @revision_ids; - foreach my $attachment (@attachments) { - my ($revision_id) = - ( $attachment->filename =~ PHAB_ATTACHMENT_PATTERN ); - next if !$revision_id; - push( @revision_ids, int($revision_id) ); - } + return unless @attachments; - if (@revision_ids) { - $revisions = get_revisions_by_ids( \@revision_ids ); - } + my @revision_ids; + foreach my $attachment (@attachments) { + my ($revision_id) = + ( $attachment->filename =~ PHAB_ATTACHMENT_PATTERN ); + next if !$revision_id; + push( @revision_ids, int($revision_id) ); } - return @$revisions; + return unless @revision_ids; + + my @revisions; + foreach my $revision_id (@revision_ids) { + push @revisions, Bugzilla::Extension::PhabBugz::Revision->new_from_query({ + ids => [ $revision_id ] + }); + } + + return \@revisions; } sub request { @@ -478,7 +183,12 @@ sub request { if $response->is_error; my $result; - my $result_ok = eval { $result = decode_json( $response->content); 1 }; + my $result_ok = eval { + my $content = $response->content; + untaint($content); + $result = decode_json( $content ); + 1; + }; if (!$result_ok || $result->{error_code}) { ThrowCodeError('phabricator_api_error', { reason => 'JSON decode failure' }) if !$result_ok; @@ -493,9 +203,8 @@ sub request { sub get_security_sync_groups { my $bug = shift; - my $phab_sync_groups = Bugzilla->params->{phabricator_sync_groups} - || ThrowUserError('invalid_phabricator_sync_groups'); - my $sync_group_names = [ split('[,\s]+', $phab_sync_groups) ]; + my $sync_groups = Bugzilla::Group->match( { isactive => 1, isbuggroup => 1 } ); + my $sync_group_names = [ map { $_->name } @$sync_groups ]; my $bug_groups = $bug->groups_in; my $bug_group_names = [ map { $_->name } @$bug_groups ]; @@ -519,7 +228,7 @@ sub add_security_sync_comments { my $phab_error_message = 'Revision is being made private due to unknown Bugzilla groups.'; foreach my $revision (@$revisions) { - add_comment_to_revision( $revision->{phid}, $phab_error_message ); + $revision->add_comment($phab_error_message); } my $num_revisions = scalar @$revisions; @@ -536,4 +245,36 @@ sub add_security_sync_comments { Bugzilla->set_user($old_user); } +sub get_needs_review { + my ($user) = @_; + $user //= Bugzilla->user; + return unless $user->id; + + my $phab_user = Bugzilla::Extension::PhabBugz::User->new_from_query( + { + ids => [ $user->id ] + } + ); + + return [] unless $phab_user; + + my $diffs = request( + 'differential.revision.search', + { + attachments => { + reviewers => 1, + }, + constraints => { + reviewerPHIDs => [$phab_user->phid], + statuses => [qw( needs-review )], + }, + order => 'newest', + } + ); + ThrowCodeError('phabricator_api_error', { reason => 'Malformed Response' }) + unless exists $diffs->{result}{data}; + + return $diffs->{result}{data}; +} + 1; |