getPHID(); if (!$viewer_phid) { return; } if (empty($this->subscribed[$viewer_phid])) { $this->subscribed[$viewer_phid] = array(); } // Load the project PHIDs the user is a member of. We use the omnipotent // user here because projects may themselves have "Subscribers" visibility // policies and we don't want to get stuck in an infinite stack of // recursive policy checks. See T13106. if (!isset($this->sourcePHIDs[$viewer_phid])) { $projects = id(new PhabricatorProjectQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withMemberPHIDs(array($viewer_phid)) ->execute(); $source_phids = mpull($projects, 'getPHID'); $source_phids[] = $viewer_phid; $this->sourcePHIDs[$viewer_phid] = $source_phids; } // Look for transaction hints. foreach ($objects as $key => $object) { $cache = $this->getTransactionHint($object); if ($cache === null) { // We don't have a hint for this object, so we'll deal with it below. continue; } // We have a hint, so use that as the source of truth. unset($objects[$key]); foreach ($this->sourcePHIDs[$viewer_phid] as $source_phid) { if (isset($cache[$source_phid])) { $this->subscribed[$viewer_phid][$object->getPHID()] = true; break; } } } $phids = mpull($objects, 'getPHID'); if (!$phids) { return; } $edge_query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($this->sourcePHIDs[$viewer_phid]) ->withEdgeTypes( array( PhabricatorSubscribedToObjectEdgeType::EDGECONST, )) ->withDestinationPHIDs($phids); $edge_query->execute(); $subscribed = $edge_query->getDestinationPHIDs(); if (!$subscribed) { return; } $this->subscribed[$viewer_phid] += array_fill_keys($subscribed, true); } public function applyRule( PhabricatorUser $viewer, $value, PhabricatorPolicyInterface $object) { $viewer_phid = $viewer->getPHID(); if (!$viewer_phid) { return false; } if ($object->isAutomaticallySubscribed($viewer_phid)) { return true; } $subscribed = idx($this->subscribed, $viewer_phid); return isset($subscribed[$object->getPHID()]); } public function getValueControlType() { return self::CONTROL_TYPE_NONE; } }