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

If users are on the email to Phabricator, do not send them the Phabricator reply.

Summary: When we receive an email, figure out if any of the other tos and ccs are users. If they are, pass their phids through the stach as "exclude phids" and exclude them from getting the email.

Test Plan: used the various applications (audit, differential, maniphest) and noted emails were sent as expected.

Reviewers: epriestley, vrana

Reviewed By: vrana

CC: aran, Korvin, vrana

Maniphest Tasks: T1676

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

+302 -292
+14
src/__phutil_library_map__.php
··· 668 668 'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php', 669 669 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', 670 670 'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php', 671 + 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 671 672 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', 672 673 'PhabricatorEmailTokenController' => 'applications/auth/controller/PhabricatorEmailTokenController.php', 673 674 'PhabricatorEmailVerificationController' => 'applications/people/controller/PhabricatorEmailVerificationController.php', ··· 1450 1451 'DifferentialChangesetParserTestCase' => 'ArcanistPhutilTestCase', 1451 1452 'DifferentialChangesetViewController' => 'DifferentialController', 1452 1453 'DifferentialComment' => 'DifferentialDAO', 1454 + 'DifferentialCommentEditor' => 'PhabricatorEditor', 1453 1455 'DifferentialCommentMail' => 'DifferentialMail', 1454 1456 'DifferentialCommentPreviewController' => 'DifferentialController', 1455 1457 'DifferentialCommentSaveController' => 'DifferentialController', ··· 1507 1509 'DifferentialRevisionCommentView' => 'AphrontView', 1508 1510 'DifferentialRevisionDetailView' => 'AphrontView', 1509 1511 'DifferentialRevisionEditController' => 'DifferentialController', 1512 + 'DifferentialRevisionEditor' => 'PhabricatorEditor', 1510 1513 'DifferentialRevisionIDFieldParserTestCase' => 'PhabricatorTestCase', 1511 1514 'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification', 1512 1515 'DifferentialRevisionListController' => 'DifferentialController', ··· 1714 1717 1 => 'PhabricatorMarkupInterface', 1715 1718 ), 1716 1719 'ManiphestTransactionDetailView' => 'ManiphestView', 1720 + 'ManiphestTransactionEditor' => 'PhabricatorEditor', 1717 1721 'ManiphestTransactionListView' => 'ManiphestView', 1718 1722 'ManiphestTransactionPreviewController' => 'ManiphestController', 1719 1723 'ManiphestTransactionSaveController' => 'ManiphestController', ··· 1765 1769 'PhabricatorApplicationsListController' => 'PhabricatorController', 1766 1770 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', 1767 1771 'PhabricatorAuditComment' => 'PhabricatorAuditDAO', 1772 + 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', 1768 1773 'PhabricatorAuditCommitListView' => 'AphrontView', 1769 1774 'PhabricatorAuditController' => 'PhabricatorController', 1770 1775 'PhabricatorAuditDAO' => 'PhabricatorLiskDAO', ··· 1839 1844 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 1840 1845 'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants', 1841 1846 'PhabricatorEdgeCycleException' => 'Exception', 1847 + 'PhabricatorEdgeEditor' => 'PhabricatorEditor', 1842 1848 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', 1843 1849 'PhabricatorEdgeQuery' => 'PhabricatorQuery', 1844 1850 'PhabricatorEdgeTestCase' => 'PhabricatorTestCase', ··· 2083 2089 'PhabricatorProjectController' => 'PhabricatorController', 2084 2090 'PhabricatorProjectCreateController' => 'PhabricatorProjectController', 2085 2091 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 2092 + 'PhabricatorProjectEditor' => 'PhabricatorEditor', 2086 2093 'PhabricatorProjectEditorTestCase' => 'PhabricatorTestCase', 2087 2094 'PhabricatorProjectListController' => 'PhabricatorProjectController', 2088 2095 'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController', ··· 2202 2209 'PhabricatorStorageManagementWorkflow' => 'PhutilArgumentWorkflow', 2203 2210 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 2204 2211 'PhabricatorSubscriptionsEditController' => 'PhabricatorController', 2212 + 'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor', 2205 2213 'PhabricatorSubscriptionsUIEventListener' => 'PhutilEventListener', 2206 2214 'PhabricatorSymbolNameLinter' => 'ArcanistXHPASTLintNamingHook', 2207 2215 'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon', ··· 2229 2237 1 => 'PhutilPerson', 2230 2238 ), 2231 2239 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 2240 + 'PhabricatorUserEditor' => 'PhabricatorEditor', 2232 2241 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 2233 2242 'PhabricatorUserLDAPInfo' => 'PhabricatorUserDAO', 2234 2243 'PhabricatorUserLog' => 'PhabricatorUserDAO', ··· 2304 2313 'PhrictionDiffController' => 'PhrictionController', 2305 2314 'PhrictionDocument' => 'PhrictionDAO', 2306 2315 'PhrictionDocumentController' => 'PhrictionController', 2316 + 'PhrictionDocumentEditor' => 'PhabricatorEditor', 2307 2317 'PhrictionDocumentPreviewController' => 'PhrictionController', 2308 2318 'PhrictionDocumentStatus' => 'PhrictionConstants', 2309 2319 'PhrictionDocumentTestCase' => 'PhabricatorTestCase', ··· 2318 2328 1 => 'PhabricatorMarkupInterface', 2319 2329 2 => 'PonderVotableInterface', 2320 2330 ), 2331 + 'PonderAnswerEditor' => 'PhabricatorEditor', 2321 2332 'PonderAnswerListView' => 'AphrontView', 2322 2333 'PonderAnswerPreviewController' => 'PonderController', 2323 2334 'PonderAnswerQuery' => 'PhabricatorOffsetPagedQuery', ··· 2329 2340 0 => 'PonderDAO', 2330 2341 1 => 'PhabricatorMarkupInterface', 2331 2342 ), 2343 + 'PonderCommentEditor' => 'PhabricatorEditor', 2332 2344 'PonderCommentListView' => 'AphrontView', 2333 2345 'PonderCommentMail' => 'PonderMail', 2334 2346 'PonderCommentQuery' => 'PhabricatorQuery', ··· 2347 2359 ), 2348 2360 'PonderQuestionAskController' => 'PonderController', 2349 2361 'PonderQuestionDetailView' => 'AphrontView', 2362 + 'PonderQuestionEditor' => 'PhabricatorEditor', 2350 2363 'PonderQuestionPreviewController' => 'PonderController', 2351 2364 'PonderQuestionQuery' => 'PhabricatorOffsetPagedQuery', 2352 2365 'PonderQuestionSummaryView' => 'AphrontView', ··· 2355 2368 'PonderRuleQuestion' => 'PhabricatorRemarkupRuleObjectName', 2356 2369 'PonderUserProfileView' => 'AphrontView', 2357 2370 'PonderVotableView' => 'AphrontView', 2371 + 'PonderVoteEditor' => 'PhabricatorEditor', 2358 2372 'PonderVoteSaveController' => 'PonderController', 2359 2373 'QueryFormattingTestCase' => 'PhabricatorTestCase', 2360 2374 ),
+3 -1
src/applications/audit/PhabricatorAuditReplyHandler.php
··· 61 61 ->setContent($mail->getCleanTextBody()); 62 62 63 63 $editor = new PhabricatorAuditCommentEditor($commit); 64 - $editor->setUser($actor); 64 + $editor->setActor($actor); 65 + $editor->setExcludeMailRecipientPHIDs( 66 + $this->getExcludeMailRecipientPHIDs()); 65 67 $editor->addComment($comment); 66 68 } 67 69
+1 -1
src/applications/audit/controller/PhabricatorAuditAddCommentController.php
··· 61 61 } 62 62 63 63 id(new PhabricatorAuditCommentEditor($commit)) 64 - ->setUser($user) 64 + ->setActor($user) 65 65 ->setAttachInlineComments(true) 66 66 ->addAuditors($auditors) 67 67 ->addCCs($ccs)
+33 -40
src/applications/audit/editor/PhabricatorAuditCommentEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - final class PhabricatorAuditCommentEditor { 19 + final class PhabricatorAuditCommentEditor extends PhabricatorEditor { 20 20 21 21 private $commit; 22 - private $user; 23 22 24 23 private $attachInlineComments; 25 24 private $auditors = array(); ··· 27 26 28 27 public function __construct(PhabricatorRepositoryCommit $commit) { 29 28 $this->commit = $commit; 30 - return $this; 31 - } 32 - 33 - public function setUser(PhabricatorUser $user) { 34 - $this->user = $user; 35 29 return $this; 36 30 } 37 31 ··· 53 47 public function addComment(PhabricatorAuditComment $comment) { 54 48 55 49 $commit = $this->commit; 56 - $user = $this->user; 50 + $actor = $this->getActor(); 57 51 58 52 $other_comments = id(new PhabricatorAuditComment())->loadAllWhere( 59 53 'targetPHID = %s', ··· 64 58 $inline_comments = id(new PhabricatorAuditInlineComment())->loadAllWhere( 65 59 'authorPHID = %s AND commitPHID = %s 66 60 AND auditCommentID IS NULL', 67 - $user->getPHID(), 61 + $actor->getPHID(), 68 62 $commit->getPHID()); 69 63 } 70 64 71 65 $comment 72 - ->setActorPHID($user->getPHID()) 66 + ->setActorPHID($actor->getPHID()) 73 67 ->setTargetPHID($commit->getPHID()) 74 68 ->save(); 75 69 ··· 106 100 $ccs = array_merge($ccs, $metacc); 107 101 } 108 102 109 - // When a user submits an audit comment, we update all the audit requests 103 + // When an actor submits an audit comment, we update all the audit requests 110 104 // they have authority over to reflect the most recent status. The general 111 105 // idea here is that if audit has triggered for, e.g., several packages, but 112 106 // a user owns all of them, they can clear the audit requirement in one go 113 107 // without auditing the commit for each trigger. 114 108 115 - $audit_phids = self::loadAuditPHIDsForUser($this->user); 109 + $audit_phids = self::loadAuditPHIDsForUser($actor); 116 110 $audit_phids = array_fill_keys($audit_phids, true); 117 111 118 112 $requests = id(new PhabricatorRepositoryAuditRequest()) ··· 128 122 // and handle the no-effect cases (e.g., closing and already-closed audit). 129 123 130 124 131 - $user_is_author = ($user->getPHID() == $commit->getAuthorPHID()); 125 + $actor_is_author = ($actor->getPHID() == $commit->getAuthorPHID()); 132 126 133 127 if ($action == PhabricatorAuditActionConstants::CLOSE) { 134 128 // "Close" means wipe out all the concerns. ··· 144 138 // user row (never package/project rows), and always affects the user 145 139 // row (other actions don't, if they were able to affect a package/project 146 140 // row). 147 - $user_request = null; 141 + $actor_request = null; 148 142 foreach ($requests as $request) { 149 - if ($request->getAuditorPHID() == $user->getPHID()) { 150 - $user_request = $request; 143 + if ($request->getAuditorPHID() == $actor->getPHID()) { 144 + $actor_request = $request; 151 145 break; 152 146 } 153 147 } 154 - if (!$user_request) { 155 - $user_request = id(new PhabricatorRepositoryAuditRequest()) 148 + if (!$actor_request) { 149 + $actor_request = id(new PhabricatorRepositoryAuditRequest()) 156 150 ->setCommitPHID($commit->getPHID()) 157 - ->setAuditorPHID($user->getPHID()) 151 + ->setAuditorPHID($actor->getPHID()) 158 152 ->setAuditReasons(array("Resigned")); 159 153 } 160 154 161 - $user_request 155 + $actor_request 162 156 ->setAuditStatus(PhabricatorAuditStatusConstants::RESIGNED) 163 157 ->save(); 164 158 165 - $requests[] = $user_request; 159 + $requests[] = $actor_request; 166 160 } else { 167 161 $have_any_requests = false; 168 162 foreach ($requests as $request) { ··· 170 164 continue; 171 165 } 172 166 173 - $request_is_for_user = ($request->getAuditorPHID() == $user->getPHID()); 167 + $request_is_for_actor = 168 + ($request->getAuditorPHID() == $actor->getPHID()); 174 169 175 170 $have_any_requests = true; 176 171 $new_status = null; ··· 181 176 // Commenting or adding cc's/auditors doesn't change status. 182 177 break; 183 178 case PhabricatorAuditActionConstants::ACCEPT: 184 - if (!$user_is_author || $request_is_for_user) { 179 + if (!$actor_is_author || $request_is_for_actor) { 185 180 // When modifying your own commits, you act only on behalf of 186 181 // yourself, not your packages/projects -- the idea being that 187 182 // you can't accept your own commits. ··· 189 184 } 190 185 break; 191 186 case PhabricatorAuditActionConstants::CONCERN: 192 - if (!$user_is_author || $request_is_for_user) { 187 + if (!$actor_is_author || $request_is_for_actor) { 193 188 // See above. 194 189 $new_status = PhabricatorAuditStatusConstants::CONCERNED; 195 190 } ··· 203 198 } 204 199 } 205 200 206 - // If the user has no current authority over any audit trigger, make a 201 + // If the actor has no current authority over any audit trigger, make a 207 202 // new one to represent their audit state. 208 203 if (!$have_any_requests) { 209 204 $new_status = null; ··· 227 222 228 223 $request = id(new PhabricatorRepositoryAuditRequest()) 229 224 ->setCommitPHID($commit->getPHID()) 230 - ->setAuditorPHID($user->getPHID()) 225 + ->setAuditorPHID($actor->getPHID()) 231 226 ->setAuditStatus($new_status) 232 227 ->setAuditReasons(array("Voluntary Participant")) 233 228 ->save(); ··· 270 265 ->setAuditorPHID($auditor_phid) 271 266 ->setAuditStatus($audit_requested) 272 267 ->setAuditReasons( 273 - array('Added by ' . $user->getUsername())) 268 + array('Added by ' . $actor->getUsername())) 274 269 ->save(); 275 270 } 276 271 } ··· 283 278 ->setAuditorPHID($cc_phid) 284 279 ->setAuditStatus($audit_cc) 285 280 ->setAuditReasons( 286 - array('Added by ' . $user->getUsername())) 281 + array('Added by ' . $actor->getUsername())) 287 282 ->save(); 288 283 } 289 284 } ··· 322 317 } 323 318 324 319 // The user can audit on behalf of all projects they are a member of. 325 - $query = new PhabricatorProjectQuery(); 326 - 327 - // TODO: As above. 328 - $query->setViewer($user); 329 - 330 - $query->withMemberPHIDs(array($user->getPHID())); 331 - $projects = $query->execute(); 320 + $projects = id(new PhabricatorProjectQuery()) 321 + ->setViewer($user) 322 + ->withMemberPHIDs(array($user->getPHID())) 323 + ->execute(); 332 324 foreach ($projects as $project) { 333 325 $phids[$project->getPHID()] = true; 334 326 } ··· 341 333 array $more_phids) { 342 334 343 335 $commit = $this->commit; 344 - $user = $this->user; 336 + $actor = $this->getActor(); 345 337 346 338 $related_phids = array_merge( 347 339 array( 348 - $user->getPHID(), 340 + $actor->getPHID(), 349 341 $commit->getPHID(), 350 342 ), 351 343 $more_phids); 352 344 353 345 id(new PhabricatorFeedStoryPublisher()) 354 346 ->setRelatedPHIDs($related_phids) 355 - ->setStoryAuthorPHID($user->getPHID()) 347 + ->setStoryAuthorPHID($actor->getPHID()) 356 348 ->setStoryTime(time()) 357 349 ->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_AUDIT) 358 350 ->setStoryData( ··· 445 437 ->setThreadID($thread_id, $is_new) 446 438 ->addHeader('Thread-Topic', $thread_topic) 447 439 ->setRelatedPHID($commit->getPHID()) 440 + ->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs()) 448 441 ->setIsBulk(true) 449 442 ->setBody($body); 450 443 ··· 484 477 assert_instances_of($inline_comments, 'PhabricatorInlineCommentInterface'); 485 478 486 479 $commit = $this->commit; 487 - $user = $this->user; 488 - $name = $user->getUsername(); 480 + $actor = $this->getActor(); 481 + $name = $actor->getUsername(); 489 482 490 483 $verb = PhabricatorAuditActionConstants::getActionPastTenseVerb( 491 484 $comment->getAction());
+1 -1
src/applications/conduit/method/differential/ConduitAPI_differential_close_Method.php
··· 63 63 64 64 $editor = new DifferentialCommentEditor( 65 65 $revision, 66 - $request->getUser()->getPHID(), 67 66 DifferentialAction::ACTION_CLOSE); 67 + $editor->setActor($request->getUser()); 68 68 $editor->save(); 69 69 70 70 $revision->setStatus(ArcanistDifferentialRevisionStatus::CLOSED);
+1 -1
src/applications/conduit/method/differential/ConduitAPI_differential_createcomment_Method.php
··· 63 63 64 64 $editor = new DifferentialCommentEditor( 65 65 $revision, 66 - $request->getUser()->getPHID(), 67 66 $action); 67 + $editor->setActor($request->getUser()); 68 68 $editor->setContentSource($content_source); 69 69 $editor->setMessage($request->getValue('message')); 70 70 $editor->setNoEmail($request->getValue('silent'));
+1 -1
src/applications/conduit/method/differential/ConduitAPI_differential_createrevision_Method.php
··· 54 54 $revision = DifferentialRevisionEditor::newRevisionFromConduitWithDiff( 55 55 $fields, 56 56 $diff, 57 - $request->getUser()->getPHID()); 57 + $request->getUser()); 58 58 59 59 return array( 60 60 'revisionid' => $revision->getID(),
+1 -1
src/applications/conduit/method/differential/ConduitAPI_differential_markcommitted_Method.php
··· 67 67 68 68 $editor = new DifferentialCommentEditor( 69 69 $revision, 70 - $request->getUser()->getPHID(), 71 70 DifferentialAction::ACTION_CLOSE); 71 + $editor->setActor($request->getUser()); 72 72 $editor->save(); 73 73 } 74 74
+2 -2
src/applications/conduit/method/differential/ConduitAPI_differential_updaterevision_Method.php
··· 72 72 array()); 73 73 74 74 $editor = new DifferentialRevisionEditor( 75 - $revision, 76 - $revision->getAuthorPHID()); 75 + $revision); 76 + $editor->setActor($request->getUser()); 77 77 $editor->setContentSource($content_source); 78 78 $fields = $request->getValue('fields'); 79 79 $editor->copyFieldsFromConduit($fields);
+1
src/applications/conduit/method/maniphest/ConduitAPI_maniphest_Method.php
··· 196 196 $transactions = $event->getValue('transactions'); 197 197 198 198 $editor = new ManiphestTransactionEditor(); 199 + $editor->setActor($request->getUser()); 199 200 $editor->applyTransactions($task, $transactions); 200 201 201 202 $event = new PhabricatorEvent(
+1 -1
src/applications/conduit/method/phriction/ConduitAPI_phriction_edit_Method.php
··· 48 48 $slug = $request->getValue('slug'); 49 49 50 50 $editor = id(PhrictionDocumentEditor::newForSlug($slug)) 51 - ->setUser($request->getUser()) 51 + ->setActor($request->getUser()) 52 52 ->setTitle($request->getValue('title')) 53 53 ->setContent($request->getValue('content')) 54 54 ->setDescription($request->getvalue('description'))
+3 -1
src/applications/differential/DifferentialReplyHandler.php
··· 138 138 try { 139 139 $editor = new DifferentialCommentEditor( 140 140 $this->getMailReceiver(), 141 - $actor->getPHID(), 142 141 $command); 142 + $editor->setActor($actor); 143 + $editor->setExcludeMailRecipientPHIDs( 144 + $this->getExcludeMailRecipientPHIDs()); 143 145 144 146 // NOTE: We have to be careful about this because Facebook's 145 147 // implementation jumps straight into handleAction() and will not have
+1 -1
src/applications/differential/controller/DifferentialCommentSaveController.php
··· 37 37 38 38 $editor = new DifferentialCommentEditor( 39 39 $revision, 40 - $request->getUser()->getPHID(), 41 40 $action); 42 41 43 42 $content_source = PhabricatorContentSource::newForSource( ··· 48 47 49 48 try { 50 49 $editor 50 + ->setActor($request->getUser()) 51 51 ->setMessage($comment) 52 52 ->setContentSource($content_source) 53 53 ->setAttachInlineComments(true)
+2 -3
src/applications/differential/controller/DifferentialRevisionEditController.php
··· 62 62 63 63 64 64 if ($request->isFormPost() && !$request->getStr('viaDiffView')) { 65 - $user_phid = $request->getUser()->getPHID(); 66 - 67 65 foreach ($aux_fields as $aux_field) { 68 66 $aux_field->setValueFromRequest($request); 69 67 try { ··· 74 72 } 75 73 76 74 if (!$errors) { 77 - $editor = new DifferentialRevisionEditor($revision, $user_phid); 75 + $editor = new DifferentialRevisionEditor($revision); 76 + $editor->setActor($request->getUser()); 78 77 if ($diff) { 79 78 $editor->addDiff($diff, $request->getStr('comments')); 80 79 }
+25 -26
src/applications/differential/editor/DifferentialCommentEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - final class DifferentialCommentEditor { 19 + final class DifferentialCommentEditor extends PhabricatorEditor { 20 20 21 21 protected $revision; 22 - protected $actorPHID; 23 22 protected $action; 24 23 25 24 protected $attachInlineComments; ··· 37 36 38 37 public function __construct( 39 38 DifferentialRevision $revision, 40 - $actor_phid, 41 39 $action) { 42 40 43 41 $this->revision = $revision; 44 - $this->actorPHID = $actor_phid; 45 42 $this->action = $action; 46 43 } 47 44 ··· 112 109 } 113 110 114 111 public function save() { 115 - $revision = $this->revision; 116 - $action = $this->action; 117 - $actor_phid = $this->actorPHID; 118 - $actor = id(new PhabricatorUser())->loadOneWhere('PHID = %s', $actor_phid); 119 - $actor_is_author = ($actor_phid == $revision->getAuthorPHID()); 120 - $allow_self_accept = PhabricatorEnv::getEnvConfig( 112 + $actor = $this->requireActor(); 113 + $revision = $this->revision; 114 + $action = $this->action; 115 + $actor_phid = $actor->getPHID(); 116 + $actor_is_author = ($actor_phid == $revision->getAuthorPHID()); 117 + $allow_self_accept = PhabricatorEnv::getEnvConfig( 121 118 'differential.allow-self-accept', false); 122 119 $always_allow_close = PhabricatorEnv::getEnvConfig( 123 120 'differential.always-allow-close', false); 124 - $revision_status = $revision->getStatus(); 121 + $revision_status = $revision->getStatus(); 125 122 126 123 $revision->loadRelationships(); 127 124 $reviewer_phids = $revision->getReviewers(); ··· 135 132 if ($this->attachInlineComments) { 136 133 $inline_comments = id(new DifferentialInlineComment())->loadAllWhere( 137 134 'authorPHID = %s AND revisionID = %d AND commentID IS NULL', 138 - $this->actorPHID, 135 + $actor_phid, 139 136 $revision->getID()); 140 137 } 141 138 ··· 414 411 DifferentialRevisionEditor::addCC( 415 412 $revision, 416 413 $cc, 417 - $this->actorPHID); 414 + $actor_phid); 418 415 } 419 416 420 417 $key = DifferentialComment::METADATA_ADDED_CCS; ··· 490 487 if ($action != DifferentialAction::ACTION_RESIGN) { 491 488 DifferentialRevisionEditor::addCC( 492 489 $revision, 493 - $this->actorPHID, 494 - $this->actorPHID); 490 + $actor_phid, 491 + $actor_phid); 495 492 } 496 493 497 494 $comment = id(new DifferentialComment()) 498 - ->setAuthorPHID($this->actorPHID) 495 + ->setAuthorPHID($actor_phid) 499 496 ->setRevisionID($revision->getID()) 500 497 ->setAction($action) 501 498 ->setContent((string)$this->message) ··· 541 538 DifferentialRevisionEditor::addCC( 542 539 $revision, 543 540 $cc_phid, 544 - $this->actorPHID); 541 + $actor_phid); 545 542 $metacc[] = $cc_phid; 546 543 } 547 544 $metadata[DifferentialComment::METADATA_ADDED_CCS] = $metacc; ··· 553 550 554 551 $revision->saveTransaction(); 555 552 556 - $phids = array($this->actorPHID); 553 + $phids = array($actor_phid); 557 554 $handles = id(new PhabricatorObjectHandleData($phids)) 558 555 ->loadHandles(); 559 - $actor_handle = $handles[$this->actorPHID]; 556 + $actor_handle = $handles[$actor_phid]; 560 557 561 558 $xherald_header = HeraldTranscript::loadXHeraldRulesHeader( 562 559 $revision->getPHID()); ··· 568 565 $comment, 569 566 $changesets, 570 567 $inline_comments)) 568 + ->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs()) 571 569 ->setToPHIDs( 572 570 array_merge( 573 571 $revision->getReviewers(), ··· 586 584 'revision_author_phid' => $revision->getAuthorPHID(), 587 585 'action' => $comment->getAction(), 588 586 'feedback_content' => $comment->getContent(), 589 - 'actor_phid' => $this->actorPHID, 587 + 'actor_phid' => $actor_phid, 590 588 ); 591 589 id(new PhabricatorTimelineEvent('difx', $event_data)) 592 590 ->recordEvent(); ··· 596 594 ->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_DIFFERENTIAL) 597 595 ->setStoryData($event_data) 598 596 ->setStoryTime(time()) 599 - ->setStoryAuthorPHID($this->actorPHID) 597 + ->setStoryAuthorPHID($actor_phid) 600 598 ->setRelatedPHIDs( 601 599 array( 602 600 $revision->getPHID(), 603 - $this->actorPHID, 601 + $actor_phid, 604 602 $revision->getAuthorPHID(), 605 603 )) 606 604 ->setPrimaryObjectPHID($revision->getPHID()) ··· 642 640 } 643 641 644 642 private function alterReviewers() { 645 - $revision = $this->revision; 646 - $added_reviewers = $this->getAddedReviewers(); 643 + $actor_phid = $this->getActor()->getPHID(); 644 + $revision = $this->revision; 645 + $added_reviewers = $this->getAddedReviewers(); 647 646 $removed_reviewers = $this->getRemovedReviewers(); 648 - $reviewer_phids = $revision->getReviewers(); 647 + $reviewer_phids = $revision->getReviewers(); 649 648 650 649 $reviewer_phids_map = array_fill_keys($reviewer_phids, true); 651 650 foreach ($added_reviewers as $k => $user_phid) { ··· 672 671 $reviewer_phids, 673 672 $removed_reviewers, 674 673 $added_reviewers, 675 - $this->actorPHID); 674 + $actor_phid); 676 675 } 677 676 678 677 return array($added_reviewers, $removed_reviewers);
+8 -14
src/applications/differential/editor/DifferentialRevisionEditor.php
··· 21 21 * reviewers, diffs, and CCs. Unlike simple edits, these changes trigger 22 22 * complicated email workflows. 23 23 */ 24 - final class DifferentialRevisionEditor { 24 + final class DifferentialRevisionEditor extends PhabricatorEditor { 25 25 26 26 protected $revision; 27 - protected $actorPHID; 28 27 29 28 protected $cc = null; 30 29 protected $reviewers = null; ··· 35 34 private $auxiliaryFields = array(); 36 35 private $contentSource; 37 36 38 - public function __construct(DifferentialRevision $revision, $actor_phid) { 37 + public function __construct(DifferentialRevision $revision) { 39 38 $this->revision = $revision; 40 - $this->actorPHID = $actor_phid; 41 39 } 42 40 43 41 public static function newRevisionFromConduitWithDiff( 44 42 array $fields, 45 43 DifferentialDiff $diff, 46 - $user_phid) { 44 + PhabricatorUser $actor) { 47 45 48 46 $revision = new DifferentialRevision(); 49 47 $revision->setPHID($revision->generatePHID()); 50 - 51 - $revision->setAuthorPHID($user_phid); 48 + $revision->setAuthorPHID($actor->getPHID()); 52 49 $revision->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW); 53 50 54 - $editor = new DifferentialRevisionEditor($revision, $user_phid); 55 - 51 + $editor = new DifferentialRevisionEditor($revision); 52 + $editor->setActor($actor); 56 53 $editor->copyFieldsFromConduit($fields); 57 54 58 55 $editor->addDiff($diff, null); ··· 63 60 64 61 public function copyFieldsFromConduit(array $fields) { 65 62 63 + $actor = $this->getActor(); 66 64 $revision = $this->revision; 67 65 $revision->loadRelationships(); 68 66 69 67 $aux_fields = DifferentialFieldSelector::newSelector() 70 68 ->getFieldSpecifications(); 71 69 72 - $user = id(new PhabricatorUser())->loadOneWhere( 73 - 'phid = %s', 74 - $this->actorPHID); 75 - 76 70 foreach ($aux_fields as $key => $aux_field) { 77 71 $aux_field->setRevision($revision); 78 - $aux_field->setUser($user); 72 + $aux_field->setUser($actor); 79 73 if (!$aux_field->shouldAppearOnCommitMessage()) { 80 74 unset($aux_fields[$key]); 81 75 }
+1 -1
src/applications/differential/field/specification/DifferentialFreeformFieldSpecification.php
··· 102 102 } 103 103 104 104 id(new PhabricatorEdgeEditor()) 105 - ->setUser($user) 105 + ->setActor($user) 106 106 ->addEdge( 107 107 $task->getPHID(), 108 108 PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT,
+1 -1
src/applications/differential/field/specification/DifferentialManiphestTasksFieldSpecification.php
··· 74 74 $rem_phids = array_diff($old_phids, $add_phids); 75 75 76 76 $edge_editor = id(new PhabricatorEdgeEditor()) 77 - ->setUser($this->getUser()); 77 + ->setActor($this->getUser()); 78 78 79 79 foreach ($add_phids as $phid) { 80 80 $edge_editor->addEdge($revision_phid, $edge_type, $phid);
+13 -23
src/applications/differential/mail/DifferentialMail.php
··· 20 20 21 21 protected $to = array(); 22 22 protected $cc = array(); 23 + protected $excludePHIDs = array(); 23 24 24 25 protected $actorHandle; 25 26 ··· 91 92 $template 92 93 ->setIsHTML($this->shouldMarkMailAsHTML()) 93 94 ->setParentMessageID($this->parentMessageID) 95 + ->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs()) 94 96 ->addHeader('Thread-Topic', $this->getThreadTopic()); 95 97 96 98 $template->setAttachments($attachments); ··· 315 317 return implode("\n", $text); 316 318 } 317 319 318 - public function setToPHIDs(array $to) { 319 - $this->to = $this->filterContactPHIDs($to); 320 + public function setExcludeMailRecipientPHIDs(array $exclude) { 321 + $this->excludePHIDs = $exclude; 320 322 return $this; 321 323 } 322 324 323 - public function setCCPHIDs(array $cc) { 324 - $this->cc = $this->filterContactPHIDs($cc); 325 + public function getExcludeMailRecipientPHIDs() { 326 + return $this->excludePHIDs; 327 + } 328 + 329 + public function setToPHIDs(array $to) { 330 + $this->to = $to; 325 331 return $this; 326 332 } 327 333 328 - protected function filterContactPHIDs(array $phids) { 329 - return $phids; 330 - 331 - // TODO: actually do this? 332 - 333 - // Differential revisions use Subscriptions for CCs, so any arbitrary 334 - // PHID can end up CC'd to them. Only try to actually send email PHIDs 335 - // which have ToolsHandle types that are marked emailable. If we don't 336 - // filter here, sending the email will fail. 337 - /* 338 - $handles = array(); 339 - prep(new ToolsHandleData($phids, $handles)); 340 - foreach ($handles as $phid => $handle) { 341 - if (!$handle->isEmailable()) { 342 - unset($handles[$phid]); 343 - } 344 - } 345 - return array_keys($handles); 346 - */ 334 + public function setCCPHIDs(array $cc) { 335 + $this->cc = $cc; 336 + return $this; 347 337 } 348 338 349 339 protected function getToPHIDs() {
+1 -1
src/applications/diffusion/controller/DiffusionCommitEditController.php
··· 51 51 $rem_proj_phids = array_diff($current_proj_phids, 52 52 $new_proj_phids); 53 53 $editor = id(new PhabricatorEdgeEditor()); 54 - $editor->setUser($user); 54 + $editor->setActor($user); 55 55 foreach ($rem_proj_phids as $phid) { 56 56 $editor->removeEdge($commit_phid, $edge_type, $phid); 57 57 }
+3
src/applications/maniphest/ManiphestReplyHandler.php
··· 167 167 168 168 169 169 $editor = new ManiphestTransactionEditor(); 170 + $editor->setActor($user); 170 171 $editor->setParentMessageID($mail->getMessageID()); 172 + $editor->setExcludeMailRecipientPHIDs( 173 + $this->getExcludeMailRecipientPHIDs()); 171 174 $editor->applyTransactions($task, $xactions); 172 175 173 176 $event = new PhabricatorEvent(
+1
src/applications/maniphest/controller/ManiphestBatchEditController.php
··· 41 41 $xactions = $this->buildTransactions($actions, $task); 42 42 if ($xactions) { 43 43 $editor = new ManiphestTransactionEditor(); 44 + $editor->setActor($user); 44 45 $editor->applyTransactions($task, $xactions); 45 46 } 46 47 }
+1
src/applications/maniphest/controller/ManiphestSubpriorityController.php
··· 59 59 $xaction->setNewValue($after_pri); 60 60 61 61 $editor = new ManiphestTransactionEditor(); 62 + $editor->setActor($request->getUser()); 62 63 $editor->applyTransactions($task, array($xaction)); 63 64 } 64 65
+1
src/applications/maniphest/controller/ManiphestTaskEditController.php
··· 231 231 $transactions = $event->getValue('transactions'); 232 232 233 233 $editor = new ManiphestTransactionEditor(); 234 + $editor->setActor($user); 234 235 $editor->setAuxiliaryFields($aux_fields); 235 236 $editor->applyTransactions($task, $transactions); 236 237
+1
src/applications/maniphest/controller/ManiphestTransactionSaveController.php
··· 244 244 $transactions = $event->getValue('transactions'); 245 245 246 246 $editor = new ManiphestTransactionEditor(); 247 + $editor->setActor($user); 247 248 $editor->applyTransactions($task, $transactions); 248 249 249 250 $draft = id(new PhabricatorDraft())->loadOneWhere(
+13 -1
src/applications/maniphest/editor/ManiphestTransactionEditor.php
··· 19 19 /** 20 20 * @group maniphest 21 21 */ 22 - final class ManiphestTransactionEditor { 22 + final class ManiphestTransactionEditor extends PhabricatorEditor { 23 23 24 24 private $parentMessageID; 25 + private $excludePHIDs = array(); 25 26 private $auxiliaryFields = array(); 26 27 27 28 public function setAuxiliaryFields(array $fields) { ··· 33 34 public function setParentMessageID($parent_message_id) { 34 35 $this->parentMessageID = $parent_message_id; 35 36 return $this; 37 + } 38 + 39 + public function setExcludePHIDs(array $exclude) { 40 + $this->excludePHIDs = $exclude; 41 + return $this; 42 + } 43 + 44 + public function getExcludePHIDs() { 45 + return $this->excludePHIDs; 36 46 } 37 47 38 48 public function applyTransactions(ManiphestTask $task, array $transactions) { ··· 221 231 } 222 232 223 233 private function sendEmail($task, $transactions, $email_to, $email_cc) { 234 + $exclude = $this->getExcludePHIDs(); 224 235 $email_to = array_filter(array_unique($email_to)); 225 236 $email_cc = array_filter(array_unique($email_cc)); 226 237 ··· 276 287 ->addHeader('Thread-Topic', "T{$task_id}: ".$task->getOriginalTitle()) 277 288 ->setThreadID($thread_id, $is_create) 278 289 ->setRelatedPHID($task->getPHID()) 290 + ->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs()) 279 291 ->setIsBulk(true) 280 292 ->setMailTags($mailtags) 281 293 ->setBody($body->render());
+1
src/applications/maniphest/event/ManiphestEdgeEventListener.php
··· 73 73 74 74 $new_edges = $this->loadAllEdges($event); 75 75 $editor = new ManiphestTransactionEditor(); 76 + $editor->setActor($event->getUser()); 76 77 77 78 foreach ($tasks as $phid => $task) { 78 79 $xactions = array();
+10
src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
··· 20 20 21 21 private $mailReceiver; 22 22 private $actor; 23 + private $excludePHIDs = array(); 23 24 24 25 final public function setMailReceiver($mail_receiver) { 25 26 $this->validateMailReceiver($mail_receiver); ··· 38 39 39 40 final public function getActor() { 40 41 return $this->actor; 42 + } 43 + 44 + final public function setExcludeMailRecipientPHIDs(array $exclude) { 45 + $this->excludePHIDs = $exclude; 46 + return $this; 47 + } 48 + 49 + final public function getExcludeMailRecipientPHIDs() { 50 + return $this->excludePHIDs; 41 51 } 42 52 43 53 abstract public function validateMailReceiver($mail_receiver);
+11 -1
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 36 36 protected $nextRetry; 37 37 protected $relatedPHID; 38 38 39 + private $excludePHIDs = array(); 40 + 39 41 public function __construct() { 40 42 41 43 $this->status = self::STATUS_QUEUE; ··· 117 119 $phids = array_unique($phids); 118 120 $this->setParam('cc', $phids); 119 121 return $this; 122 + } 123 + 124 + public function setExcludeMailRecipientPHIDs($exclude) { 125 + $this->excludePHIDs = $exclude; 126 + return $this; 127 + } 128 + private function getExcludeMailRecipientPHIDs() { 129 + return $this->excludePHIDs; 120 130 } 121 131 122 132 public function getTranslation(array $objects) { ··· 349 359 350 360 $this->loadEmailAndNameDataFromPHIDs($phids); 351 361 352 - $exclude = array(); 362 + $exclude = array_fill_keys($this->getExcludeMailRecipientPHIDs(), true); 353 363 354 364 $params = $this->parameters; 355 365 $default = PhabricatorEnv::getEnvConfig('metamta.default-address');
+23
src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php
··· 62 62 return $this->getRawEmailAddresses(idx($this->headers, 'to')); 63 63 } 64 64 65 + private function loadExcludeMailRecipientPHIDs() { 66 + $addresses = array_merge( 67 + $this->getToAddresses(), 68 + $this->getCCAddresses() 69 + ); 70 + 71 + $users = id(new PhabricatorUserEmail()) 72 + ->loadAllWhere('address IN (%Ls)', $addresses); 73 + $user_phids = mpull($users, 'getUserPHID'); 74 + 75 + $mailing_lists = id(new PhabricatorMetaMTAMailingList()) 76 + ->loadAllWhere('email in (%Ls)', $addresses); 77 + $mailing_list_phids = mpull($mailing_lists, 'getPHID'); 78 + 79 + return array_merge($user_phids, $mailing_list_phids); 80 + } 81 + 65 82 /** 66 83 * Parses "to" addresses, looking for a public create email address 67 84 * first and if not found parsing the "to" address for reply handler ··· 182 199 $receiver->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); 183 200 184 201 $editor = new ManiphestTransactionEditor(); 202 + $editor->setActor($user); 185 203 $handler = $editor->buildReplyHandler($receiver); 186 204 187 205 $handler->setActor($user); 206 + $handler->setExcludeMailRecipientPHIDs( 207 + $this->loadExcludeMailRecipientPHIDs()); 188 208 $handler->processEmail($this); 189 209 190 210 $this->setRelatedPHID($receiver->getPHID()); ··· 248 268 249 269 if ($receiver instanceof ManiphestTask) { 250 270 $editor = new ManiphestTransactionEditor(); 271 + $editor->setActor($user); 251 272 $handler = $editor->buildReplyHandler($receiver); 252 273 } else if ($receiver instanceof DifferentialRevision) { 253 274 $handler = DifferentialMail::newReplyHandlerForRevision($receiver); ··· 257 278 } 258 279 259 280 $handler->setActor($user); 281 + $handler->setExcludeMailRecipientPHIDs( 282 + $this->loadExcludeMailRecipientPHIDs()); 260 283 $handler->processEmail($this); 261 284 262 285 $this->setMessage('OK');
+6 -30
src/applications/people/PhabricatorUserEditor.php
··· 26 26 * @task email Adding, Removing and Changing Email 27 27 * @task internal Internals 28 28 */ 29 - final class PhabricatorUserEditor { 29 + final class PhabricatorUserEditor extends PhabricatorEditor { 30 30 31 - private $actor; 32 31 private $logs = array(); 33 32 34 33 35 - /* -( Configuration )------------------------------------------------------ */ 36 - 37 - 38 - /** 39 - * @task config 40 - */ 41 - public function setActor(PhabricatorUser $actor) { 42 - $this->actor = $actor; 43 - return $this; 44 - } 45 - 46 - 47 34 /* -( Creating and Editing Users )----------------------------------------- */ 48 35 49 36 ··· 88 75 } 89 76 90 77 $log = PhabricatorUserLog::newLog( 91 - $this->actor, 78 + $this->getActor(), 92 79 $user, 93 80 PhabricatorUserLog::ACTION_CREATE); 94 81 $log->setNewValue($email->getAddress()); ··· 147 134 $user->save(); 148 135 149 136 $log = PhabricatorUserLog::newLog( 150 - $this->actor, 137 + $this->getActor(), 151 138 $user, 152 139 PhabricatorUserLog::ACTION_CHANGE_PASSWORD); 153 140 $log->save(); ··· 186 173 } 187 174 188 175 $log = PhabricatorUserLog::newLog( 189 - $this->actor, 176 + $actor, 190 177 $user, 191 178 PhabricatorUserLog::ACTION_CHANGE_USERNAME); 192 179 $log->setOldValue($old_username); ··· 429 416 } 430 417 431 418 $log = PhabricatorUserLog::newLog( 432 - $this->actor, 419 + $actor, 433 420 $user, 434 421 PhabricatorUserLog::ACTION_EMAIL_ADD); 435 422 $log->setNewValue($email->getAddress()); ··· 474 461 $email->delete(); 475 462 476 463 $log = PhabricatorUserLog::newLog( 477 - $this->actor, 464 + $actor, 478 465 $user, 479 466 PhabricatorUserLog::ACTION_EMAIL_REMOVE); 480 467 $log->setOldValue($email->getAddress()); ··· 551 538 552 539 553 540 /* -( Internals )---------------------------------------------------------- */ 554 - 555 - 556 - /** 557 - * @task internal 558 - */ 559 - private function requireActor() { 560 - if (!$this->actor) { 561 - throw new Exception("User edit requires actor!"); 562 - } 563 - return $this->actor; 564 - } 565 541 566 542 567 543 /**
+2 -2
src/applications/phame/controller/blog/PhameBlogDeleteController.php
··· 88 88 $blogger_phids = array_keys($blogger_edges); 89 89 $post_edges = $edges[$blog_phid][$post_edge_type]; 90 90 $post_phids = array_keys($post_edges); 91 - $editor = id(new PhabricatorEdgeEditor()); 92 - $editor->setUser($user); 91 + $editor = id(new PhabricatorEdgeEditor()) 92 + ->setActor($user); 93 93 foreach ($blogger_phids as $phid) { 94 94 $editor->removeEdge($blog_phid, $blogger_edge_type, $phid); 95 95 }
+1 -1
src/applications/phame/controller/blog/PhameBlogEditController.php
··· 163 163 $rem_phids = array_diff($old_bloggers, $new_bloggers); 164 164 $editor = new PhabricatorEdgeEditor(); 165 165 $edge_type = PhabricatorEdgeConfig::TYPE_BLOG_HAS_BLOGGER; 166 - $editor->setUser($user); 166 + $editor->setActor($user); 167 167 foreach ($add_phids as $phid) { 168 168 $editor->addEdge($blog->getPHID(), $edge_type, $phid); 169 169 }
+2 -2
src/applications/phame/controller/post/PhamePostDeleteController.php
··· 62 62 63 63 $blog_edges = $edges[$post_phid][$edge_type]; 64 64 $blog_phids = array_keys($blog_edges); 65 - $editor = id(new PhabricatorEdgeEditor()); 66 - $editor->setUser($user); 65 + $editor = id(new PhabricatorEdgeEditor()) 66 + ->setActor($user); 67 67 foreach ($blog_phids as $phid) { 68 68 $editor->removeEdge($post_phid, $edge_type, $phid); 69 69 }
+1 -1
src/applications/phame/controller/post/PhamePostEditController.php
··· 198 198 199 199 $editor = new PhabricatorEdgeEditor(); 200 200 $edge_type = PhabricatorEdgeConfig::TYPE_POST_HAS_BLOG; 201 - $editor->setUser($user); 201 + $editor->setActor($user); 202 202 foreach ($blogs_to_publish as $phid) { 203 203 $editor->addEdge($post->getPHID(), $edge_type, $phid); 204 204 }
+1 -1
src/applications/phriction/controller/PhrictionDeleteController.php
··· 41 41 42 42 if ($request->isFormPost()) { 43 43 $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug())) 44 - ->setUser($user) 44 + ->setActor($user) 45 45 ->delete(); 46 46 return id(new AphrontRedirectResponse())->setURI($document_uri); 47 47 }
+1 -1
src/applications/phriction/controller/PhrictionEditController.php
··· 134 134 135 135 if (!count($errors)) { 136 136 $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug())) 137 - ->setUser($user) 137 + ->setActor($user) 138 138 ->setTitle($title) 139 139 ->setContent($request->getStr('content')) 140 140 ->setDescription($notes);
+6 -17
src/applications/phriction/editor/PhrictionDocumentEditor.php
··· 21 21 * 22 22 * @group phriction 23 23 */ 24 - final class PhrictionDocumentEditor { 24 + final class PhrictionDocumentEditor extends PhabricatorEditor { 25 25 26 26 private $document; 27 27 private $content; 28 - 29 - private $user; 30 28 31 29 private $newTitle; 32 30 private $newContent; ··· 65 63 return $obj; 66 64 } 67 65 68 - public function setUser(PhabricatorUser $user) { 69 - $this->user = $user; 70 - return $this; 71 - } 72 - 73 66 public function setTitle($title) { 74 67 $this->newTitle = $title; 75 68 return $this; ··· 90 83 } 91 84 92 85 public function delete() { 93 - if (!$this->user) { 94 - throw new Exception("Call setUser() before deleting a document!"); 95 - } 86 + $actor = $this->requireActor(); 96 87 97 88 // TODO: Should we do anything about deleting an already-deleted document? 98 89 // We currently allow it. ··· 109 100 } 110 101 111 102 public function save() { 112 - if (!$this->user) { 113 - throw new Exception("Call setUser() before updating a document!"); 114 - } 103 + $actor = $this->requireActor(); 115 104 116 105 if ($this->newContent === '') { 117 106 // If this is an edit which deletes all the content, just treat it as ··· 134 123 135 124 $new_content = new PhrictionContent(); 136 125 $new_content->setSlug($document->getSlug()); 137 - $new_content->setAuthorPHID($this->user->getPHID()); 126 + $new_content->setAuthorPHID($this->getActor()->getPHID()); 138 127 $new_content->setChangeType(PhrictionChangeType::CHANGE_EDIT); 139 128 140 129 $new_content->setTitle( ··· 214 203 215 204 $related_phids = array( 216 205 $document->getPHID(), 217 - $this->user->getPHID(), 206 + $this->getActor()->getPHID(), 218 207 ); 219 208 220 209 if ($project_phid) { ··· 223 212 224 213 id(new PhabricatorFeedStoryPublisher()) 225 214 ->setRelatedPHIDs($related_phids) 226 - ->setStoryAuthorPHID($this->user->getPHID()) 215 + ->setStoryAuthorPHID($this->getActor()->getPHID()) 227 216 ->setStoryTime(time()) 228 217 ->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PHRICTION) 229 218 ->setStoryData(
+1 -1
src/applications/ponder/controller/PonderAnswerSaveController.php
··· 60 60 ->setContentSource($content_source); 61 61 62 62 id(new PonderAnswerEditor()) 63 - ->setUser($user) 63 + ->setActor($user) 64 64 ->setQuestion($question) 65 65 ->setAnswer($res) 66 66 ->saveAnswer();
+1 -1
src/applications/ponder/controller/PonderCommentSaveController.php
··· 61 61 ->setQuestion($question) 62 62 ->setComment($res) 63 63 ->setTargetPHID($target) 64 - ->setUser($user) 64 + ->setActor($user) 65 65 ->save(); 66 66 67 67 return id(new AphrontRedirectResponse())
+1 -1
src/applications/ponder/controller/PonderQuestionAskController.php
··· 53 53 54 54 id(new PonderQuestionEditor()) 55 55 ->setQuestion($question) 56 - ->setUser($user) 56 + ->setActor($user) 57 57 ->save(); 58 58 59 59 return id(new AphrontRedirectResponse())
+1 -1
src/applications/ponder/controller/PonderVoteSaveController.php
··· 49 49 50 50 $editor = id(new PonderVoteEditor()) 51 51 ->setVotable($target) 52 - ->setUser($user) 52 + ->setActor($user) 53 53 ->setVote($newvote) 54 54 ->saveVote(); 55 55
+6 -14
src/applications/ponder/editor/PonderAnswerEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - final class PonderAnswerEditor { 19 + final class PonderAnswerEditor extends PhabricatorEditor { 20 + 20 21 private $question; 21 22 private $answer; 22 - private $viewer; 23 23 private $shouldEmail = true; 24 24 25 25 public function setQuestion($question) { ··· 32 32 return $this; 33 33 } 34 34 35 - public function setUser(PhabricatorUser $user) { 36 - $this->viewer = $user; 37 - return $this; 38 - } 39 - 40 35 public function saveAnswer() { 41 - if (!$this->viewer) { 42 - throw new Exception("Must set user before saving question"); 43 - } 36 + $actor = $this->requireActor(); 44 37 if (!$this->question) { 45 38 throw new Exception("Must set question before saving answer"); 46 39 } ··· 50 43 51 44 $question = $this->question; 52 45 $answer = $this->answer; 53 - $viewer = $this->viewer; 54 46 $conn = $answer->establishConnection('w'); 55 47 $trans = $conn->openTransaction(); 56 48 $trans->beginReadLocking(); ··· 76 68 // subscribe author and @mentions 77 69 $subeditor = id(new PhabricatorSubscriptionsEditor()) 78 70 ->setObject($question) 79 - ->setUser($viewer); 71 + ->setActor($actor); 80 72 81 73 $subeditor->subscribeExplicit(array($answer->getAuthorPHID())); 82 74 ··· 98 90 id(new PonderMentionMail( 99 91 $question, 100 92 $answer, 101 - $viewer)) 93 + $actor)) 102 94 ->setToPHIDs($at_mention_phids) 103 95 ->send(); 104 96 } ··· 115 107 id(new PonderAnsweredMail( 116 108 $question, 117 109 $answer, 118 - $viewer)) 110 + $actor)) 119 111 ->setToPHIDs($other_subs) 120 112 ->send(); 121 113 }
+5 -15
src/applications/ponder/editor/PonderCommentEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - 20 - final class PonderCommentEditor { 19 + final class PonderCommentEditor extends PhabricatorEditor { 21 20 22 21 private $question; 23 22 private $comment; 24 23 private $targetPHID; 25 - private $viewer; 26 24 private $shouldEmail = true; 27 25 28 26 public function setComment(PonderComment $comment) { ··· 40 38 return $this; 41 39 } 42 40 43 - public function setUser(PhabricatorUser $user) { 44 - $this->viewer = $user; 45 - return $this; 46 - } 47 - 48 41 public function save() { 42 + $actor = $this->requireActor(); 49 43 if (!$this->comment) { 50 44 throw new Exception("Must set comment before saving it"); 51 45 } ··· 55 49 if (!$this->targetPHID) { 56 50 throw new Exception("Must set target before saving comment"); 57 51 } 58 - if (!$this->viewer) { 59 - throw new Exception("Must set viewer before saving comment"); 60 - } 61 52 62 53 $comment = $this->comment; 63 54 $question = $this->question; 64 55 $target = $this->targetPHID; 65 - $viewer = $this->viewer; 66 56 $comment->save(); 67 57 68 58 $question->attachRelated(); ··· 71 61 // subscribe author and @mentions 72 62 $subeditor = id(new PhabricatorSubscriptionsEditor()) 73 63 ->setObject($question) 74 - ->setUser($viewer); 64 + ->setActor($actor); 75 65 76 66 $subeditor->subscribeExplicit(array($comment->getAuthorPHID())); 77 67 ··· 92 82 id(new PonderMentionMail( 93 83 $question, 94 84 $comment, 95 - $viewer)) 85 + $actor)) 96 86 ->setToPHIDs($at_mention_phids) 97 87 ->send(); 98 88 } ··· 124 114 id(new PonderCommentMail( 125 115 $question, 126 116 $comment, 127 - $viewer)) 117 + $actor)) 128 118 ->setToPHIDs($other_subs) 129 119 ->send(); 130 120 }
+4 -14
src/applications/ponder/editor/PonderQuestionEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - 20 - final class PonderQuestionEditor { 19 + final class PonderQuestionEditor extends PhabricatorEditor { 21 20 22 21 private $question; 23 - private $viewer; 24 22 private $shouldEmail = true; 25 23 26 24 public function setQuestion(PonderQuestion $question) { 27 25 $this->question = $question; 28 - return $this; 29 - } 30 - 31 - public function setUser(PhabricatorUser $user) { 32 - $this->viewer = $user; 33 26 return $this; 34 27 } 35 28 ··· 39 32 } 40 33 41 34 public function save() { 42 - if (!$this->viewer) { 43 - throw new Exception("Must set user before saving question"); 44 - } 35 + $actor = $this->requireActor(); 45 36 if (!$this->question) { 46 37 throw new Exception("Must set question before saving it"); 47 38 } 48 39 49 - $viewer = $this->viewer; 50 40 $question = $this->question; 51 41 $question->save(); 52 42 ··· 57 47 // subscribe author and @mentions 58 48 $subeditor = id(new PhabricatorSubscriptionsEditor()) 59 49 ->setObject($question) 60 - ->setUser($viewer); 50 + ->setActor($actor); 61 51 62 52 $subeditor->subscribeExplicit(array($question->getAuthorPHID())); 63 53 ··· 72 62 id(new PonderMentionMail( 73 63 $question, 74 64 $question, 75 - $viewer)) 65 + $actor)) 76 66 ->setToPHIDs($at_mention_phids) 77 67 ->send(); 78 68 }
+6 -16
src/applications/ponder/editor/PonderVoteEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - 20 - final class PonderVoteEditor { 19 + final class PonderVoteEditor extends PhabricatorEditor { 21 20 22 21 private $answer; 23 22 private $votable; 24 23 private $anwer; 25 - private $user; 26 24 private $vote; 27 25 28 26 public function setAnswer($answer) { ··· 35 33 return $this; 36 34 } 37 35 38 - public function setUser($user) { 39 - $this->user = $user; 40 - return $this; 41 - } 42 - 43 36 public function setVote($vote) { 44 37 $this->vote = $vote; 45 38 return $this; 46 39 } 47 40 48 41 public function saveVote() { 42 + $actor = $this->requireActor(); 49 43 if (!$this->votable) { 50 44 throw new Exception("Must set votable before saving vote"); 51 45 } 52 - if (!$this->user) { 53 - throw new Exception("Must set user before saving vote"); 54 - } 55 46 56 - $user = $this->user; 57 47 $votable = $this->votable; 58 48 $newvote = $this->vote; 59 49 60 50 // prepare vote add, or update if this user is amending an 61 51 // earlier vote 62 52 $editor = id(new PhabricatorEdgeEditor()) 63 - ->setUser($user) 53 + ->setActor($actor) 64 54 ->addEdge( 65 - $user->getPHID(), 55 + $actor->getPHID(), 66 56 $votable->getUserVoteEdgeType(), 67 57 $votable->getVotablePHID(), 68 58 array('data' => $newvote)) 69 59 ->removeEdge( 70 - $user->getPHID(), 60 + $actor->getPHID(), 71 61 $votable->getUserVoteEdgeType(), 72 62 $votable->getVotablePHID()); 73 63 ··· 77 67 78 68 $votable->reload(); 79 69 $curvote = (int)PhabricatorEdgeQuery::loadSingleEdgeData( 80 - $user->getPHID(), 70 + $actor->getPHID(), 81 71 $votable->getUserVoteEdgeType(), 82 72 $votable->getVotablePHID()); 83 73
+1 -1
src/applications/project/controller/PhabricatorProjectCreateController.php
··· 49 49 $xactions[] = $xaction; 50 50 51 51 $editor = new PhabricatorProjectEditor($project); 52 - $editor->setUser($user); 52 + $editor->setActor($user); 53 53 $editor->applyTransactions($xactions); 54 54 } catch (PhabricatorProjectNameCollisionException $ex) { 55 55 $e_name = 'Not Unique';
+1 -1
src/applications/project/controller/PhabricatorProjectMembersEditController.php
··· 80 80 81 81 if ($xactions) { 82 82 $editor = new PhabricatorProjectEditor($project); 83 - $editor->setUser($user); 83 + $editor->setActor($user); 84 84 $editor->applyTransactions($xactions); 85 85 } 86 86
+1 -1
src/applications/project/controller/PhabricatorProjectProfileEditController.php
··· 92 92 $xactions[] = $xaction; 93 93 94 94 $editor = new PhabricatorProjectEditor($project); 95 - $editor->setUser($user); 95 + $editor->setActor($user); 96 96 $editor->applyTransactions($xactions); 97 97 } catch (PhabricatorProjectNameCollisionException $ex) { 98 98 $e_name = 'Not Unique';
+12 -21
src/applications/project/editor/PhabricatorProjectEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - final class PhabricatorProjectEditor { 19 + final class PhabricatorProjectEditor extends PhabricatorEditor { 20 20 21 21 private $project; 22 - private $user; 23 22 private $projectName; 24 23 25 24 private $addEdges = array(); ··· 65 64 $xaction->setNewValue($new_value); 66 65 67 66 $editor = new PhabricatorProjectEditor($project); 68 - $editor->setUser($user); 67 + $editor->setActor($user); 69 68 $editor->applyTransactions(array($xaction)); 70 69 } 71 70 72 71 73 72 public function __construct(PhabricatorProject $project) { 74 73 $this->project = $project; 75 - } 76 - 77 - public function setUser(PhabricatorUser $user) { 78 - $this->user = $user; 79 - return $this; 80 74 } 81 75 82 76 public function applyTransactions(array $transactions) { 83 77 assert_instances_of($transactions, 'PhabricatorProjectTransaction'); 84 - if (!$this->user) { 85 - throw new Exception('Call setUser() before save()!'); 86 - } 87 - $user = $this->user; 78 + $actor = $this->requireActor(); 88 79 89 80 $project = $this->project; 90 81 91 82 $is_new = !$project->getID(); 92 83 93 84 if ($is_new) { 94 - $project->setAuthorPHID($user->getPHID()); 85 + $project->setAuthorPHID($actor->getPHID()); 95 86 } 96 87 97 88 foreach ($transactions as $key => $xaction) { ··· 105 96 if (!$is_new) { 106 97 // You must be able to view a project in order to edit it in any capacity. 107 98 PhabricatorPolicyFilter::requireCapability( 108 - $user, 99 + $actor, 109 100 $project, 110 101 PhabricatorPolicyCapability::CAN_VIEW); 111 102 ··· 122 113 123 114 if ($need_edit) { 124 115 PhabricatorPolicyFilter::requireCapability( 125 - $user, 116 + $actor, 126 117 $project, 127 118 PhabricatorPolicyCapability::CAN_EDIT); 128 119 } 129 120 130 121 if ($need_join) { 131 122 PhabricatorPolicyFilter::requireCapability( 132 - $user, 123 + $actor, 133 124 $project, 134 125 PhabricatorPolicyCapability::CAN_JOIN); 135 126 } ··· 149 140 150 141 $edge_type = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER; 151 142 $editor = new PhabricatorEdgeEditor(); 152 - $editor->setUser($this->user); 143 + $editor->setActor($actor); 153 144 foreach ($this->remEdges as $phid) { 154 145 $editor->removeEdge($project->getPHID(), $edge_type, $phid); 155 146 } ··· 159 150 $editor->save(); 160 151 161 152 foreach ($transactions as $xaction) { 162 - $xaction->setAuthorPHID($user->getPHID()); 153 + $xaction->setAuthorPHID($actor->getPHID()); 163 154 $xaction->setProjectID($project->getID()); 164 155 $xaction->save(); 165 156 } ··· 278 269 279 270 // You can't edit away your ability to edit the project. 280 271 PhabricatorPolicyFilter::mustRetainCapability( 281 - $this->user, 272 + $this->getActor(), 282 273 $project, 283 274 PhabricatorPolicyCapability::CAN_EDIT); 284 275 break; ··· 369 360 if (count($add) > 1) { 370 361 return null; 371 362 } else if (count($add) == 1) { 372 - if (reset($add) != $this->user->getPHID()) { 363 + if (reset($add) != $this->getActor()->getPHID()) { 373 364 return null; 374 365 } else { 375 366 return 'join'; ··· 379 370 if (count($rem) > 1) { 380 371 return null; 381 372 } else if (count($rem) == 1) { 382 - if (reset($rem) != $this->user->getPHID()) { 373 + if (reset($rem) != $this->getActor()->getPHID()) { 383 374 return null; 384 375 } else { 385 376 return 'leave';
+1 -1
src/applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php
··· 114 114 $xaction->setNewValue($new_name); 115 115 116 116 $editor = new PhabricatorProjectEditor($proj); 117 - $editor->setUser($user); 117 + $editor->setActor($user); 118 118 $editor->applyTransactions(array($xaction)); 119 119 120 120 return true;
+3 -1
src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
··· 122 122 $committer_phid, 123 123 $author_phid, 124 124 $revision->getAuthorPHID()); 125 + $actor = id(new PhabricatorUser()) 126 + ->loadOneWhere('phid = %s', $actor_phid); 125 127 126 128 $diff = $this->attachToRevision($revision, $actor_phid); 127 129 128 130 $revision->setDateCommitted($commit->getEpoch()); 129 131 $editor = new DifferentialCommentEditor( 130 132 $revision, 131 - $actor_phid, 132 133 DifferentialAction::ACTION_CLOSE); 134 + $editor->setActor($actor); 133 135 $editor->setIsDaemonWorkflow(true); 134 136 135 137 $vs_diff = $this->loadChangedByCommit($diff);
+2 -1
src/applications/search/controller/PhabricatorSearchAttachController.php
··· 78 78 $rem_phids = array_diff($old_phids, $add_phids); 79 79 80 80 $editor = id(new PhabricatorEdgeEditor()); 81 - $editor->setUser($user); 81 + $editor->setActor($user); 82 82 foreach ($add_phids as $phid) { 83 83 $editor->addEdge($this->phid, $edge_type, $phid); 84 84 } ··· 159 159 } 160 160 161 161 $editor = new ManiphestTransactionEditor(); 162 + $editor->setActor($user); 162 163 163 164 $task_names = array(); 164 165
+1 -1
src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php
··· 74 74 } 75 75 76 76 $editor = id(new PhabricatorSubscriptionsEditor()) 77 - ->setUser($user) 77 + ->setActor($user) 78 78 ->setObject($object); 79 79 80 80 if ($is_add) {
+3 -12
src/applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - final class PhabricatorSubscriptionsEditor { 19 + final class PhabricatorSubscriptionsEditor extends PhabricatorEditor { 20 20 21 21 private $object; 22 - private $user; 23 22 24 23 private $explicitSubscribePHIDs = array(); 25 24 private $implicitSubscribePHIDs = array(); ··· 30 29 return $this; 31 30 } 32 31 33 - public function setUser(PhabricatorUser $user) { 34 - $this->user = $user; 35 - return $this; 36 - } 37 - 38 - 39 32 /** 40 33 * Add explicit subscribers. These subscribers have explicitly subscribed 41 34 * (or been subscribed) to the object, and will be added even if they ··· 81 74 if (!$this->object) { 82 75 throw new Exception('Call setObject() before save()!'); 83 76 } 84 - if (!$this->user) { 85 - throw new Exception('Call setUser() before save()!'); 86 - } 77 + $actor = $this->requireActor(); 87 78 88 79 $src = $this->object->getPHID(); 89 80 ··· 109 100 $s_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER; 110 101 111 102 $editor = id(new PhabricatorEdgeEditor()) 112 - ->setUser($this->user); 103 + ->setActor($actor); 113 104 114 105 foreach ($add as $phid => $ignored) { 115 106 $editor->removeEdge($src, $u_type, $phid);
+47
src/infrastructure/PhabricatorEditor.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + abstract class PhabricatorEditor { 20 + 21 + private $actor; 22 + private $excludeMailRecipientPHIDs = array(); 23 + 24 + final public function setActor(PhabricatorUser $user) { 25 + $this->user = $user; 26 + return $this; 27 + } 28 + final protected function getActor() { 29 + return $this->user; 30 + } 31 + final protected function requireActor() { 32 + $actor = $this->getActor(); 33 + if (!$actor) { 34 + throw new Exception('You must setActor()!'); 35 + } 36 + return $actor; 37 + } 38 + 39 + final public function setExcludeMailRecipientPHIDs($phids) { 40 + $this->excludeMailRecipientPHIDs = $phids; 41 + return $this; 42 + } 43 + final protected function getExcludeMailRecipientPHIDs() { 44 + return $this->excludeMailRecipientPHIDs; 45 + } 46 + 47 + }
+3 -3
src/infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php
··· 37 37 $phid2 = $obj2->getPHID(); 38 38 39 39 $editor = id(new PhabricatorEdgeEditor()) 40 - ->setUser($user) 40 + ->setActor($user) 41 41 ->addEdge($phid1, PhabricatorEdgeConfig::TYPE_TEST_NO_CYCLE, $phid2) 42 42 ->addEdge($phid2, PhabricatorEdgeConfig::TYPE_TEST_NO_CYCLE, $phid1); 43 43 ··· 57 57 // fail (it introduces a cycle). 58 58 59 59 $editor = id(new PhabricatorEdgeEditor()) 60 - ->setUser($user) 60 + ->setActor($user) 61 61 ->addEdge($phid1, PhabricatorEdgeConfig::TYPE_TEST_NO_CYCLE, $phid2) 62 62 ->save(); 63 63 64 64 $editor = id(new PhabricatorEdgeEditor()) 65 - ->setUser($user) 65 + ->setActor($user) 66 66 ->addEdge($phid2, PhabricatorEdgeConfig::TYPE_TEST_NO_CYCLE, $phid1); 67 67 68 68 $caught = null;
+3 -9
src/infrastructure/edges/editor/PhabricatorEdgeEditor.php
··· 28 28 * 29 29 * id(new PhabricatorEdgeEditor()) 30 30 * ->addEdge($src, $type, $dst) 31 - * ->setUser($user) 31 + * ->setActor($user) 32 32 * ->save(); 33 33 * 34 34 * @task edit Editing Edges 35 35 * @task cycles Cycle Prevention 36 36 * @task internal Internals 37 37 */ 38 - final class PhabricatorEdgeEditor { 38 + final class PhabricatorEdgeEditor extends PhabricatorEditor { 39 39 40 40 private $addEdges = array(); 41 41 private $remEdges = array(); 42 42 private $openTransactions = array(); 43 - private $user; 44 43 private $suppressEvents; 45 - 46 - public function setUser(PhabricatorUser $user) { 47 - $this->user = $user; 48 - return $this; 49 - } 50 44 51 45 52 46 /* -( Editing Edges )------------------------------------------------------ */ ··· 398 392 'add' => $this->addEdges, 399 393 'rem' => $this->remEdges, 400 394 )); 401 - $event->setUser($this->user); 395 + $event->setUser($this->getActor()); 402 396 PhutilEventEngine::dispatchEvent($event); 403 397 } 404 398