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

Hook Ponder to Subscriptions

Summary: Adding email aggro email aggro

Test Plan: Added some content; annoyed some coworkers.

Reviewers: epriestley, nh, vrana

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T1808

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

+587 -6
+10
src/__phutil_library_map__.php
··· 1200 1200 'PonderAnswerQuery' => 'applications/ponder/query/PonderAnswerQuery.php', 1201 1201 'PonderAnswerSaveController' => 'applications/ponder/controller/PonderAnswerSaveController.php', 1202 1202 'PonderAnswerViewController' => 'applications/ponder/controller/PonderAnswerViewController.php', 1203 + 'PonderAnsweredMail' => 'applications/ponder/mail/PonderAnsweredMail.php', 1203 1204 'PonderComment' => 'applications/ponder/storage/PonderComment.php', 1204 1205 'PonderCommentEditor' => 'applications/ponder/editor/PonderCommentEditor.php', 1205 1206 'PonderCommentListView' => 'applications/ponder/view/PonderCommentListView.php', 1207 + 'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php', 1206 1208 'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php', 1207 1209 'PonderCommentSaveController' => 'applications/ponder/controller/PonderCommentSaveController.php', 1208 1210 'PonderConstants' => 'applications/ponder/PonderConstants.php', 1209 1211 'PonderController' => 'applications/ponder/controller/PonderController.php', 1210 1212 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 1211 1213 'PonderFeedController' => 'applications/ponder/controller/PonderFeedController.php', 1214 + 'PonderMail' => 'applications/ponder/mail/PonderMail.php', 1215 + 'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php', 1212 1216 'PonderPostBodyView' => 'applications/ponder/view/PonderPostBodyView.php', 1213 1217 'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php', 1214 1218 'PonderQuestionAskController' => 'applications/ponder/controller/PonderQuestionAskController.php', ··· 1218 1222 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 1219 1223 'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php', 1220 1224 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 1225 + 'PonderReplyHandler' => 'applications/ponder/PonderReplyHandler.php', 1221 1226 'PonderRuleQuestion' => 'infrastructure/markup/rule/PonderRuleQuestion.php', 1222 1227 'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php', 1223 1228 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', ··· 2318 2323 'PonderAnswerQuery' => 'PhabricatorOffsetPagedQuery', 2319 2324 'PonderAnswerSaveController' => 'PonderController', 2320 2325 'PonderAnswerViewController' => 'PonderController', 2326 + 'PonderAnsweredMail' => 'PonderMail', 2321 2327 'PonderComment' => 2322 2328 array( 2323 2329 0 => 'PonderDAO', 2324 2330 1 => 'PhabricatorMarkupInterface', 2325 2331 ), 2326 2332 'PonderCommentListView' => 'AphrontView', 2333 + 'PonderCommentMail' => 'PonderMail', 2327 2334 'PonderCommentQuery' => 'PhabricatorQuery', 2328 2335 'PonderCommentSaveController' => 'PonderController', 2329 2336 'PonderController' => 'PhabricatorController', 2330 2337 'PonderDAO' => 'PhabricatorLiskDAO', 2331 2338 'PonderFeedController' => 'PonderController', 2339 + 'PonderMentionMail' => 'PonderMail', 2332 2340 'PonderPostBodyView' => 'AphrontView', 2333 2341 'PonderQuestion' => 2334 2342 array( 2335 2343 0 => 'PonderDAO', 2336 2344 1 => 'PhabricatorMarkupInterface', 2337 2345 2 => 'PonderVotableInterface', 2346 + 3 => 'PhabricatorSubscribableInterface', 2338 2347 ), 2339 2348 'PonderQuestionAskController' => 'PonderController', 2340 2349 'PonderQuestionDetailView' => 'AphrontView', ··· 2342 2351 'PonderQuestionQuery' => 'PhabricatorOffsetPagedQuery', 2343 2352 'PonderQuestionSummaryView' => 'AphrontView', 2344 2353 'PonderQuestionViewController' => 'PonderController', 2354 + 'PonderReplyHandler' => 'PhabricatorMailReplyHandler', 2345 2355 'PonderRuleQuestion' => 'PhabricatorRemarkupRuleObjectName', 2346 2356 'PonderUserProfileView' => 'AphrontView', 2347 2357 'PonderVotableView' => 'AphrontView',
+48
src/applications/ponder/PonderReplyHandler.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 + final class PonderReplyHandler extends PhabricatorMailReplyHandler { 20 + 21 + public function validateMailReceiver($mail_receiver) { 22 + if (!($mail_receiver instanceof PonderQuestion)) { 23 + throw new Exception("Mail receiver is not a PonderQuestion!"); 24 + } 25 + } 26 + 27 + public function getPrivateReplyHandlerEmailAddress( 28 + PhabricatorObjectHandle $handle) { 29 + return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'Q'); 30 + } 31 + 32 + public function getPublicReplyHandlerEmailAddress() { 33 + return $this->getDefaultPublicReplyHandlerEmailAddress('Q'); 34 + } 35 + 36 + public function getReplyHandlerDomain() { 37 + return PhabricatorEnv::getEnvConfig( 38 + 'metamta.maniphest.reply-handler-domain'); 39 + } 40 + 41 + public function getReplyHandlerInstructions() { 42 + return null; 43 + } 44 + 45 + protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { 46 + // ignore this entirely for now 47 + } 48 + }
+1
src/applications/ponder/controller/PonderAnswerSaveController.php
··· 60 60 ->setContentSource($content_source); 61 61 62 62 id(new PonderAnswerEditor()) 63 + ->setUser($user) 63 64 ->setQuestion($question) 64 65 ->setAnswer($res) 65 66 ->saveAnswer();
+3
src/applications/ponder/controller/PonderCommentSaveController.php
··· 38 38 if (!$objects) { 39 39 return new Aphront404Response(); 40 40 } 41 + 41 42 $content = $request->getStr('content'); 42 43 43 44 if (!strlen(trim($content))) { ··· 59 60 id(new PonderCommentEditor()) 60 61 ->setQuestion($question) 61 62 ->setComment($res) 63 + ->setTargetPHID($target) 64 + ->setUser($user) 62 65 ->save(); 63 66 64 67 return id(new AphrontRedirectResponse())
+1
src/applications/ponder/controller/PonderQuestionAskController.php
··· 53 53 54 54 id(new PonderQuestionEditor()) 55 55 ->setQuestion($question) 56 + ->setUser($user) 56 57 ->save(); 57 58 58 59 return id(new AphrontRedirectResponse())
+21 -2
src/applications/ponder/controller/PonderQuestionViewController.php
··· 52 52 } 53 53 } 54 54 55 + $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID( 56 + $question->getPHID()); 57 + 58 + $object_phids = array_merge($object_phids, $subscribers); 59 + 55 60 $handles = $this->loadViewerHandles($object_phids); 56 61 $this->loadHandles($object_phids); 57 62 ··· 79 84 ->setHeader($question->getTitle()); 80 85 81 86 $actions = $this->buildActionListView($question); 82 - $properties = $this->buildPropertyListView($question); 87 + $properties = $this->buildPropertyListView($question, $subscribers); 83 88 84 89 $nav = $this->buildSideNavView($question); 85 90 $nav->appendChild( ··· 112 117 return $view; 113 118 } 114 119 115 - private function buildPropertyListView(PonderQuestion $question) { 120 + private function buildPropertyListView( 121 + PonderQuestion $question, 122 + array $subscribers) { 123 + 116 124 $viewer = $this->getRequest()->getUser(); 117 125 $view = new PhabricatorPropertyListView(); 118 126 ··· 123 131 $view->addProperty( 124 132 pht('Created'), 125 133 phabricator_datetime($question->getDateCreated(), $viewer)); 134 + 135 + if ($subscribers) { 136 + foreach ($subscribers as $key => $subscriber) { 137 + $subscribers[$key] = $this->getHandle($subscriber)->renderLink(); 138 + } 139 + $subscribers = implode(', ', $subscribers); 140 + } 141 + 142 + $view->addProperty( 143 + pht('Subscribers'), 144 + nonempty($subscribers, '<em>'.pht('None').'</em>')); 126 145 127 146 return $view; 128 147 }
+59 -2
src/applications/ponder/editor/PonderAnswerEditor.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 - 20 19 final class PonderAnswerEditor { 21 - 22 20 private $question; 23 21 private $answer; 22 + private $viewer; 23 + private $shouldEmail = true; 24 24 25 25 public function setQuestion($question) { 26 26 $this->question = $question; ··· 32 32 return $this; 33 33 } 34 34 35 + public function setUser(PhabricatorUser $user) { 36 + $this->viewer = $user; 37 + return $this; 38 + } 39 + 35 40 public function saveAnswer() { 41 + if (!$this->viewer) { 42 + throw new Exception("Must set user before saving question"); 43 + } 36 44 if (!$this->question) { 37 45 throw new Exception("Must set question before saving answer"); 38 46 } ··· 42 50 43 51 $question = $this->question; 44 52 $answer = $this->answer; 53 + $viewer = $this->viewer; 45 54 $conn = $answer->establishConnection('w'); 46 55 $trans = $conn->openTransaction(); 47 56 $trans->beginReadLocking(); ··· 63 72 64 73 $question->attachRelated(); 65 74 PhabricatorSearchPonderIndexer::indexQuestion($question); 75 + 76 + // subscribe author and @mentions 77 + $subeditor = id(new PhabricatorSubscriptionsEditor()) 78 + ->setObject($question) 79 + ->setUser($viewer); 80 + 81 + $subeditor->subscribeExplicit(array($answer->getAuthorPHID())); 82 + 83 + $content = $answer->getContent(); 84 + $at_mention_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 85 + array($content) 86 + ); 87 + $subeditor->subscribeImplicit($at_mention_phids); 88 + $subeditor->save(); 89 + 90 + if ($this->shouldEmail) { 91 + // now load subscribers, including implicitly-added @mention victims 92 + $subscribers = PhabricatorSubscribersQuery 93 + ::loadSubscribersForPHID($question->getPHID()); 94 + 95 + 96 + // @mention emails (but not for anyone who has explicitly unsubscribed) 97 + if (array_intersect($at_mention_phids, $subscribers)) { 98 + id(new PonderMentionMail( 99 + $question, 100 + $answer, 101 + $viewer)) 102 + ->setToPHIDs($at_mention_phids) 103 + ->send(); 104 + } 105 + 106 + $other_subs = 107 + array_diff( 108 + $subscribers, 109 + $at_mention_phids 110 + ); 111 + 112 + // 'Answered' emails for subscribers who are not @mentiond (and excluding 113 + // author depending on their MetaMTA settings). 114 + if ($other_subs) { 115 + id(new PonderAnsweredMail( 116 + $question, 117 + $answer, 118 + $viewer)) 119 + ->setToPHIDs($other_subs) 120 + ->send(); 121 + } 122 + } 66 123 } 67 124 }
+83 -1
src/applications/ponder/editor/PonderCommentEditor.php
··· 21 21 22 22 private $question; 23 23 private $comment; 24 + private $targetPHID; 25 + private $viewer; 26 + private $shouldEmail = true; 24 27 25 28 public function setComment(PonderComment $comment) { 26 29 $this->comment = $comment; ··· 32 35 return $this; 33 36 } 34 37 38 + public function setTargetPHID($target) { 39 + $this->targetPHID = $target; 40 + return $this; 41 + } 42 + 43 + public function setUser(PhabricatorUser $user) { 44 + $this->viewer = $user; 45 + return $this; 46 + } 47 + 35 48 public function save() { 36 49 if (!$this->comment) { 37 50 throw new Exception("Must set comment before saving it"); ··· 39 52 if (!$this->question) { 40 53 throw new Exception("Must set question before saving comment"); 41 54 } 55 + if (!$this->targetPHID) { 56 + throw new Exception("Must set target before saving comment"); 57 + } 58 + if (!$this->viewer) { 59 + throw new Exception("Must set viewer before saving comment"); 60 + } 42 61 43 62 $comment = $this->comment; 44 63 $question = $this->question; 45 - 64 + $target = $this->targetPHID; 65 + $viewer = $this->viewer; 46 66 $comment->save(); 47 67 48 68 $question->attachRelated(); 49 69 PhabricatorSearchPonderIndexer::indexQuestion($question); 70 + 71 + // subscribe author and @mentions 72 + $subeditor = id(new PhabricatorSubscriptionsEditor()) 73 + ->setObject($question) 74 + ->setUser($viewer); 75 + 76 + $subeditor->subscribeExplicit(array($comment->getAuthorPHID())); 77 + 78 + $content = $comment->getContent(); 79 + $at_mention_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 80 + array($content) 81 + ); 82 + $subeditor->subscribeImplicit($at_mention_phids); 83 + $subeditor->save(); 84 + 85 + if ($this->shouldEmail) { 86 + // now load subscribers, including implicitly-added @mention victims 87 + $subscribers = PhabricatorSubscribersQuery 88 + ::loadSubscribersForPHID($question->getPHID()); 89 + 90 + // @mention emails (but not for anyone who has explicitly unsubscribed) 91 + if (array_intersect($at_mention_phids, $subscribers)) { 92 + id(new PonderMentionMail( 93 + $question, 94 + $comment, 95 + $viewer)) 96 + ->setToPHIDs($at_mention_phids) 97 + ->send(); 98 + } 99 + 100 + if ($target === $question->getPHID()) { 101 + $target = $question; 102 + } 103 + else { 104 + $answers_by_phid = mgroup($question->getAnswers(), 'getPHID'); 105 + $target = head($answers_by_phid[$target]); 106 + } 107 + 108 + // only send emails to others in the same thread 109 + $thread = mpull($target->getComments(), 'getAuthorPHID'); 110 + $thread[] = $target->getAuthorPHID(); 111 + $thread[] = $question->getAuthorPHID(); 112 + 113 + $other_subs = 114 + array_diff( 115 + array_intersect($thread, $subscribers), 116 + $at_mention_phids 117 + ); 118 + 119 + // 'Comment' emails for subscribers who are in the same comment thread, 120 + // including the author of the parent question and/or answer, excluding 121 + // @mentions (and excluding the author, depending on their MetaMTA 122 + // settings). 123 + if ($other_subs) { 124 + id(new PonderCommentMail( 125 + $question, 126 + $comment, 127 + $viewer)) 128 + ->setToPHIDs($other_subs) 129 + ->send(); 130 + } 131 + } 50 132 } 51 133 }
+39
src/applications/ponder/editor/PonderQuestionEditor.php
··· 21 21 22 22 private $question; 23 23 private $viewer; 24 + private $shouldEmail = true; 24 25 25 26 public function setQuestion(PonderQuestion $question) { 26 27 $this->question = $question; 27 28 return $this; 28 29 } 29 30 31 + public function setUser(PhabricatorUser $user) { 32 + $this->viewer = $user; 33 + return $this; 34 + } 35 + 36 + public function setShouldEmail($se) { 37 + $this->shouldEmail = $se; 38 + return $this; 39 + } 40 + 30 41 public function save() { 42 + if (!$this->viewer) { 43 + throw new Exception("Must set user before saving question"); 44 + } 31 45 if (!$this->question) { 32 46 throw new Exception("Must set question before saving it"); 33 47 } 34 48 49 + $viewer = $this->viewer; 35 50 $question = $this->question; 36 51 $question->save(); 37 52 53 + // search index 38 54 $question->attachRelated(); 39 55 PhabricatorSearchPonderIndexer::indexQuestion($question); 56 + 57 + // subscribe author and @mentions 58 + $subeditor = id(new PhabricatorSubscriptionsEditor()) 59 + ->setObject($question) 60 + ->setUser($viewer); 61 + 62 + $subeditor->subscribeExplicit(array($question->getAuthorPHID())); 63 + 64 + $content = $question->getContent(); 65 + $at_mention_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 66 + array($content) 67 + ); 68 + $subeditor->subscribeImplicit($at_mention_phids); 69 + $subeditor->save(); 70 + 71 + if ($this->shouldEmail && $at_mention_phids) { 72 + id(new PonderMentionMail( 73 + $question, 74 + $question, 75 + $viewer)) 76 + ->setToPHIDs($at_mention_phids) 77 + ->send(); 78 + } 40 79 } 41 80 }
+53
src/applications/ponder/mail/PonderAnsweredMail.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 + final class PonderAnsweredMail extends PonderMail { 20 + 21 + public function __construct( 22 + PonderQuestion $question, 23 + PonderAnswer $target, 24 + PhabricatorUser $actor) { 25 + 26 + $this->setQuestion($question); 27 + $this->setTarget($target); 28 + $this->setActorHandle($actor); 29 + } 30 + 31 + protected function renderVaryPrefix() { 32 + return "[Answered]"; 33 + } 34 + 35 + protected function renderBody() { 36 + $question = $this->getQuestion(); 37 + $target = $this->getTarget(); 38 + $actor = $this->getActorName(); 39 + $name = $question->getTitle(); 40 + 41 + $body = array(); 42 + $body[] = "{$actor} answered a question that you are subscribed to."; 43 + $body[] = null; 44 + 45 + $content = $target->getContent(); 46 + if (strlen($content)) { 47 + $body[] = $this->formatText($content); 48 + $body[] = null; 49 + } 50 + 51 + return implode("\n", $body); 52 + } 53 + }
+53
src/applications/ponder/mail/PonderCommentMail.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 + final class PonderCommentMail extends PonderMail { 20 + 21 + public function __construct( 22 + PonderQuestion $question, 23 + PonderComment $target, 24 + PhabricatorUser $actor) { 25 + 26 + $this->setQuestion($question); 27 + $this->setTarget($target); 28 + $this->setActorHandle($actor); 29 + } 30 + 31 + protected function renderVaryPrefix() { 32 + return "[Commented]"; 33 + } 34 + 35 + protected function renderBody() { 36 + $question = $this->getQuestion(); 37 + $target = $this->getTarget(); 38 + $actor = $this->getActorName(); 39 + $name = $question->getTitle(); 40 + 41 + $body = array(); 42 + $body[] = "{$actor} commented on a question that you are subscribed to."; 43 + $body[] = null; 44 + 45 + $content = $target->getContent(); 46 + if (strlen($content)) { 47 + $body[] = $this->formatText($content); 48 + $body[] = null; 49 + } 50 + 51 + return implode("\n", $body); 52 + } 53 + }
+144
src/applications/ponder/mail/PonderMail.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 PonderMail { 20 + 21 + protected $to = array(); 22 + protected $actorHandle; 23 + protected $question; 24 + protected $target; 25 + 26 + protected $isFirstMailAboutQuestion; 27 + 28 + // protected $replyHandler; 29 + 30 + protected $parentMessageID; 31 + 32 + protected function renderSubject() { 33 + $question = $this->getQuestion(); 34 + $title = $question->getTitle(); 35 + $id = $question->getID(); 36 + return "Q{$id}: {$title}"; 37 + } 38 + 39 + abstract protected function renderVaryPrefix(); 40 + abstract protected function renderBody(); 41 + 42 + public function setActorHandle($actor_handle) { 43 + $this->actorHandle = $actor_handle; 44 + return $this; 45 + } 46 + 47 + public function getActorHandle() { 48 + return $this->actorHandle; 49 + } 50 + 51 + protected function getActorName() { 52 + return $this->actorHandle->getRealName(); 53 + } 54 + 55 + protected function getSubjectPrefix() { 56 + return "[Ponder]"; 57 + } 58 + 59 + public function setToPHIDs(array $to) { 60 + $this->to = $to; 61 + return $this; 62 + } 63 + 64 + protected function getToPHIDs() { 65 + return $this->to; 66 + } 67 + 68 + public function setQuestion($question) { 69 + $this->question = $question; 70 + return $this; 71 + } 72 + 73 + public function getQuestion() { 74 + return $this->question; 75 + } 76 + 77 + public function setTarget($target) { 78 + $this->target = $target; 79 + return $this; 80 + } 81 + 82 + public function getTarget() { 83 + return $this->target; 84 + } 85 + 86 + protected function getThreadID() { 87 + $phid = $this->getQuestion()->getPHID(); 88 + return "ponder-ques-{$phid}"; 89 + } 90 + 91 + protected function getThreadTopic() { 92 + $id = $this->getQuestion()->getID(); 93 + $title = $this->getQuestion()->getTitle(); 94 + return "Q{$id}: {$title}"; 95 + } 96 + 97 + public function send() { 98 + $email_to = array_filter(array_unique($this->to)); 99 + $question = $this->getQuestion(); 100 + $target = $this->getTarget(); 101 + 102 + $uri = PhabricatorEnv::getURI('/Q'. $question->getID()); 103 + $thread_id = $this->getThreadID(); 104 + 105 + $handles = id(new PhabricatorObjectHandleData($email_to)) 106 + ->loadHandles(); 107 + 108 + $reply_handler = new PonderReplyHandler(); 109 + 110 + $body = new PhabricatorMetaMTAMailBody(); 111 + $body->addRawSection($this->renderBody()); 112 + $body->addTextSection(pht('QUESTION DETAIL'), $uri); 113 + 114 + $template = id(new PhabricatorMetaMTAMail()) 115 + ->setSubject($this->getThreadTopic()) 116 + ->setSubjectPrefix($this->getSubjectPrefix()) 117 + ->setVarySubjectPrefix($this->renderVaryPrefix()) 118 + ->setFrom($target->getAuthorPHID()) 119 + ->setParentMessageID($this->parentMessageID) 120 + ->addHeader('Thread-Topic', $this->getThreadTopic()) 121 + ->setThreadID($this->getThreadID(), false) 122 + ->setRelatedPHID($question->getPHID()) 123 + ->setIsBulk(true) 124 + ->setBody($body->render()); 125 + 126 + $mails = $reply_handler->multiplexMail( 127 + $template, 128 + array_select_keys($handles, $email_to), 129 + array()); 130 + 131 + foreach ($mails as $mail) { 132 + $mail->saveAndSend(); 133 + } 134 + } 135 + 136 + protected function formatText($text) { 137 + $text = explode("\n", rtrim($text)); 138 + foreach ($text as &$line) { 139 + $line = rtrim(' '.$line); 140 + } 141 + unset($line); 142 + return implode("\n", $text); 143 + } 144 + }
+64
src/applications/ponder/mail/PonderMentionMail.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 + final class PonderMentionMail extends PonderMail { 20 + 21 + public function __construct( 22 + PonderQuestion $question, 23 + $target, 24 + PhabricatorUser $actor) { 25 + 26 + $this->setQuestion($question); 27 + $this->setTarget($target); 28 + $this->setActorHandle($actor); 29 + } 30 + 31 + protected function renderVaryPrefix() { 32 + return "[Mentioned]"; 33 + } 34 + 35 + protected function renderBody() { 36 + $question = $this->getQuestion(); 37 + $target = $this->getTarget(); 38 + $actor = $this->getActorName(); 39 + $name = $question->getTitle(); 40 + 41 + $targetkind = "somewhere"; 42 + if ($target instanceof PonderQuestion) { 43 + $targetkind = "in a question"; 44 + } 45 + else if ($target instanceof PonderAnswer) { 46 + $targetkind = "in an answer"; 47 + } 48 + else if ($target instanceof PonderComment) { 49 + $targetkind = "in a comment"; 50 + } 51 + 52 + $body = array(); 53 + $body[] = "{$actor} mentioned you {$targetkind}."; 54 + $body[] = null; 55 + 56 + $content = $target->getContent(); 57 + if (strlen($content)) { 58 + $body[] = $this->formatText($content); 59 + $body[] = null; 60 + } 61 + 62 + return implode("\n", $body); 63 + } 64 + }
+8 -1
src/applications/ponder/storage/PonderQuestion.php
··· 17 17 */ 18 18 19 19 final class PonderQuestion extends PonderDAO 20 - implements PhabricatorMarkupInterface, PonderVotableInterface { 20 + implements 21 + PhabricatorMarkupInterface, 22 + PonderVotableInterface, 23 + PhabricatorSubscribableInterface { 21 24 22 25 const MARKUP_FIELD_CONTENT = 'markup:content'; 23 26 ··· 167 170 168 171 public function getVotablePHID() { 169 172 return $this->getPHID(); 173 + } 174 + 175 + public function isAutomaticallySubscribed($phid) { 176 + return false; 170 177 } 171 178 }