@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
1
fork

Configure Feed

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

Make Projects a PhabricatorSubscribableInterface, but with restricted defaults

Summary:
Ref T4379. I want project subscriptions to work like this (yell if this seems whacky, since it makes subscriptions mean somethign a little different for projects than they do for other objects):

- You can only subscribe to a project if you're a project member.
- When you're added as a member, you're added as a subscriber.
- When you're removed as a member, you're removed as a subscriber.
- While you're a member, you can optionally unsubscribe.

From a UI perspective:

- We don't show the subscriber list, since it's going to be some uninteresting subset of the member list.
- We don't show CC transactions in history, since they're an uninteresting near-approximation of the membership transactions.
- You only see the subscription controls if you're a member.

To do this, I've augmented `PhabricatorSubscribableInterface` with two new methods. It would be nice if we were on PHP 5.4+ and could just use traits for this, but we should get data about version usage before we think about this. For now, copy/paste the default implementations into every implementing class.

Then, I implemented the interface in `PhabricatorProject` but with alternate defaults.

Test Plan:
- Used the normal interaction on existing objects.
- This has no actual effect on projects, verified no subscription stuff mysteriously appeared.
- Hit the new error case by fiddling with the UI.

Reviewers: btrahan

Reviewed By: btrahan

CC: chad, aran

Maniphest Tasks: T4379

Differential Revision: https://secure.phabricator.com/D8165

