When publishing project transactions, load ancestor members

Summary: Ref T10010. Fixes T10107. When we publish a transaction about a project, we perform visibility checks for many different users. We need to know all of the ancestors' members to perform these checks.

Test Plan:
  - Before patch: when updating a subproject, daemons fatal trying to publish things because they can not test visibility of parent projects.
  - After patch: daemons successfully publish subproject updates.
  - Also added a unit test.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10010, T10107

Differential Revision: https://secure.phabricator.com/D15054
This commit is contained in:
epriestley
2016-01-19 09:36:40 -08:00
parent 99ea7082d6
commit c51752b4aa
3 changed files with 83 additions and 28 deletions

View File

@@ -30,6 +30,7 @@ final class PhabricatorProjectQuery
private $needSlugs;
private $needMembers;
private $needAncestorMembers;
private $needWatchers;
private $needImages;
@@ -109,6 +110,11 @@ final class PhabricatorProjectQuery
return $this;
}
public function needAncestorMembers($need_ancestor_members) {
$this->needAncestorMembers = $need_ancestor_members;
return $this;
}
public function needWatchers($need_watchers) {
$this->needWatchers = $need_watchers;
return $this;
@@ -220,8 +226,16 @@ final class PhabricatorProjectQuery
$types[] = $watcher_type;
}
$all_graph = $this->getAllReachableAncestors($projects);
if ($this->needAncestorMembers) {
$src_projects = $all_graph;
} else {
$src_projects = $projects;
}
$all_sources = array();
foreach ($projects as $project) {
foreach ($src_projects as $project) {
if ($project->isMilestone()) {
$phid = $project->getParentProjectPHID();
} else {
@@ -234,10 +248,15 @@ final class PhabricatorProjectQuery
->withSourcePHIDs($all_sources)
->withEdgeTypes($types);
$need_all_edges =
$this->needMembers ||
$this->needWatchers ||
$this->needAncestorMembers;
// If we only need to know if the viewer is a member, we can restrict
// the query to just their PHID.
$any_edges = true;
if (!$this->needMembers && !$this->needWatchers) {
if (!$need_all_edges) {
if ($viewer_phid) {
$edge_query->withDestinationPHIDs(array($viewer_phid));
} else {
@@ -253,7 +272,7 @@ final class PhabricatorProjectQuery
}
$membership_projects = array();
foreach ($projects as $project) {
foreach ($src_projects as $project) {
$project_phid = $project->getPHID();
if ($project->isMilestone()) {
@@ -274,7 +293,7 @@ final class PhabricatorProjectQuery
$membership_projects[$project_phid] = $project;
}
if ($this->needMembers) {
if ($this->needMembers || $this->needAncestorMembers) {
$project->attachMemberPHIDs($member_phids);
}
@@ -289,12 +308,15 @@ final class PhabricatorProjectQuery
}
}
$all_graph = $this->getAllReachableAncestors($projects);
$member_graph = $this->getAllReachableAncestors($membership_projects);
// If we loaded ancestor members, we've already populated membership
// lists above, so we can skip this step.
if (!$this->needAncestorMembers) {
$member_graph = $this->getAllReachableAncestors($membership_projects);
foreach ($all_graph as $phid => $project) {
$is_member = isset($member_graph[$phid]);
$project->setIsUserMember($viewer_phid, $is_member);
foreach ($all_graph as $phid => $project) {
$is_member = isset($member_graph[$phid]);
$project->setIsUserMember($viewer_phid, $is_member);
}
}
return $projects;