From 3ceaad1aa8b79f6406cf9f9a8e63c3f466121fc3 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 21 Nov 2012 17:39:46 -0800 Subject: [PATCH] Add basic email support to Pholio Summary: These emails aren't yet useful, but thread/multiplex/etc correctly. Test Plan: Got some Pholio emails. Reviewers: btrahan, chad Reviewed By: btrahan CC: aran Maniphest Tasks: T2097 Differential Revision: https://secure.phabricator.com/D3842 --- conf/default.conf.php | 10 +- src/__phutil_library_map__.php | 2 + .../editor/ManiphestTransactionEditor.php | 11 --- .../pholio/editor/PholioMockEditor.php | 99 ++++++++++++++++++- .../pholio/mail/PholioReplyHandler.php | 59 +++++++++++ 5 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 src/applications/pholio/mail/PholioReplyHandler.php diff --git a/conf/default.conf.php b/conf/default.conf.php index 1ff8c86771..11121e892b 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -349,8 +349,9 @@ return array( // class with an implementation of your own. This will allow you to do things // like have a single public reply handler or change how private reply // handlers are generated and validated. + // // This key should be set to a loadable subclass of - // PhabricatorMailReplyHandler (and possibly of ManiphestReplyHandler). + // PhabricatorMailReplyHandler. 'metamta.maniphest.reply-handler' => 'ManiphestReplyHandler', // If you don't want phabricator to take up an entire domain @@ -367,6 +368,13 @@ return array( // distinguish between testing and development installs, for example. 'metamta.maniphest.subject-prefix' => '[Maniphest]', + // See 'metamta.pholio.reply-handler-domain'. This does the same thing, but + // affects Pholio. + 'metamta.pholio.reply-handler-domain' => null, + + // Prefix prepended to mail sent by Pholio. + 'metamta.pholio.subject-prefix' => '[Pholio]', + // See 'metamta.maniphest.reply-handler-domain'. This does the same thing, // but allows email replies via Differential. 'metamta.differential.reply-handler-domain' => null, diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7690fca583..396128195d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1216,6 +1216,7 @@ phutil_register_library_map(array( 'PholioMockQuery' => 'applications/pholio/query/PholioMockQuery.php', 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', 'PholioPixelComment' => 'applications/pholio/storage/PholioPixelComment.php', + 'PholioReplyHandler' => 'applications/pholio/mail/PholioReplyHandler.php', 'PholioTransaction' => 'applications/pholio/storage/PholioTransaction.php', 'PholioTransactionQuery' => 'applications/pholio/query/PholioTransactionQuery.php', 'PholioTransactionType' => 'applications/pholio/constants/PholioTransactionType.php', @@ -2427,6 +2428,7 @@ phutil_register_library_map(array( 0 => 'PholioDAO', 1 => 'PhabricatorMarkupInterface', ), + 'PholioReplyHandler' => 'PhabricatorMailReplyHandler', 'PholioTransaction' => array( 0 => 'PholioDAO', diff --git a/src/applications/maniphest/editor/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/ManiphestTransactionEditor.php index 014b348c24..8fa7970dc4 100644 --- a/src/applications/maniphest/editor/ManiphestTransactionEditor.php +++ b/src/applications/maniphest/editor/ManiphestTransactionEditor.php @@ -6,7 +6,6 @@ final class ManiphestTransactionEditor extends PhabricatorEditor { private $parentMessageID; - private $excludePHIDs = array(); private $auxiliaryFields = array(); public function setAuxiliaryFields(array $fields) { @@ -20,15 +19,6 @@ final class ManiphestTransactionEditor extends PhabricatorEditor { return $this; } - public function setExcludePHIDs(array $exclude) { - $this->excludePHIDs = $exclude; - return $this; - } - - public function getExcludePHIDs() { - return $this->excludePHIDs; - } - public function applyTransactions(ManiphestTask $task, array $transactions) { assert_instances_of($transactions, 'ManiphestTransaction'); @@ -219,7 +209,6 @@ final class ManiphestTransactionEditor extends PhabricatorEditor { } private function sendEmail($task, $transactions, $email_to, $email_cc) { - $exclude = $this->getExcludePHIDs(); $email_to = array_filter(array_unique($email_to)); $email_cc = array_filter(array_unique($email_cc)); diff --git a/src/applications/pholio/editor/PholioMockEditor.php b/src/applications/pholio/editor/PholioMockEditor.php index a1f727a65f..b988db2bf4 100644 --- a/src/applications/pholio/editor/PholioMockEditor.php +++ b/src/applications/pholio/editor/PholioMockEditor.php @@ -41,6 +41,8 @@ final class PholioMockEditor extends PhabricatorEditor { "Call setContentSource() before applyTransactions()!"); } + $is_new = !$mock->getID(); + $comments = array(); foreach ($xactions as $xaction) { if (strlen($xaction->getComment())) { @@ -54,8 +56,12 @@ final class PholioMockEditor extends PhabricatorEditor { $mentioned_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( $comments); + $subscribe_phids = $mentioned_phids; - if ($mentioned_phids) { + // Attempt to subscribe the actor. + $subscribe_phids[] = $actor->getPHID(); + + if ($subscribe_phids) { if ($mock->getID()) { $old_subs = PhabricatorSubscribersQuery::loadSubscribersForPHID( $mock->getPHID()); @@ -111,11 +117,99 @@ final class PholioMockEditor extends PhabricatorEditor { $mock->saveTransaction(); + $this->sendMail($mock, $xactions, $is_new, $mentioned_phids); + PholioIndexer::indexMock($mock); return $this; } + private function sendMail( + PholioMock $mock, + array $xactions, + $is_new, + array $mentioned_phids) { + + $subscribed_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID( + $mock->getPHID()); + + $email_to = array( + $mock->getAuthorPHID(), + $this->requireActor()->getPHID(), + ); + $email_cc = $subscribed_phids; + + $phids = array_merge($email_to, $email_cc); + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($this->requireActor()) + ->loadHandles(); + + $mock_id = $mock->getID(); + $name = $mock->getName(); + $original_name = $mock->getOriginalName(); + + $thread_id = 'pholio-mock-'.$mock->getPHID(); + + $mail_tags = $this->getMailTags($mock, $xactions); + + $body = new PhabricatorMetaMTAMailBody(); + $body->addRawSection('lorem ipsum'); + + $mock_uri = PhabricatorEnv::getProductionURI('/M'.$mock->getID()); + + $body->addTextSection(pht('MOCK DETAIL'), $mock_uri); + + $reply_handler = $this->buildReplyHandler($mock); + + $template = id(new PhabricatorMetaMTAMail()) + ->setSubject("M{$mock_id}: {$name}") + ->setSubjectPrefix($this->getMailSubjectPrefix()) + ->setVarySubjectPrefix('[edit/create?]') + ->setFrom($this->requireActor()->getPHID()) + ->addHeader('Thread-Topic', "M{$mock_id}: {$original_name}") + ->setThreadID($thread_id, $is_new) + ->setRelatedPHID($mock->getPHID()) + ->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs()) + ->setIsBulk(true) + ->setMailTags($mail_tags) + ->setBody($body->render()); + + // TODO + // ->setParentMessageID(...) + + $mails = $reply_handler->multiplexMail( + $template, + array_select_keys($handles, $email_to), + array_select_keys($handles, $email_cc)); + + foreach ($mails as $mail) { + $mail->saveAndSend(); + } + + $template->addTos($email_to); + $template->addCCs($email_cc); + + return $template; + } + + private function getMailTags(PholioMock $mock, array $xactions) { + assert_instances_of($xactions, 'PholioTransaction'); + $tags = array(); + + return $tags; + } + + public function buildReplyHandler(PholioMock $mock) { + $handler_object = new PholioReplyHandler(); + $handler_object->setMailReceiver($mock); + + return $handler_object; + } + + private function getMailSubjectPrefix() { + return PhabricatorEnv::getEnvConfig('metamta.pholio.subject-prefix'); + } + private function applyTransaction( PholioMock $mock, PholioTransaction $xaction) { @@ -155,6 +249,9 @@ final class PholioMockEditor extends PhabricatorEditor { break; case PholioTransactionType::TYPE_NAME: $mock->setName($xaction->getNewValue()); + if ($mock->getOriginalName() === null) { + $mock->setOriginalName($xaction->getNewValue()); + } break; case PholioTransactionType::TYPE_DESCRIPTION: $mock->setDescription($xaction->getNewValue()); diff --git a/src/applications/pholio/mail/PholioReplyHandler.php b/src/applications/pholio/mail/PholioReplyHandler.php new file mode 100644 index 0000000000..e2ceb2c7d7 --- /dev/null +++ b/src/applications/pholio/mail/PholioReplyHandler.php @@ -0,0 +1,59 @@ +getDefaultPrivateReplyHandlerEmailAddress($handle, 'M'); + } + + public function getPublicReplyHandlerEmailAddress() { + return $this->getDefaultPublicReplyHandlerEmailAddress('M'); + } + + public function getReplyHandlerDomain() { + return PhabricatorEnv::getEnvConfig( + 'metamta.pholio.reply-handler-domain'); + } + + public function getReplyHandlerInstructions() { + if ($this->supportsReplies()) { + // TODO: Implement. + return null; + return "Reply to comment."; + } else { + return null; + } + } + + protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { + // TODO: Implement this. + return null; + } + +}