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

Restore mail to Ponder

Summary: Ref T3578. Use ApplicationTransactions mail.

Test Plan: {F52159}

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T3578

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

+118 -373
+2 -12
src/__phutil_library_map__.php
··· 1880 1880 'PonderAnswerTransactionComment' => 'applications/ponder/storage/PonderAnswerTransactionComment.php', 1881 1881 'PonderAnswerTransactionQuery' => 'applications/ponder/query/PonderAnswerTransactionQuery.php', 1882 1882 'PonderAnswerViewController' => 'applications/ponder/controller/PonderAnswerViewController.php', 1883 - 'PonderAnsweredMail' => 'applications/ponder/mail/PonderAnsweredMail.php', 1884 1883 'PonderComment' => 'applications/ponder/storage/PonderComment.php', 1885 - 'PonderCommentEditor' => 'applications/ponder/editor/PonderCommentEditor.php', 1886 - 'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php', 1887 1884 'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php', 1888 1885 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php', 1889 1886 'PonderController' => 'applications/ponder/controller/PonderController.php', 1890 1887 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 1891 1888 'PonderLiterals' => 'applications/ponder/constants/PonderLiterals.php', 1892 - 'PonderMail' => 'applications/ponder/mail/PonderMail.php', 1893 - 'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php', 1894 1889 'PonderPHIDTypeAnswer' => 'applications/ponder/phid/PonderPHIDTypeAnswer.php', 1895 1890 'PonderPHIDTypeQuestion' => 'applications/ponder/phid/PonderPHIDTypeQuestion.php', 1896 1891 'PonderPostBodyView' => 'applications/ponder/view/PonderPostBodyView.php', ··· 1903 1898 'PonderQuestionMailReceiver' => 'applications/ponder/mail/PonderQuestionMailReceiver.php', 1904 1899 'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php', 1905 1900 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 1901 + 'PonderQuestionReplyHandler' => 'applications/ponder/mail/PonderQuestionReplyHandler.php', 1906 1902 'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php', 1907 1903 'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php', 1908 1904 'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php', ··· 1911 1907 'PonderQuestionTransactionQuery' => 'applications/ponder/query/PonderQuestionTransactionQuery.php', 1912 1908 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 1913 1909 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', 1914 - 'PonderReplyHandler' => 'applications/ponder/mail/PonderReplyHandler.php', 1915 1910 'PonderSearchIndexer' => 'applications/ponder/search/PonderSearchIndexer.php', 1916 1911 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', 1917 1912 'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php', ··· 4003 3998 'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment', 4004 3999 'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4005 4000 'PonderAnswerViewController' => 'PonderController', 4006 - 'PonderAnsweredMail' => 'PonderMail', 4007 4001 'PonderComment' => 4008 4002 array( 4009 4003 0 => 'PonderDAO', 4010 4004 1 => 'PhabricatorMarkupInterface', 4011 4005 ), 4012 - 'PonderCommentEditor' => 'PhabricatorEditor', 4013 - 'PonderCommentMail' => 'PonderMail', 4014 4006 'PonderCommentQuery' => 'PhabricatorQuery', 4015 4007 'PonderController' => 'PhabricatorController', 4016 4008 'PonderDAO' => 'PhabricatorLiskDAO', 4017 4009 'PonderLiterals' => 'PonderConstants', 4018 - 'PonderMail' => 'PhabricatorMail', 4019 - 'PonderMentionMail' => 'PonderMail', 4020 4010 'PonderPHIDTypeAnswer' => 'PhabricatorPHIDType', 4021 4011 'PonderPHIDTypeQuestion' => 'PhabricatorPHIDType', 4022 4012 'PonderPostBodyView' => 'AphrontView', ··· 4041 4031 'PonderQuestionMailReceiver' => 'PhabricatorObjectMailReceiver', 4042 4032 'PonderQuestionPreviewController' => 'PonderController', 4043 4033 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4034 + 'PonderQuestionReplyHandler' => 'PhabricatorMailReplyHandler', 4044 4035 'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine', 4045 4036 'PonderQuestionStatus' => 'PonderConstants', 4046 4037 'PonderQuestionStatusController' => 'PonderController', ··· 4049 4040 'PonderQuestionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4050 4041 'PonderQuestionViewController' => 'PonderController', 4051 4042 'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject', 4052 - 'PonderReplyHandler' => 'PhabricatorMailReplyHandler', 4053 4043 'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 4054 4044 'PonderVotableView' => 'AphrontView', 4055 4045 'PonderVote' => 'PonderConstants',
-104
src/applications/ponder/editor/PonderCommentEditor.php
··· 1 - <?php 2 - 3 - final class PonderCommentEditor extends PhabricatorEditor { 4 - 5 - private $question; 6 - private $comment; 7 - private $targetPHID; 8 - private $shouldEmail = true; 9 - 10 - public function setComment(PonderComment $comment) { 11 - $this->comment = $comment; 12 - return $this; 13 - } 14 - 15 - public function setQuestion(PonderQuestion $question) { 16 - $this->question = $question; 17 - return $this; 18 - } 19 - 20 - public function setTargetPHID($target) { 21 - $this->targetPHID = $target; 22 - return $this; 23 - } 24 - 25 - public function save() { 26 - $actor = $this->requireActor(); 27 - if (!$this->comment) { 28 - throw new Exception("Must set comment before saving it"); 29 - } 30 - if (!$this->question) { 31 - throw new Exception("Must set question before saving comment"); 32 - } 33 - if (!$this->targetPHID) { 34 - throw new Exception("Must set target before saving comment"); 35 - } 36 - 37 - $comment = $this->comment; 38 - $question = $this->question; 39 - $target = $this->targetPHID; 40 - $comment->save(); 41 - 42 - id(new PhabricatorSearchIndexer()) 43 - ->indexDocumentByPHID($question->getPHID()); 44 - 45 - // subscribe author and @mentions 46 - $subeditor = id(new PhabricatorSubscriptionsEditor()) 47 - ->setObject($question) 48 - ->setActor($actor); 49 - 50 - $subeditor->subscribeExplicit(array($comment->getAuthorPHID())); 51 - 52 - $content = $comment->getContent(); 53 - $at_mention_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 54 - array($content)); 55 - $subeditor->subscribeImplicit($at_mention_phids); 56 - $subeditor->save(); 57 - 58 - if ($this->shouldEmail) { 59 - // now load subscribers, including implicitly-added @mention victims 60 - $subscribers = PhabricatorSubscribersQuery 61 - ::loadSubscribersForPHID($question->getPHID()); 62 - 63 - // @mention emails (but not for anyone who has explicitly unsubscribed) 64 - if (array_intersect($at_mention_phids, $subscribers)) { 65 - id(new PonderMentionMail( 66 - $question, 67 - $comment, 68 - $actor)) 69 - ->setToPHIDs($at_mention_phids) 70 - ->send(); 71 - } 72 - 73 - if ($target === $question->getPHID()) { 74 - $target = $question; 75 - } else { 76 - $answers_by_phid = mgroup($question->getAnswers(), 'getPHID'); 77 - $target = head($answers_by_phid[$target]); 78 - } 79 - 80 - // only send emails to others in the same thread 81 - $thread = mpull($target->getComments(), 'getAuthorPHID'); 82 - $thread[] = $target->getAuthorPHID(); 83 - $thread[] = $question->getAuthorPHID(); 84 - 85 - $other_subs = 86 - array_diff( 87 - array_intersect($thread, $subscribers), 88 - $at_mention_phids); 89 - 90 - // 'Comment' emails for subscribers who are in the same comment thread, 91 - // including the author of the parent question and/or answer, excluding 92 - // @mentions (and excluding the author, depending on their MetaMTA 93 - // settings). 94 - if ($other_subs) { 95 - id(new PonderCommentMail( 96 - $question, 97 - $comment, 98 - $actor)) 99 - ->setToPHIDs($other_subs) 100 - ->send(); 101 - } 102 - } 103 - } 104 - }
+54 -5
src/applications/ponder/editor/PonderQuestionEditor.php
··· 149 149 return true; 150 150 } 151 151 152 - protected function getMailTo(PhabricatorLiskDAO $object) { 153 - return array($object->getAuthorPHID()); 154 - } 155 - 156 152 protected function supportsSearch() { 157 153 return true; 158 154 } ··· 169 165 return parent::shouldImplyCC($object, $xaction); 170 166 } 171 167 172 - // TODO: Mail support 168 + protected function supportsMail() { 169 + return true; 170 + } 171 + 172 + protected function buildReplyHandler(PhabricatorLiskDAO $object) { 173 + return id(new PonderQuestionReplyHandler()) 174 + ->setMailReceiver($object); 175 + } 176 + 177 + protected function buildMailTemplate(PhabricatorLiskDAO $object) { 178 + $id = $object->getID(); 179 + $title = $object->getTitle(); 180 + $original_title = $object->getOriginalTitle(); 181 + 182 + return id(new PhabricatorMetaMTAMail()) 183 + ->setSubject("Q{$id}: {$title}") 184 + ->addHeader('Thread-Topic', "Q{$id}: {$original_title}"); 185 + } 186 + 187 + protected function getMailTo(PhabricatorLiskDAO $object) { 188 + return array( 189 + $object->getAuthorPHID(), 190 + $this->requireActor()->getPHID(), 191 + ); 192 + } 193 + 194 + protected function buildMailBody( 195 + PhabricatorLiskDAO $object, 196 + array $xactions) { 197 + 198 + $body = parent::buildMailBody($object, $xactions); 199 + 200 + // If the user just asked the question, add the question text. 201 + foreach ($xactions as $xaction) { 202 + $type = $xaction->getTransactionType(); 203 + $old = $xaction->getOldValue(); 204 + $new = $xaction->getNewValue(); 205 + if ($type == PonderQuestionTransaction::TYPE_CONTENT) { 206 + if ($old === null) { 207 + $body->addRawSection($new); 208 + } 209 + } 210 + } 211 + 212 + $body->addTextSection( 213 + pht('QUESTION DETAIL'), 214 + PhabricatorEnv::getProductionURI('/Q'.$object->getID())); 215 + 216 + return $body; 217 + } 218 + 219 + protected function getMailSubjectPrefix() { 220 + return '[Ponder]'; 221 + } 173 222 174 223 }
-38
src/applications/ponder/mail/PonderAnsweredMail.php
··· 1 - <?php 2 - 3 - final class PonderAnsweredMail extends PonderMail { 4 - 5 - public function __construct( 6 - PonderQuestion $question, 7 - PonderAnswer $target, 8 - PhabricatorUser $actor) { 9 - 10 - $this->setQuestion($question); 11 - $this->setTarget($target); 12 - $this->setActorHandle($actor); 13 - $this->setActor($actor); 14 - } 15 - 16 - protected function renderVaryPrefix() { 17 - return "[Answered]"; 18 - } 19 - 20 - protected function renderBody() { 21 - $question = $this->getQuestion(); 22 - $target = $this->getTarget(); 23 - $actor = $this->getActorName(); 24 - $name = $question->getTitle(); 25 - 26 - $body = array(); 27 - $body[] = "{$actor} answered a question that you are subscribed to."; 28 - $body[] = null; 29 - 30 - $content = $target->getContent(); 31 - if (strlen($content)) { 32 - $body[] = $this->formatText($content); 33 - $body[] = null; 34 - } 35 - 36 - return implode("\n", $body); 37 - } 38 - }
-38
src/applications/ponder/mail/PonderCommentMail.php
··· 1 - <?php 2 - 3 - final class PonderCommentMail extends PonderMail { 4 - 5 - public function __construct( 6 - PonderQuestion $question, 7 - PonderComment $target, 8 - PhabricatorUser $actor) { 9 - 10 - $this->setQuestion($question); 11 - $this->setTarget($target); 12 - $this->setActorHandle($actor); 13 - $this->setActor($actor); 14 - } 15 - 16 - protected function renderVaryPrefix() { 17 - return "[Commented]"; 18 - } 19 - 20 - protected function renderBody() { 21 - $question = $this->getQuestion(); 22 - $target = $this->getTarget(); 23 - $actor = $this->getActorName(); 24 - $name = $question->getTitle(); 25 - 26 - $body = array(); 27 - $body[] = "{$actor} commented on a question that you are subscribed to."; 28 - $body[] = null; 29 - 30 - $content = $target->getContent(); 31 - if (strlen($content)) { 32 - $body[] = $this->formatText($content); 33 - $body[] = null; 34 - } 35 - 36 - return implode("\n", $body); 37 - } 38 - }
-127
src/applications/ponder/mail/PonderMail.php
··· 1 - <?php 2 - 3 - abstract class PonderMail extends PhabricatorMail { 4 - 5 - protected $to = array(); 6 - protected $actorHandle; 7 - protected $question; 8 - protected $target; 9 - 10 - protected $isFirstMailAboutQuestion; 11 - protected $parentMessageID; 12 - 13 - protected function renderSubject() { 14 - $question = $this->getQuestion(); 15 - $title = $question->getTitle(); 16 - $id = $question->getID(); 17 - return "Q{$id}: {$title}"; 18 - } 19 - 20 - abstract protected function renderVaryPrefix(); 21 - abstract protected function renderBody(); 22 - 23 - public function setActorHandle($actor_handle) { 24 - $this->actorHandle = $actor_handle; 25 - return $this; 26 - } 27 - 28 - public function getActorHandle() { 29 - return $this->actorHandle; 30 - } 31 - 32 - protected function getActorName() { 33 - return $this->actorHandle->getRealName(); 34 - } 35 - 36 - protected function getSubjectPrefix() { 37 - return "[Ponder]"; 38 - } 39 - 40 - public function setToPHIDs(array $to) { 41 - $this->to = $to; 42 - return $this; 43 - } 44 - 45 - protected function getToPHIDs() { 46 - return $this->to; 47 - } 48 - 49 - public function setQuestion($question) { 50 - $this->question = $question; 51 - return $this; 52 - } 53 - 54 - public function getQuestion() { 55 - return $this->question; 56 - } 57 - 58 - public function setTarget($target) { 59 - $this->target = $target; 60 - return $this; 61 - } 62 - 63 - public function getTarget() { 64 - return $this->target; 65 - } 66 - 67 - protected function getThreadID() { 68 - $phid = $this->getQuestion()->getPHID(); 69 - return "ponder-ques-{$phid}"; 70 - } 71 - 72 - protected function getThreadTopic() { 73 - $id = $this->getQuestion()->getID(); 74 - $title = $this->getQuestion()->getTitle(); 75 - return "Q{$id}: {$title}"; 76 - } 77 - 78 - public function send() { 79 - $email_to = array_filter(array_unique($this->to)); 80 - $question = $this->getQuestion(); 81 - $target = $this->getTarget(); 82 - 83 - $uri = PhabricatorEnv::getURI('/Q'. $question->getID()); 84 - $thread_id = $this->getThreadID(); 85 - 86 - $handles = id(new PhabricatorObjectHandleData($email_to)) 87 - ->setViewer($this->getActor()) 88 - ->loadHandles(); 89 - 90 - $reply_handler = new PonderReplyHandler(); 91 - $reply_handler->setMailReceiver($question); 92 - 93 - $body = new PhabricatorMetaMTAMailBody(); 94 - $body->addRawSection($this->renderBody()); 95 - $body->addTextSection(pht('QUESTION DETAIL'), $uri); 96 - 97 - $template = id(new PhabricatorMetaMTAMail()) 98 - ->setSubject($this->getThreadTopic()) 99 - ->setSubjectPrefix($this->getSubjectPrefix()) 100 - ->setVarySubjectPrefix($this->renderVaryPrefix()) 101 - ->setFrom($target->getAuthorPHID()) 102 - ->setParentMessageID($this->parentMessageID) 103 - ->addHeader('Thread-Topic', $this->getThreadTopic()) 104 - ->setThreadID($this->getThreadID(), false) 105 - ->setRelatedPHID($question->getPHID()) 106 - ->setIsBulk(true) 107 - ->setBody($body->render()); 108 - 109 - $mails = $reply_handler->multiplexMail( 110 - $template, 111 - array_select_keys($handles, $email_to), 112 - array()); 113 - 114 - foreach ($mails as $mail) { 115 - $mail->saveAndSend(); 116 - } 117 - } 118 - 119 - protected function formatText($text) { 120 - $text = explode("\n", rtrim($text)); 121 - foreach ($text as &$line) { 122 - $line = rtrim(' '.$line); 123 - } 124 - unset($line); 125 - return implode("\n", $text); 126 - } 127 - }
-47
src/applications/ponder/mail/PonderMentionMail.php
··· 1 - <?php 2 - 3 - final class PonderMentionMail extends PonderMail { 4 - 5 - public function __construct( 6 - PonderQuestion $question, 7 - $target, 8 - PhabricatorUser $actor) { 9 - 10 - $this->setQuestion($question); 11 - $this->setTarget($target); 12 - $this->setActorHandle($actor); 13 - $this->setActor($actor); 14 - } 15 - 16 - protected function renderVaryPrefix() { 17 - return "[Mentioned]"; 18 - } 19 - 20 - protected function renderBody() { 21 - $question = $this->getQuestion(); 22 - $target = $this->getTarget(); 23 - $actor = $this->getActorName(); 24 - $name = $question->getTitle(); 25 - 26 - $targetkind = "somewhere"; 27 - if ($target instanceof PonderQuestion) { 28 - $targetkind = "in a question"; 29 - } else if ($target instanceof PonderAnswer) { 30 - $targetkind = "in an answer"; 31 - } else if ($target instanceof PonderComment) { 32 - $targetkind = "in a comment"; 33 - } 34 - 35 - $body = array(); 36 - $body[] = "{$actor} mentioned you {$targetkind}."; 37 - $body[] = null; 38 - 39 - $content = $target->getContent(); 40 - if (strlen($content)) { 41 - $body[] = $this->formatText($content); 42 - $body[] = null; 43 - } 44 - 45 - return implode("\n", $body); 46 - } 47 - }
+1 -1
src/applications/ponder/mail/PonderReplyHandler.php src/applications/ponder/mail/PonderQuestionReplyHandler.php
··· 1 1 <?php 2 2 3 - final class PonderReplyHandler extends PhabricatorMailReplyHandler { 3 + final class PonderQuestionReplyHandler extends PhabricatorMailReplyHandler { 4 4 5 5 public function validateMailReceiver($mail_receiver) { 6 6 if (!($mail_receiver instanceof PonderQuestion)) {
+5
src/applications/ponder/storage/PonderQuestion.php
··· 203 203 return ($viewer->getPHID() == $this->getAuthorPHID()); 204 204 } 205 205 206 + public function getOriginalTitle() { 207 + // TODO: Make this actually save/return the original title. 208 + return $this->getTitle(); 209 + } 210 + 206 211 207 212 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 208 213
+49 -1
src/applications/ponder/storage/PonderQuestionTransaction.php
··· 38 38 case self::TYPE_TITLE: 39 39 if ($old === null) { 40 40 return pht( 41 - '%s created this question.', 41 + '%s asked this question.', 42 42 $this->renderHandleLink($author_phid)); 43 43 } else { 44 44 return pht( ··· 132 132 ->setNewText($new); 133 133 134 134 return $view->render(); 135 + } 136 + 137 + public function getActionStrength() { 138 + $old = $this->getOldValue(); 139 + $new = $this->getNewValue(); 140 + 141 + switch ($this->getTransactionType()) { 142 + case self::TYPE_TITLE: 143 + if ($old === null) { 144 + return 3; 145 + } 146 + break; 147 + case self::TYPE_ANSWERS: 148 + return 2; 149 + } 150 + 151 + return parent::getActionStrength(); 152 + } 153 + 154 + public function getActionName() { 155 + $old = $this->getOldValue(); 156 + $new = $this->getNewValue(); 157 + 158 + switch ($this->getTransactionType()) { 159 + case self::TYPE_TITLE: 160 + if ($old === null) { 161 + return pht('Asked'); 162 + } 163 + break; 164 + case self::TYPE_ANSWERS: 165 + return pht('Answered'); 166 + } 167 + 168 + return parent::getActionName(); 169 + } 170 + 171 + public function shouldHide() { 172 + switch ($this->getTransactionType()) { 173 + case self::TYPE_CONTENT: 174 + if ($this->getOldValue() === null) { 175 + return true; 176 + } else { 177 + return false; 178 + } 179 + break; 180 + } 181 + 182 + return parent::shouldHide(); 135 183 } 136 184 137 185 public function getTitleForFeed() {
+3
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 1188 1188 $comments = array(); 1189 1189 1190 1190 foreach ($xactions as $xaction) { 1191 + if ($xaction->shouldHideForMail()) { 1192 + continue; 1193 + } 1191 1194 $headers[] = id(clone $xaction)->setRenderingTarget('text')->getTitle(); 1192 1195 $comment = $xaction->getComment(); 1193 1196 if ($comment && strlen($comment->getContent())) {
+4
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 214 214 return false; 215 215 } 216 216 217 + public function shouldHideForMail() { 218 + return $this->shouldHide(); 219 + } 220 + 217 221 public function getNoEffectDescription() { 218 222 219 223 switch ($this->getTransactionType()) {