@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 128 lines 3.5 kB view raw
1<?php 2 3final class PhabricatorSubscriptionsSubscribersPolicyRule 4 extends PhabricatorPolicyRule { 5 6 private $subscribed = array(); 7 private $sourcePHIDs = array(); 8 9 public function getObjectPolicyKey() { 10 return 'subscriptions.subscribers'; 11 } 12 13 public function getObjectPolicyName() { 14 return pht('Subscribers'); 15 } 16 17 public function getPolicyExplanation() { 18 return pht('Subscribers can take this action.'); 19 } 20 21 public function getRuleDescription() { 22 return pht('subscribers'); 23 } 24 25 public function canApplyToObject(PhabricatorPolicyInterface $object) { 26 return ($object instanceof PhabricatorSubscribableInterface); 27 } 28 29 public function willApplyRules( 30 PhabricatorUser $viewer, 31 array $values, 32 array $objects) { 33 34 // We want to let the user see the object if they're a subscriber or 35 // a member of any project which is a subscriber. Additionally, because 36 // subscriber state is complex, we need to read hints passed from 37 // the TransactionEditor to predict policy state after transactions apply. 38 39 $viewer_phid = $viewer->getPHID(); 40 if (!$viewer_phid) { 41 return; 42 } 43 44 if (empty($this->subscribed[$viewer_phid])) { 45 $this->subscribed[$viewer_phid] = array(); 46 } 47 48 // Load the project PHIDs the user is a member of. We use the omnipotent 49 // user here because projects may themselves have "Subscribers" visibility 50 // policies and we don't want to get stuck in an infinite stack of 51 // recursive policy checks. See T13106. 52 if (!isset($this->sourcePHIDs[$viewer_phid])) { 53 $projects = id(new PhabricatorProjectQuery()) 54 ->setViewer(PhabricatorUser::getOmnipotentUser()) 55 ->withMemberPHIDs(array($viewer_phid)) 56 ->execute(); 57 58 $source_phids = mpull($projects, 'getPHID'); 59 $source_phids[] = $viewer_phid; 60 61 $this->sourcePHIDs[$viewer_phid] = $source_phids; 62 } 63 64 // Look for transaction hints. 65 foreach ($objects as $key => $object) { 66 $cache = $this->getTransactionHint($object); 67 if ($cache === null) { 68 // We don't have a hint for this object, so we'll deal with it below. 69 continue; 70 } 71 72 // We have a hint, so use that as the source of truth. 73 unset($objects[$key]); 74 75 foreach ($this->sourcePHIDs[$viewer_phid] as $source_phid) { 76 if (isset($cache[$source_phid])) { 77 $this->subscribed[$viewer_phid][$object->getPHID()] = true; 78 break; 79 } 80 } 81 } 82 83 $phids = mpull($objects, 'getPHID'); 84 if (!$phids) { 85 return; 86 } 87 88 $edge_query = id(new PhabricatorEdgeQuery()) 89 ->withSourcePHIDs($this->sourcePHIDs[$viewer_phid]) 90 ->withEdgeTypes( 91 array( 92 PhabricatorSubscribedToObjectEdgeType::EDGECONST, 93 )) 94 ->withDestinationPHIDs($phids); 95 96 $edge_query->execute(); 97 98 $subscribed = $edge_query->getDestinationPHIDs(); 99 if (!$subscribed) { 100 return; 101 } 102 103 $this->subscribed[$viewer_phid] += array_fill_keys($subscribed, true); 104 } 105 106 public function applyRule( 107 PhabricatorUser $viewer, 108 $value, 109 PhabricatorPolicyInterface $object) { 110 111 $viewer_phid = $viewer->getPHID(); 112 if (!$viewer_phid) { 113 return false; 114 } 115 116 if ($object->isAutomaticallySubscribed($viewer_phid)) { 117 return true; 118 } 119 120 $subscribed = idx($this->subscribed, $viewer_phid); 121 return isset($subscribed[$object->getPHID()]); 122 } 123 124 public function getValueControlType() { 125 return self::CONTROL_TYPE_NONE; 126 } 127 128}