1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-27 09:12:41 +01:00

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
This commit is contained in:
epriestley 2013-07-29 08:38:25 -07:00
parent 4308a932c2
commit 1fd2d28b11
12 changed files with 118 additions and 373 deletions

View file

@ -1880,17 +1880,12 @@ phutil_register_library_map(array(
'PonderAnswerTransactionComment' => 'applications/ponder/storage/PonderAnswerTransactionComment.php',
'PonderAnswerTransactionQuery' => 'applications/ponder/query/PonderAnswerTransactionQuery.php',
'PonderAnswerViewController' => 'applications/ponder/controller/PonderAnswerViewController.php',
'PonderAnsweredMail' => 'applications/ponder/mail/PonderAnsweredMail.php',
'PonderComment' => 'applications/ponder/storage/PonderComment.php',
'PonderCommentEditor' => 'applications/ponder/editor/PonderCommentEditor.php',
'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php',
'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php',
'PonderConstants' => 'applications/ponder/constants/PonderConstants.php',
'PonderController' => 'applications/ponder/controller/PonderController.php',
'PonderDAO' => 'applications/ponder/storage/PonderDAO.php',
'PonderLiterals' => 'applications/ponder/constants/PonderLiterals.php',
'PonderMail' => 'applications/ponder/mail/PonderMail.php',
'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php',
'PonderPHIDTypeAnswer' => 'applications/ponder/phid/PonderPHIDTypeAnswer.php',
'PonderPHIDTypeQuestion' => 'applications/ponder/phid/PonderPHIDTypeQuestion.php',
'PonderPostBodyView' => 'applications/ponder/view/PonderPostBodyView.php',
@ -1903,6 +1898,7 @@ phutil_register_library_map(array(
'PonderQuestionMailReceiver' => 'applications/ponder/mail/PonderQuestionMailReceiver.php',
'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php',
'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php',
'PonderQuestionReplyHandler' => 'applications/ponder/mail/PonderQuestionReplyHandler.php',
'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php',
'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php',
'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php',
@ -1911,7 +1907,6 @@ phutil_register_library_map(array(
'PonderQuestionTransactionQuery' => 'applications/ponder/query/PonderQuestionTransactionQuery.php',
'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php',
'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php',
'PonderReplyHandler' => 'applications/ponder/mail/PonderReplyHandler.php',
'PonderSearchIndexer' => 'applications/ponder/search/PonderSearchIndexer.php',
'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php',
'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php',
@ -4003,20 +3998,15 @@ phutil_register_library_map(array(
'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PonderAnswerViewController' => 'PonderController',
'PonderAnsweredMail' => 'PonderMail',
'PonderComment' =>
array(
0 => 'PonderDAO',
1 => 'PhabricatorMarkupInterface',
),
'PonderCommentEditor' => 'PhabricatorEditor',
'PonderCommentMail' => 'PonderMail',
'PonderCommentQuery' => 'PhabricatorQuery',
'PonderController' => 'PhabricatorController',
'PonderDAO' => 'PhabricatorLiskDAO',
'PonderLiterals' => 'PonderConstants',
'PonderMail' => 'PhabricatorMail',
'PonderMentionMail' => 'PonderMail',
'PonderPHIDTypeAnswer' => 'PhabricatorPHIDType',
'PonderPHIDTypeQuestion' => 'PhabricatorPHIDType',
'PonderPostBodyView' => 'AphrontView',
@ -4041,6 +4031,7 @@ phutil_register_library_map(array(
'PonderQuestionMailReceiver' => 'PhabricatorObjectMailReceiver',
'PonderQuestionPreviewController' => 'PonderController',
'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PonderQuestionReplyHandler' => 'PhabricatorMailReplyHandler',
'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PonderQuestionStatus' => 'PonderConstants',
'PonderQuestionStatusController' => 'PonderController',
@ -4049,7 +4040,6 @@ phutil_register_library_map(array(
'PonderQuestionTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PonderQuestionViewController' => 'PonderController',
'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject',
'PonderReplyHandler' => 'PhabricatorMailReplyHandler',
'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'PonderVotableView' => 'AphrontView',
'PonderVote' => 'PonderConstants',

View file

@ -1,104 +0,0 @@
<?php
final class PonderCommentEditor extends PhabricatorEditor {
private $question;
private $comment;
private $targetPHID;
private $shouldEmail = true;
public function setComment(PonderComment $comment) {
$this->comment = $comment;
return $this;
}
public function setQuestion(PonderQuestion $question) {
$this->question = $question;
return $this;
}
public function setTargetPHID($target) {
$this->targetPHID = $target;
return $this;
}
public function save() {
$actor = $this->requireActor();
if (!$this->comment) {
throw new Exception("Must set comment before saving it");
}
if (!$this->question) {
throw new Exception("Must set question before saving comment");
}
if (!$this->targetPHID) {
throw new Exception("Must set target before saving comment");
}
$comment = $this->comment;
$question = $this->question;
$target = $this->targetPHID;
$comment->save();
id(new PhabricatorSearchIndexer())
->indexDocumentByPHID($question->getPHID());
// subscribe author and @mentions
$subeditor = id(new PhabricatorSubscriptionsEditor())
->setObject($question)
->setActor($actor);
$subeditor->subscribeExplicit(array($comment->getAuthorPHID()));
$content = $comment->getContent();
$at_mention_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions(
array($content));
$subeditor->subscribeImplicit($at_mention_phids);
$subeditor->save();
if ($this->shouldEmail) {
// now load subscribers, including implicitly-added @mention victims
$subscribers = PhabricatorSubscribersQuery
::loadSubscribersForPHID($question->getPHID());
// @mention emails (but not for anyone who has explicitly unsubscribed)
if (array_intersect($at_mention_phids, $subscribers)) {
id(new PonderMentionMail(
$question,
$comment,
$actor))
->setToPHIDs($at_mention_phids)
->send();
}
if ($target === $question->getPHID()) {
$target = $question;
} else {
$answers_by_phid = mgroup($question->getAnswers(), 'getPHID');
$target = head($answers_by_phid[$target]);
}
// only send emails to others in the same thread
$thread = mpull($target->getComments(), 'getAuthorPHID');
$thread[] = $target->getAuthorPHID();
$thread[] = $question->getAuthorPHID();
$other_subs =
array_diff(
array_intersect($thread, $subscribers),
$at_mention_phids);
// 'Comment' emails for subscribers who are in the same comment thread,
// including the author of the parent question and/or answer, excluding
// @mentions (and excluding the author, depending on their MetaMTA
// settings).
if ($other_subs) {
id(new PonderCommentMail(
$question,
$comment,
$actor))
->setToPHIDs($other_subs)
->send();
}
}
}
}

View file

@ -149,10 +149,6 @@ final class PonderQuestionEditor
return true;
}
protected function getMailTo(PhabricatorLiskDAO $object) {
return array($object->getAuthorPHID());
}
protected function supportsSearch() {
return true;
}
@ -169,6 +165,59 @@ final class PonderQuestionEditor
return parent::shouldImplyCC($object, $xaction);
}
// TODO: Mail support
protected function supportsMail() {
return true;
}
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
return id(new PonderQuestionReplyHandler())
->setMailReceiver($object);
}
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
$id = $object->getID();
$title = $object->getTitle();
$original_title = $object->getOriginalTitle();
return id(new PhabricatorMetaMTAMail())
->setSubject("Q{$id}: {$title}")
->addHeader('Thread-Topic', "Q{$id}: {$original_title}");
}
protected function getMailTo(PhabricatorLiskDAO $object) {
return array(
$object->getAuthorPHID(),
$this->requireActor()->getPHID(),
);
}
protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
$body = parent::buildMailBody($object, $xactions);
// If the user just asked the question, add the question text.
foreach ($xactions as $xaction) {
$type = $xaction->getTransactionType();
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
if ($type == PonderQuestionTransaction::TYPE_CONTENT) {
if ($old === null) {
$body->addRawSection($new);
}
}
}
$body->addTextSection(
pht('QUESTION DETAIL'),
PhabricatorEnv::getProductionURI('/Q'.$object->getID()));
return $body;
}
protected function getMailSubjectPrefix() {
return '[Ponder]';
}
}

View file

@ -1,38 +0,0 @@
<?php
final class PonderAnsweredMail extends PonderMail {
public function __construct(
PonderQuestion $question,
PonderAnswer $target,
PhabricatorUser $actor) {
$this->setQuestion($question);
$this->setTarget($target);
$this->setActorHandle($actor);
$this->setActor($actor);
}
protected function renderVaryPrefix() {
return "[Answered]";
}
protected function renderBody() {
$question = $this->getQuestion();
$target = $this->getTarget();
$actor = $this->getActorName();
$name = $question->getTitle();
$body = array();
$body[] = "{$actor} answered a question that you are subscribed to.";
$body[] = null;
$content = $target->getContent();
if (strlen($content)) {
$body[] = $this->formatText($content);
$body[] = null;
}
return implode("\n", $body);
}
}

View file

@ -1,38 +0,0 @@
<?php
final class PonderCommentMail extends PonderMail {
public function __construct(
PonderQuestion $question,
PonderComment $target,
PhabricatorUser $actor) {
$this->setQuestion($question);
$this->setTarget($target);
$this->setActorHandle($actor);
$this->setActor($actor);
}
protected function renderVaryPrefix() {
return "[Commented]";
}
protected function renderBody() {
$question = $this->getQuestion();
$target = $this->getTarget();
$actor = $this->getActorName();
$name = $question->getTitle();
$body = array();
$body[] = "{$actor} commented on a question that you are subscribed to.";
$body[] = null;
$content = $target->getContent();
if (strlen($content)) {
$body[] = $this->formatText($content);
$body[] = null;
}
return implode("\n", $body);
}
}

View file

@ -1,127 +0,0 @@
<?php
abstract class PonderMail extends PhabricatorMail {
protected $to = array();
protected $actorHandle;
protected $question;
protected $target;
protected $isFirstMailAboutQuestion;
protected $parentMessageID;
protected function renderSubject() {
$question = $this->getQuestion();
$title = $question->getTitle();
$id = $question->getID();
return "Q{$id}: {$title}";
}
abstract protected function renderVaryPrefix();
abstract protected function renderBody();
public function setActorHandle($actor_handle) {
$this->actorHandle = $actor_handle;
return $this;
}
public function getActorHandle() {
return $this->actorHandle;
}
protected function getActorName() {
return $this->actorHandle->getRealName();
}
protected function getSubjectPrefix() {
return "[Ponder]";
}
public function setToPHIDs(array $to) {
$this->to = $to;
return $this;
}
protected function getToPHIDs() {
return $this->to;
}
public function setQuestion($question) {
$this->question = $question;
return $this;
}
public function getQuestion() {
return $this->question;
}
public function setTarget($target) {
$this->target = $target;
return $this;
}
public function getTarget() {
return $this->target;
}
protected function getThreadID() {
$phid = $this->getQuestion()->getPHID();
return "ponder-ques-{$phid}";
}
protected function getThreadTopic() {
$id = $this->getQuestion()->getID();
$title = $this->getQuestion()->getTitle();
return "Q{$id}: {$title}";
}
public function send() {
$email_to = array_filter(array_unique($this->to));
$question = $this->getQuestion();
$target = $this->getTarget();
$uri = PhabricatorEnv::getURI('/Q'. $question->getID());
$thread_id = $this->getThreadID();
$handles = id(new PhabricatorObjectHandleData($email_to))
->setViewer($this->getActor())
->loadHandles();
$reply_handler = new PonderReplyHandler();
$reply_handler->setMailReceiver($question);
$body = new PhabricatorMetaMTAMailBody();
$body->addRawSection($this->renderBody());
$body->addTextSection(pht('QUESTION DETAIL'), $uri);
$template = id(new PhabricatorMetaMTAMail())
->setSubject($this->getThreadTopic())
->setSubjectPrefix($this->getSubjectPrefix())
->setVarySubjectPrefix($this->renderVaryPrefix())
->setFrom($target->getAuthorPHID())
->setParentMessageID($this->parentMessageID)
->addHeader('Thread-Topic', $this->getThreadTopic())
->setThreadID($this->getThreadID(), false)
->setRelatedPHID($question->getPHID())
->setIsBulk(true)
->setBody($body->render());
$mails = $reply_handler->multiplexMail(
$template,
array_select_keys($handles, $email_to),
array());
foreach ($mails as $mail) {
$mail->saveAndSend();
}
}
protected function formatText($text) {
$text = explode("\n", rtrim($text));
foreach ($text as &$line) {
$line = rtrim(' '.$line);
}
unset($line);
return implode("\n", $text);
}
}

View file

@ -1,47 +0,0 @@
<?php
final class PonderMentionMail extends PonderMail {
public function __construct(
PonderQuestion $question,
$target,
PhabricatorUser $actor) {
$this->setQuestion($question);
$this->setTarget($target);
$this->setActorHandle($actor);
$this->setActor($actor);
}
protected function renderVaryPrefix() {
return "[Mentioned]";
}
protected function renderBody() {
$question = $this->getQuestion();
$target = $this->getTarget();
$actor = $this->getActorName();
$name = $question->getTitle();
$targetkind = "somewhere";
if ($target instanceof PonderQuestion) {
$targetkind = "in a question";
} else if ($target instanceof PonderAnswer) {
$targetkind = "in an answer";
} else if ($target instanceof PonderComment) {
$targetkind = "in a comment";
}
$body = array();
$body[] = "{$actor} mentioned you {$targetkind}.";
$body[] = null;
$content = $target->getContent();
if (strlen($content)) {
$body[] = $this->formatText($content);
$body[] = null;
}
return implode("\n", $body);
}
}

View file

@ -1,6 +1,6 @@
<?php
final class PonderReplyHandler extends PhabricatorMailReplyHandler {
final class PonderQuestionReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof PonderQuestion)) {

View file

@ -203,6 +203,11 @@ final class PonderQuestion extends PonderDAO
return ($viewer->getPHID() == $this->getAuthorPHID());
}
public function getOriginalTitle() {
// TODO: Make this actually save/return the original title.
return $this->getTitle();
}
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */

View file

@ -38,7 +38,7 @@ final class PonderQuestionTransaction
case self::TYPE_TITLE:
if ($old === null) {
return pht(
'%s created this question.',
'%s asked this question.',
$this->renderHandleLink($author_phid));
} else {
return pht(
@ -134,6 +134,54 @@ final class PonderQuestionTransaction
return $view->render();
}
public function getActionStrength() {
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_TITLE:
if ($old === null) {
return 3;
}
break;
case self::TYPE_ANSWERS:
return 2;
}
return parent::getActionStrength();
}
public function getActionName() {
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_TITLE:
if ($old === null) {
return pht('Asked');
}
break;
case self::TYPE_ANSWERS:
return pht('Answered');
}
return parent::getActionName();
}
public function shouldHide() {
switch ($this->getTransactionType()) {
case self::TYPE_CONTENT:
if ($this->getOldValue() === null) {
return true;
} else {
return false;
}
break;
}
return parent::shouldHide();
}
public function getTitleForFeed() {
$author_phid = $this->getAuthorPHID();
$object_phid = $this->getObjectPHID();

View file

@ -1188,6 +1188,9 @@ abstract class PhabricatorApplicationTransactionEditor
$comments = array();
foreach ($xactions as $xaction) {
if ($xaction->shouldHideForMail()) {
continue;
}
$headers[] = id(clone $xaction)->setRenderingTarget('text')->getTitle();
$comment = $xaction->getComment();
if ($comment && strlen($comment->getContent())) {

View file

@ -214,6 +214,10 @@ abstract class PhabricatorApplicationTransaction
return false;
}
public function shouldHideForMail() {
return $this->shouldHide();
}
public function getNoEffectDescription() {
switch ($this->getTransactionType()) {