@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.

Allow unsubscription from projects

Summary:
Fixes T4379. Several changes:

- Migrate all project members into subscribers.
- When members are added or removed, subscribe or unsubscribe them.
- Show sub/unsub in the UI.
- Determine mailable membership of projects by querying subscribers.

Test Plan:
- As `duck`, joined a project.
- Added the project as a reviewer to a revision.
- Commented on the revision.
- Observed `duck` receive mail.
- Unsubscribed as `duck`.
- Observed no mail.
- Resubscribed as `duck`.
- Mail again.
- Joined/left project, checked sub/unsub status.
- Ran migration, looked at database.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran, asherkin

Maniphest Tasks: T4379

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

+42 -8
+8
resources/sql/autopatches/20140210.projcfield.4.memmig.sql
··· 1 + /* These are here so `grep` will find them if we ever change things: */ 2 + 3 + /* PhabricatorEdgeConfig::TYPE_PROJ_MEMBER = 13 */ 4 + /* PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER = 21 */ 5 + 6 + INSERT IGNORE INTO {$NAMESPACE}_project.edge (src, type, dst, dateCreated) 7 + SELECT src, 21, dst, dateCreated FROM {$NAMESPACE}_project.edge 8 + WHERE type = 13;
+6 -6
src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php
··· 37 37 foreach ($type_map as $type => $phids) { 38 38 switch ($type) { 39 39 case PhabricatorProjectPHIDTypeProject::TYPECONST: 40 - // TODO: For now, project members are always on the "mailing list" 41 - // implied by the project, but we should differentiate members and 42 - // subscribers (i.e., allow you to unsubscribe from mail about 43 - // a project). 40 + // NOTE: We're loading the projects here in order to respect policies. 44 41 45 42 $projects = id(new PhabricatorProjectQuery()) 46 43 ->setViewer($this->getViewer()) 47 - ->needMembers(true) 48 44 ->withPHIDs($phids) 49 45 ->execute(); 50 46 47 + $subscribers = id(new PhabricatorSubscribersQuery()) 48 + ->withObjectPHIDs($phids) 49 + ->execute(); 50 + 51 51 $projects = mpull($projects, null, 'getPHID'); 52 52 foreach ($phids as $phid) { 53 53 $project = idx($projects, $phid); 54 54 if (!$project) { 55 55 $results[$phid] = array(); 56 56 } else { 57 - $results[$phid] = $project->getMemberPHIDs(); 57 + $results[$phid] = idx($subscribers, $phid, array()); 58 58 } 59 59 } 60 60 break;
+27 -1
src/applications/project/editor/PhabricatorProjectTransactionEditor.php
··· 118 118 case PhabricatorTransactions::TYPE_VIEW_POLICY: 119 119 case PhabricatorTransactions::TYPE_EDIT_POLICY: 120 120 case PhabricatorTransactions::TYPE_JOIN_POLICY: 121 - case PhabricatorTransactions::TYPE_EDGE: 122 121 case PhabricatorProjectTransaction::TYPE_STATUS: 123 122 case PhabricatorProjectTransaction::TYPE_IMAGE: 123 + return; 124 + case PhabricatorTransactions::TYPE_EDGE: 125 + switch ($xaction->getMetadataValue('edge:type')) { 126 + case PhabricatorEdgeConfig::TYPE_PROJ_MEMBER: 127 + // When project members are added or removed, add or remove their 128 + // subscriptions. 129 + $old = $xaction->getOldValue(); 130 + $new = $xaction->getNewValue(); 131 + $add = array_keys(array_diff_key($new, $old)); 132 + $rem = array_keys(array_diff_key($old, $new)); 133 + 134 + // NOTE: The subscribe is "explicit" because there's no implicit 135 + // unsubscribe, so Join -> Leave -> Join doesn't resubscribe you 136 + // if we use an implicit subscribe, even though you never willfully 137 + // unsubscribed. Not sure if adding implicit unsubscribe (which 138 + // would not write the unsubscribe row) is justified to deal with 139 + // this, which is a fairly weird edge case and pretty arguable both 140 + // ways. 141 + 142 + id(new PhabricatorSubscriptionsEditor()) 143 + ->setActor($this->requireActor()) 144 + ->setObject($object) 145 + ->subscribeExplicit($add) 146 + ->unsubscribe($rem) 147 + ->save(); 148 + break; 149 + } 124 150 return; 125 151 } 126 152
+1 -1
src/applications/project/storage/PhabricatorProject.php
··· 171 171 } 172 172 173 173 public function shouldAllowSubscription($phid) { 174 - return false; 174 + return $this->isUserMember($phid); 175 175 } 176 176 177 177