+191 -15
+1
src/__phutil_library_map__.php
··· 4555 4555 0 => 'PhabricatorProjectDAO', 4556 4556 1 => 'PhabricatorFlaggableInterface', 4557 4557 2 => 'PhabricatorPolicyInterface', 4558 + 3 => 'PhabricatorSubscribableInterface', 4558 4559 ), 4559 4560 'PhabricatorProjectBoardController' => 'PhabricatorProjectController', 4560 4561 'PhabricatorProjectBoardEditController' => 'PhabricatorProjectController',
+8
src/applications/files/storage/PhabricatorFile.php
··· 933 933 return ($this->authorPHID == $phid); 934 934 } 935 935 936 + public function shouldShowSubscribersProperty() { 937 + return true; 938 + } 939 + 940 + public function shouldAllowSubscription($phid) { 941 + return true; 942 + } 943 + 936 944 937 945 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 938 946
+8
src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php
··· 64 64 return false; 65 65 } 66 66 67 + public function shouldShowSubscribersProperty() { 68 + return true; 69 + } 70 + 71 + public function shouldAllowSubscription($phid) { 72 + return true; 73 + } 74 + 67 75 68 76 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 69 77
+14 -2
src/applications/legalpad/storage/LegalpadDocument.php
··· 91 91 return 'L'.$this->getID(); 92 92 } 93 93 94 - /* -( PhabricatorSubscribableInterface Implementation )-------------------- */ 94 + 95 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 96 + 95 97 96 98 public function isAutomaticallySubscribed($phid) { 97 99 return ($this->creatorPHID == $phid); 98 100 } 99 101 100 - /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ 102 + public function shouldShowSubscribersProperty() { 103 + return true; 104 + } 105 + 106 + public function shouldAllowSubscription($phid) { 107 + return true; 108 + } 109 + 110 + 111 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 112 + 101 113 102 114 public function getCapabilities() { 103 115 return array(
+8
src/applications/macro/storage/PhabricatorFileImageMacro.php
··· 79 79 return false; 80 80 } 81 81 82 + public function shouldShowSubscribersProperty() { 83 + return true; 84 + } 85 + 86 + public function shouldAllowSubscription($phid) { 87 + return true; 88 + } 89 + 82 90 83 91 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 84 92
+8
src/applications/paste/storage/PhabricatorPaste.php
··· 87 87 return ($this->authorPHID == $phid); 88 88 } 89 89 90 + public function shouldShowSubscribersProperty() { 91 + return true; 92 + } 93 + 94 + public function shouldAllowSubscription($phid) { 95 + return true; 96 + } 97 + 90 98 91 99 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 92 100
+8
src/applications/pholio/storage/PholioMock.php
··· 137 137 return ($this->authorPHID == $phid); 138 138 } 139 139 140 + public function shouldShowSubscribersProperty() { 141 + return true; 142 + } 143 + 144 + public function shouldAllowSubscription($phid) { 145 + return true; 146 + } 147 + 140 148 141 149 /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ 142 150
+18
src/applications/phriction/storage/PhrictionDocument.php
··· 104 104 return $parts[1].'/'; 105 105 } 106 106 107 + 108 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 109 + 110 + 107 111 public function getCapabilities() { 108 112 return array( 109 113 PhabricatorPolicyCapability::CAN_VIEW, ··· 133 137 return null; 134 138 } 135 139 140 + 141 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 142 + 143 + 136 144 public function isAutomaticallySubscribed($phid) { 137 145 return false; 138 146 } 139 147 148 + public function shouldShowSubscribersProperty() { 149 + return true; 150 + } 151 + 152 + public function shouldAllowSubscription($phid) { 153 + return true; 154 + } 155 + 156 + 140 157 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 158 + 141 159 142 160 public function getUsersToNotifyOfTokenGiven() { 143 161 return PhabricatorSubscribersQuery::loadSubscribersForPHID($this->phid);
+7
src/applications/ponder/storage/PonderAnswer.php
··· 188 188 return ($phid == $this->getAuthorPHID()); 189 189 } 190 190 191 + public function shouldShowSubscribersProperty() { 192 + return true; 193 + } 194 + 195 + public function shouldAllowSubscription($phid) { 196 + return true; 197 + } 191 198 192 199 }
+26 -11
src/applications/ponder/storage/PonderQuestion.php
··· 170 170 return $this->getPHID(); 171 171 } 172 172 173 - public function isAutomaticallySubscribed($phid) { 174 - return ($phid == $this->getAuthorPHID()); 175 - } 176 - 177 173 public function save() { 178 174 if (!$this->getMailKey()) { 179 175 $this->setMailKey(Filesystem::readRandomCharacters(20)); 180 176 } 181 177 return parent::save(); 182 178 } 179 + 180 + public function getOriginalTitle() { 181 + // TODO: Make this actually save/return the original title. 182 + return $this->getTitle(); 183 + } 184 + 185 + public function getFullTitle() { 186 + $id = $this->getID(); 187 + $title = $this->getTitle(); 188 + return "Q{$id}: {$title}"; 189 + } 190 + 191 + 192 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 183 193 184 194 public function getCapabilities() { 185 195 return array( ··· 210 220 'The user who asked a question can always view and edit it.'); 211 221 } 212 222 213 - public function getOriginalTitle() { 214 - // TODO: Make this actually save/return the original title. 215 - return $this->getTitle(); 223 + 224 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 225 + 226 + 227 + public function isAutomaticallySubscribed($phid) { 228 + return ($phid == $this->getAuthorPHID()); 216 229 } 217 230 218 - public function getFullTitle() { 219 - $id = $this->getID(); 220 - $title = $this->getTitle(); 221 - return "Q{$id}: {$title}"; 231 + public function shouldShowSubscribersProperty() { 232 + return true; 233 + } 234 + 235 + public function shouldAllowSubscription($phid) { 236 + return true; 222 237 } 223 238 224 239
+1
src/applications/project/controller/PhabricatorProjectProfileController.php
··· 214 214 } 215 215 $view->addAction($action); 216 216 217 + 217 218 $view->addAction( 218 219 id(new PhabricatorActionView()) 219 220 ->setName(pht('View History'))
+19 -2
src/applications/project/storage/PhabricatorProject.php
··· 3 3 final class PhabricatorProject extends PhabricatorProjectDAO 4 4 implements 5 5 PhabricatorFlaggableInterface, 6 - PhabricatorPolicyInterface { 6 + PhabricatorPolicyInterface, 7 + PhabricatorSubscribableInterface { 7 8 8 9 protected $name; 9 10 protected $status = PhabricatorProjectStatus::STATUS_ACTIVE; ··· 15 16 protected $editPolicy; 16 17 protected $joinPolicy; 17 18 18 - private $subprojectsNeedUpdate; 19 19 private $memberPHIDs = self::ATTACHABLE; 20 20 private $sparseMembers = self::ATTACHABLE; 21 21 private $profile = self::ATTACHABLE; ··· 133 133 $slug = $this->getPhrictionSlug(); 134 134 return 'projects/'.$slug; 135 135 } 136 + 137 + 138 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 139 + 140 + 141 + public function isAutomaticallySubscribed($phid) { 142 + return false; 143 + } 144 + 145 + public function shouldShowSubscribersProperty() { 146 + return false; 147 + } 148 + 149 + public function shouldAllowSubscription($phid) { 150 + return false; 151 + } 152 + 136 153 137 154 }
+8
src/applications/slowvote/storage/PhabricatorSlowvotePoll.php
··· 125 125 return ($phid == $this->getAuthorPHID()); 126 126 } 127 127 128 + public function shouldShowSubscribersProperty() { 129 + return true; 130 + } 131 + 132 + public function shouldAllowSubscription($phid) { 133 + return true; 134 + } 135 + 128 136 129 137 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 130 138
+7
src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php
··· 56 56 $handle->getURI()); 57 57 } 58 58 59 + if (!$object->shouldAllowSubscription($user->getPHID())) { 60 + return $this->buildErrorResponse( 61 + pht('You Can Not Subscribe'), 62 + pht('You can not subscribe to this object.'), 63 + $handle->getURI()); 64 + } 65 + 59 66 if ($object instanceof PhabricatorApplicationTransactionInterface) { 60 67 if ($is_add) { 61 68 $xaction_value = array(
+11
src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
··· 33 33 return; 34 34 } 35 35 36 + if (!$object->shouldAllowSubscription($user->getPHID())) { 37 + // This object doesn't allow the viewer to subscribe. 38 + return; 39 + } 40 + 36 41 if ($object->isAutomaticallySubscribed($user->getPHID())) { 37 42 $sub_action = id(new PhabricatorActionView()) 38 43 ->setWorkflow(true) ··· 95 100 // This object isn't subscribable. 96 101 return; 97 102 } 103 + 104 + if (!$object->shouldShowSubscribersProperty()) { 105 + // This object doesn't render subscribers in its property list. 106 + return; 107 + } 108 + 98 109 $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID( 99 110 $object->getPHID()); 100 111 if ($subscribers) {
+39
src/applications/subscriptions/interface/PhabricatorSubscribableInterface.php
··· 13 13 */ 14 14 public function isAutomaticallySubscribed($phid); 15 15 16 + 17 + /** 18 + * Return `true` to indicate that "Subscribers:" should be shown when 19 + * rendering property lists for this object, or `false` to omit the property. 20 + * 21 + * @return bool True to show the "Subscribers:" property. 22 + */ 23 + public function shouldShowSubscribersProperty(); 24 + 25 + 26 + /** 27 + * Return `true` to indicate that the "Subscribe" action should be shown and 28 + * enabled when rendering action lists for this object, or `false` to omit 29 + * the action. 30 + * 31 + * @param phid Viewing or acting user PHID. 32 + * @return bool True to allow the user to subscribe. 33 + */ 34 + public function shouldAllowSubscription($phid); 35 + 16 36 } 37 + 38 + // TEMPLATE IMPLEMENTATION ///////////////////////////////////////////////////// 39 + 40 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 41 + /* 42 + 43 + public function isAutomaticallySubscribed($phid) { 44 + return false; 45 + } 46 + 47 + public function shouldShowSubscribersProperty() { 48 + return true; 49 + } 50 + 51 + public function shouldAllowSubscription($phid) { 52 + return true; 53 + } 54 + 55 + */