Page MenuHomePhabricator

D11329.id27202.diff
No OneTemporary

D11329.id27202.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1274,6 +1274,7 @@
'PhabricatorApplicationTransactionController' => 'applications/transactions/controller/PhabricatorApplicationTransactionController.php',
'PhabricatorApplicationTransactionDetailController' => 'applications/transactions/controller/PhabricatorApplicationTransactionDetailController.php',
'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php',
+ 'PhabricatorApplicationTransactionEmailWorker' => 'applications/transactions/worker/PhabricatorApplicationTransactionEmailWorker.php',
'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php',
'PhabricatorApplicationTransactionInterface' => 'applications/transactions/interface/PhabricatorApplicationTransactionInterface.php',
'PhabricatorApplicationTransactionNoEffectException' => 'applications/transactions/exception/PhabricatorApplicationTransactionNoEffectException.php',
@@ -1930,6 +1931,7 @@
'PhabricatorManiphestApplication' => 'applications/maniphest/application/PhabricatorManiphestApplication.php',
'PhabricatorManiphestConfigOptions' => 'applications/maniphest/config/PhabricatorManiphestConfigOptions.php',
'PhabricatorManiphestTaskTestDataGenerator' => 'applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php',
+ 'PhabricatorManiphestTransactionEmailWorker' => 'applications/maniphest/worker/PhabricatorManiphestTransactionEmailWorker.php',
'PhabricatorMarkupCache' => 'applications/cache/storage/PhabricatorMarkupCache.php',
'PhabricatorMarkupEngine' => 'infrastructure/markup/PhabricatorMarkupEngine.php',
'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php',
@@ -4435,6 +4437,7 @@
'PhabricatorApplicationTransactionController' => 'PhabricatorController',
'PhabricatorApplicationTransactionDetailController' => 'PhabricatorApplicationTransactionController',
'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor',
+ 'PhabricatorApplicationTransactionEmailWorker' => 'PhabricatorWorker',
'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory',
'PhabricatorApplicationTransactionNoEffectException' => 'Exception',
'PhabricatorApplicationTransactionNoEffectResponse' => 'AphrontProxyResponse',
@@ -5125,6 +5128,7 @@
'PhabricatorManiphestApplication' => 'PhabricatorApplication',
'PhabricatorManiphestConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorManiphestTaskTestDataGenerator' => 'PhabricatorTestDataGenerator',
+ 'PhabricatorManiphestTransactionEmailWorker' => 'PhabricatorApplicationTransactionEmailWorker',
'PhabricatorMarkupCache' => 'PhabricatorCacheDAO',
'PhabricatorMarkupOneOff' => 'PhabricatorMarkupInterface',
'PhabricatorMarkupPreviewController' => 'PhabricatorController',
diff --git a/src/applications/maniphest/editor/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/ManiphestTransactionEditor.php
--- a/src/applications/maniphest/editor/ManiphestTransactionEditor.php
+++ b/src/applications/maniphest/editor/ManiphestTransactionEditor.php
@@ -13,6 +13,10 @@
return pht('Maniphest Tasks');
}
+ protected function getTransactionEmailWorkerClass() {
+ return 'PhabricatorManiphestTransactionEmailWorker';
+ }
+
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
@@ -406,13 +410,13 @@
return $xactions;
}
- protected function getMailSubjectPrefix() {
+ /* protected function getMailSubjectPrefix() {
return PhabricatorEnv::getEnvConfig('metamta.maniphest.subject-prefix');
}
protected function getMailThreadID(PhabricatorLiskDAO $object) {
return 'maniphest-task-'.$object->getPHID();
- }
+ }*/
protected function getMailTo(PhabricatorLiskDAO $object) {
return array(
@@ -435,7 +439,7 @@
return $phids;
}
- public function getMailTagsMap() {
+ /* public function getMailTagsMap() {
return array(
ManiphestTransaction::MAILTAG_STATUS =>
pht("A task's status changes."),
@@ -456,23 +460,23 @@
ManiphestTransaction::MAILTAG_OTHER =>
pht('Other task activity not listed above occurs.'),
);
- }
+ }*/
- protected function buildReplyHandler(PhabricatorLiskDAO $object) {
+ /* protected function buildReplyHandler(PhabricatorLiskDAO $object) {
return id(new ManiphestReplyHandler())
->setMailReceiver($object);
- }
+ }*/
- protected function buildMailTemplate(PhabricatorLiskDAO $object) {
+ /* protected function buildMailTemplate(PhabricatorLiskDAO $object) {
$id = $object->getID();
$title = $object->getTitle();
return id(new PhabricatorMetaMTAMail())
->setSubject("T{$id}: {$title}")
->addHeader('Thread-Topic', "T{$id}: ".$object->getOriginalTitle());
- }
+ }*/
- protected function buildMailBody(
+ /* protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
@@ -517,7 +521,7 @@
return $body;
- }
+ }*/
protected function shouldPublishFeedStory(
PhabricatorLiskDAO $object,
@@ -549,6 +553,7 @@
HeraldTranscript $transcript) {
$this->heraldEmailPHIDs = $adapter->getEmailPHIDs();
+
$xactions = array();
$cc_phids = $adapter->getCcPHIDs();
diff --git a/src/applications/maniphest/worker/PhabricatorManiphestTransactionEmailWorker.php b/src/applications/maniphest/worker/PhabricatorManiphestTransactionEmailWorker.php
new file mode 100644
--- /dev/null
+++ b/src/applications/maniphest/worker/PhabricatorManiphestTransactionEmailWorker.php
@@ -0,0 +1,113 @@
+<?php
+
+final class PhabricatorManiphestTransactionEmailWorker
+ extends PhabricatorApplicationTransactionEmailWorker {
+
+ protected function loadObject($phid) {
+ $task = id(new ManiphestTaskQuery())
+ ->withPHIDs(array($phid))
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->executeOne();
+ return $task;
+ }
+
+ protected function loadXActions($xactions) {
+ $xactions = id(new ManiphestTransactionQuery())
+ ->withPHIDs($xactions)
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->execute();
+ return $xactions;
+ }
+
+ protected function buildReplyHandler(PhabricatorLiskDAO $object) {
+ return id(new ManiphestReplyHandler())
+ ->setMailReceiver($object);
+ }
+
+ protected function getMailSubjectPrefix() {
+ return PhabricatorEnv::getEnvConfig('metamta.maniphest.subject-prefix');
+ }
+
+ protected function getMailThreadID(PhabricatorLiskDAO $object) {
+ return 'maniphest-task-'.$object->getPHID();
+ }
+
+ public function getMailTagsMap() {
+ return array(
+ ManiphestTransaction::MAILTAG_STATUS =>
+ pht("A task's status changes."),
+ ManiphestTransaction::MAILTAG_OWNER =>
+ pht("A task's owner changes."),
+ ManiphestTransaction::MAILTAG_PRIORITY =>
+ pht("A task's priority changes."),
+ ManiphestTransaction::MAILTAG_CC =>
+ pht("A task's subscribers change."),
+ ManiphestTransaction::MAILTAG_PROJECTS =>
+ pht("A task's associated projects change."),
+ ManiphestTransaction::MAILTAG_UNBLOCK =>
+ pht('One of the tasks a task is blocked by changes status.'),
+ ManiphestTransaction::MAILTAG_COLUMN =>
+ pht('A task is moved between columns on a workboard.'),
+ ManiphestTransaction::MAILTAG_COMMENT =>
+ pht('Someone comments on a task.'),
+ ManiphestTransaction::MAILTAG_OTHER =>
+ pht('Other task activity not listed above occurs.'),
+ );
+ }
+
+ protected function buildMailTemplate(PhabricatorLiskDAO $object) {
+ $id = $object->getID();
+ $title = $object->getTitle();
+
+ return id(new PhabricatorMetaMTAMail())
+ ->setSubject("T{$id}: {$title}")
+ ->addHeader('Thread-Topic', "T{$id}: ".$object->getOriginalTitle());
+ }
+
+ protected function buildMailBody(
+ PhabricatorLiskDAO $object,
+ array $xactions,
+ PhabricatorUser $viewer) {
+
+ $body = parent::buildMailBody($object, $xactions, $viewer);
+
+ if ($this->getIsNewObject()) {
+ $body->addTextSection(
+ pht('TASK DESCRIPTION'),
+ $object->getDescription());
+ }
+
+ $body->addLinkSection(
+ pht('TASK DETAIL'),
+ PhabricatorEnv::getProductionURI('/T'.$object->getID()));
+
+
+ $board_phids = array();
+ $type_column = ManiphestTransaction::TYPE_PROJECT_COLUMN;
+ foreach ($xactions as $xaction) {
+ if ($xaction->getTransactionType() == $type_column) {
+ $new = $xaction->getNewValue();
+ $project_phid = idx($new, 'projectPHID');
+ if ($project_phid) {
+ $board_phids[] = $project_phid;
+ }
+ }
+ }
+
+ if ($board_phids) {
+ $projects = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($board_phids)
+ ->execute();
+
+ foreach ($projects as $project) {
+ $body->addLinkSection(
+ pht('WORKBOARD'),
+ PhabricatorEnv::getProductionURI(
+ '/project/board/'.$project->getID().'/'));
+ }
+ }
+
+ return $body;
+ }
+}
diff --git a/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php b/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
--- a/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
+++ b/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
@@ -197,6 +197,35 @@
// for now.
$recipients = $tos + $ccs;
+ // Check if all recipients have proper permissions to the object
+ // Remove them from the list otherwise
+ $recipient_users = id(new PhabricatorPeopleQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs(array_keys($recipients))
+ ->execute();
+ $recipient_users = mpull($recipient_users, null, 'getPHID');
+
+ // Check if user has permissions to view this object
+ foreach ($recipients as $phid => $recipient) {
+ if ($this->mailReceiver
+ && $this->mailReceiver instanceof PhabricatorPolicyInterface
+ && idx($recipient_users, $phid)
+ && $recipient_users[$phid] instanceof PhabricatorUser) {
+ if (!PhabricatorPolicyFilter::hasCapability(
+ $recipient_users[$phid],
+ $this->mailReceiver,
+ PhabricatorPolicyCapability::CAN_VIEW)) {
+ // User has no permission to this object
+ // so remove them from the recipient list
+ unset($recipients[$phid]);
+ }
+ }
+ }
+
+ if (!$recipients) {
+ return $result;
+ }
+
// When multiplexing mail, explicitly include To/Cc information in the
// message body and headers.
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -29,6 +29,7 @@
private $actingAsPHID;
private $disableEmail;
+ protected $emailData;
/**
* Get the class name for the application this editor is a part of.
@@ -794,6 +795,7 @@
$mail = null;
if (!$this->getDisableEmail()) {
if ($this->shouldSendMail($object, $xactions)) {
+ // FIXME: fix the $mail recipient list for the feed
$mail = $this->sendMail($object, $xactions);
}
}
@@ -1906,6 +1908,11 @@
return false;
}
+ // FIXME: Make abstract?
+ protected function getTransactionEmailWorkerClass() {
+ throw new Exception('This function needs to be implemented to be able to render Email');
+ }
+
/**
* @task mail
@@ -1916,7 +1923,6 @@
// Check if any of the transactions are visible. If we don't have any
// visible transactions, don't send the mail.
-
$any_visible = false;
foreach ($xactions as $xaction) {
if (!$xaction->shouldHideForMail($xactions)) {
@@ -1929,10 +1935,39 @@
return;
}
+ $herald_xscript = $this->getHeraldTranscript();
+ if ($herald_xscript) {
+ $herald_header = $herald_xscript->getXHeraldRulesHeader();
+ $herald_header = HeraldTranscript::saveXHeraldRulesHeader(
+ $object->getPHID(),
+ $herald_header);
+ } else {
+ $herald_header = HeraldTranscript::loadXHeraldRulesHeader(
+ $object->getPHID());
+ }
+
+ PhabricatorWorker::scheduleTask(
+ $this->getTransactionEmailWorkerClass(),
+ array(
+ 'object' => $object->getPHID(),
+ 'xactions' => mpull($xactions, 'getPHID'),
+ 'mailTo' => $this->getMailTo($object),
+ 'mailCC' => $this->getMailCC($object),
+ 'actingAsPHID' => $this->getActingAsPHID(),
+ 'isNewObject' => $this->getIsNewObject(),
+ 'heraldHeader' => $herald_header,
+ 'excludeMailRecipientPHIDs' => $this->getExcludeMailRecipientPHIDs(),
+ 'parentMessageID' => $this->getParentMessageID(),
+ ),
+ array(
+ 'priority' => PhabricatorWorker::PRIORITY_ALERTS, // FIXME: right prio?
+ ));
+
+ /*
$email_to = array_filter(array_unique($this->getMailTo($object)));
$email_cc = array_filter(array_unique($this->getMailCC($object)));
-
$phids = array_merge($email_to, $email_cc);
+
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->requireActor())
->withPHIDs($phids)
@@ -2003,10 +2038,12 @@
$template->addTos($email_to);
$template->addCCs($email_cc);
- return $template;
+ return $template;*/
+
+ return null;
}
- private function addMailProjectMetadata(
+ /* private function addMailProjectMetadata(
PhabricatorLiskDAO $object,
PhabricatorMetaMTAMail $template) {
@@ -2046,37 +2083,38 @@
protected function getMailThreadID(PhabricatorLiskDAO $object) {
return $object->getPHID();
- }
+ }*/
/**
* @task mail
*/
- protected function getStrongestAction(
+ /* protected function getStrongestAction(
PhabricatorLiskDAO $object,
array $xactions) {
return last(msort($xactions, 'getActionStrength'));
- }
+ }*/
/**
* @task mail
*/
- protected function buildReplyHandler(PhabricatorLiskDAO $object) {
+ /* protected function buildReplyHandler(PhabricatorLiskDAO $object) {
throw new Exception('Capability not supported.');
- }
+ }*/
/**
* @task mail
*/
- protected function getMailSubjectPrefix() {
+ /* protected function getMailSubjectPrefix() {
throw new Exception('Capability not supported.');
- }
+ }*/
/**
* @task mail
*/
+ // FIXME: Only needed for feeds now
protected function getMailTags(
PhabricatorLiskDAO $object,
array $xactions) {
@@ -2092,28 +2130,28 @@
/**
* @task mail
*/
- public function getMailTagsMap() {
+ /* public function getMailTagsMap() {
// TODO: We should move shared mail tags, like "comment", here.
return array();
- }
+ }*/
/**
* @task mail
*/
- protected function getMailAction(
+ /* protected function getMailAction(
PhabricatorLiskDAO $object,
array $xactions) {
return $this->getStrongestAction($object, $xactions)->getActionName();
- }
+ }*/
/**
* @task mail
*/
- protected function buildMailTemplate(PhabricatorLiskDAO $object) {
+ /* protected function buildMailTemplate(PhabricatorLiskDAO $object) {
throw new Exception('Capability not supported.');
- }
+ }*/
/**
@@ -2187,7 +2225,7 @@
/**
* @task mail
*/
- protected function buildMailBody(
+ /* protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
@@ -2234,7 +2272,7 @@
}
return $body;
- }
+ }*/
/* -( Publishing Feed Stories )-------------------------------------------- */
diff --git a/src/applications/transactions/worker/PhabricatorApplicationTransactionEmailWorker.php b/src/applications/transactions/worker/PhabricatorApplicationTransactionEmailWorker.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/worker/PhabricatorApplicationTransactionEmailWorker.php
@@ -0,0 +1,347 @@
+<?php
+
+abstract class PhabricatorApplicationTransactionEmailWorker
+ extends PhabricatorWorker {
+
+ private $actingAsPHID;
+ private $isNewObject;
+ private $heraldHeader;
+ private $excludeMailRecipientPHIDs;
+ private $parentMessageID;
+
+ abstract protected function loadObject($phid);
+ abstract protected function loadXActions($xactions);
+ abstract protected function buildReplyHandler(PhabricatorLiskDAO $object);
+
+ public function getMaximumRetryCount() {
+ return 250;
+ }
+
+ public function getWaitBeforeRetry(PhabricatorWorkerTask $task) {
+ return ($task->getFailureCount() * 15);
+ }
+
+ public function getActingAsPHID() {
+ return $this->actingAsPHID;
+ }
+
+ public function getIsNewObject() {
+ return $this->isNewObject;
+ }
+
+ public function doWork() {
+ $task_data = $this->getTaskData();
+
+ if (!idx($task_data, 'actingAsPHID')) {
+ throw new PhabricatorWorkerPermanentFailureException(
+ pht('Missing actingAsPHID in Tasks Data'));
+ }
+ $this->actingAsPHID = $task_data['actingAsPHID'];
+
+ if (!idx($task_data, 'mailTo')) {
+ throw new PhabricatorWorkerPermanentFailureException(
+ pht('Missing mailTo in Tasks Data'));
+ }
+ $mailTo = $task_data['mailTo'];
+
+ if (!idx($task_data, 'mailCC')) {
+ throw new PhabricatorWorkerPermanentFailureException(
+ pht('Missing mailCC in Tasks Data'));
+ }
+ $mailCC = $task_data['mailCC'];
+
+ $this->heraldHeader = idx($task_data, 'heraldHeader', null);
+
+ $this->isNewObject = idx($task_data, 'isNewObject', false);
+
+ $this->excludeMailRecipientPHIDs = idx($task_data, 'excludeMailRecipientPHIDs');
+
+ $this->parentMessageID = idx($task_data, 'parentMessageID');
+
+ $this->aux_data = idx($task_data, 'aux_data', null);
+
+ $object = $this->loadObject($task_data['object']);
+ if (!$object) {
+ throw new PhabricatorWorkerPermanentFailureException(
+ pht('Unable to load object!'));
+ }
+
+ $xactions = $this->loadXActions($task_data['xactions']);
+ assert_instances_of($xactions, 'PhabricatorApplicationTransaction');
+
+ $email_to = $this->expandPHIDs(array_filter(array_unique($mailTo)));
+ $email_cc = $this->expandPHIDs(array_filter(array_unique($mailCC)));
+ $recipients = array_merge($email_to, $email_cc);
+
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs($recipients)
+ ->execute();
+ $users = mpull($users, null, 'getPHID');
+
+ foreach ($users as $key => $user) {
+ // Check if the receiving user has permissions to view this object
+ if ($object
+ && $object instanceof PhabricatorPolicyInterface
+ && $user
+ && $user instanceof PhabricatorUser) {
+ if (!PhabricatorPolicyFilter::hasCapability(
+ $user,
+ $object,
+ PhabricatorPolicyCapability::CAN_VIEW)) {
+ // User has no permission to this object
+ // so remove them from all lists
+ unset($users[$key]);
+ $phid = array($user->getPHID());
+ $recipients = array_diff($recipients, $phid);
+ $email_to = array_diff($email_to, $phid);
+ $email_cc = array_diff($email_cc, $phid);
+ }
+ }
+ }
+
+ $handles = id(new PhabricatorHandleQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs($recipients)
+ ->execute();
+
+ $to_handles = array_select_keys($handles, $email_to);
+ $cc_handles = array_select_keys($handles, $email_cc);
+
+ $emails = array();
+ $send_as_one_email = false;
+ // Render the email for each user individually so correct permissions are preserved
+ foreach ($recipients as $recipient) {
+ $viewer = $users[$recipient];
+
+ $template = $this->buildMailTemplate($object);
+ $template->addPHIDHeaders('X-Phabricator-To', array_keys($email_to));
+ $template->addPHIDHeaders('X-Phabricator-Cc', array_keys($email_cc));
+
+ if (!PhabricatorMetaMTAMail::shouldMultiplexAllMail()) {
+ // If config is set to not multiplex we render as the triggering user
+ $viewer = $users[$this->getActingAsPHID()];
+ $template->addTos($email_to);
+ $template->addCCs($email_cc);
+ $send_as_one_email = true;
+ } else {
+ $template->addTos(array($recipient));
+ }
+
+ // This stuff doesen't change per user. We still handle
+ // it here to support sending in the users locale in the future.
+ $mail_tags = $this->getMailTags($object, $xactions);
+ $action = $this->getMailAction($object, $xactions);
+ $reply_handler = $this->buildReplyHandler($object);
+ $reply_section = $reply_handler->getReplyHandlerInstructions();
+
+ // Render the actual mail body
+ $body = $this->buildMailBody($object, $xactions, $viewer);
+
+ if ($reply_section !== null) {
+ $body->addReplySection($reply_section);
+ }
+
+ $body->addEmailPreferenceSection();
+
+ // FIXME?: This changes the emails a bit (adds a RECIPIENTS header at the bottom)
+ $body->addPlainTextSection('RECIPIENTS', $reply_handler->getRecipientsSummary($to_handles, $cc_handles));
+ $body->addHTMLSection('RECIPIENTS', $reply_handler->getRecipientsSummaryHTML($to_handles, $cc_handles));
+
+ // TODO: Reply-To handling is still missing
+
+ $template
+ ->setFrom($this->getActingAsPHID())
+ ->setSubjectPrefix($this->getMailSubjectPrefix())
+ ->setVarySubjectPrefix('['.$action.']')
+ ->setThreadID($this->getMailThreadID($object), $this->getIsNewObject())
+ ->setRelatedPHID($object->getPHID())
+ ->setExcludeMailRecipientPHIDs($this->excludeMailRecipientPHIDs)
+ ->setMailTags($mail_tags)
+ ->setIsBulk(true)
+ ->setBody($body->render())
+ ->setHTMLBody($body->renderHTML());
+
+ foreach ($body->getAttachments() as $attachment) {
+ $template->addAttachment($attachment);
+ }
+
+ if ($this->heraldHeader) {
+ $template->addHeader('X-Herald-Rules', $this->heraldHeader);
+ }
+
+ if ($object instanceof PhabricatorProjectInterface) {
+ $this->addMailProjectMetadata($object, $template, $viewer);
+ }
+
+ if ($this->parentMessageID) {
+ $template->setParentMessageID($this->parentMessageID);
+ }
+
+ $emails[] = $template;
+
+ if ($send_as_one_email) {
+ // We send all users just a single email
+ break;
+ }
+ }
+
+ foreach ($emails as $mail) {
+ $mail->saveAndSend();
+ }
+
+ return true;
+ }
+
+ protected function expandPHIDs($phids) {
+ // Expand recipients (get projects members)
+ $map = id(new PhabricatorMetaMTAMemberQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs($phids)
+ ->execute();
+
+ $results = array();
+ foreach ($phids as $phid) {
+ if (isset($map[$phid])) {
+ foreach ($map[$phid] as $expanded_phid) {
+ $results[$expanded_phid] = $expanded_phid;
+ }
+ } else {
+ $results[$phid] = $phid;
+ }
+ }
+ return $results;
+ }
+
+ // FIXME: Make abstract?
+ protected function buildMailTemplate(PhabricatorLiskDAO $object) {
+ throw new Exception('Capability not supported.');
+ }
+
+ // FIXME: Make abstract?
+ protected function getMailSubjectPrefix() {
+ throw new Exception('Capability not supported.');
+ }
+
+ private function addMailProjectMetadata(
+ PhabricatorLiskDAO $object,
+ PhabricatorMetaMTAMail $template,
+ PhabricatorUser $viewer) {
+
+ $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $object->getPHID(),
+ PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
+
+ if (!$project_phids) {
+ return;
+ }
+
+ // TODO: This viewer isn't quite right. It would be slightly better to use
+ // the mail recipient, but that's not very easy given the way rendering
+ // works today.
+
+ $handles = id(new PhabricatorHandleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($project_phids)
+ ->execute();
+
+ $project_tags = array();
+ foreach ($handles as $handle) {
+ if (!$handle->isComplete()) {
+ continue;
+ }
+ $project_tags[] = '<'.$handle->getObjectName().'>';
+ }
+
+ if (!$project_tags) {
+ return;
+ }
+
+ $project_tags = implode(', ', $project_tags);
+ $template->addHeader('X-Phabricator-Projects', $project_tags);
+ }
+
+
+ protected function getMailThreadID(PhabricatorLiskDAO $object) {
+ return $object->getPHID();
+ }
+
+ protected function getMailTags(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ $tags = array();
+
+ foreach ($xactions as $xaction) {
+ $tags[] = $xaction->getMailTags();
+ }
+
+ return array_mergev($tags);
+ }
+
+ public function getMailTagsMap() {
+ // TODO: We should move shared mail tags, like "comment", here.
+ return array();
+ }
+
+ protected function getStrongestAction(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return last(msort($xactions, 'getActionStrength'));
+ }
+
+ protected function getMailAction(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return $this->getStrongestAction($object, $xactions)->getActionName();
+ }
+
+ protected function buildMailBody(
+ PhabricatorLiskDAO $object,
+ array $xactions,
+ PhabricatorUser $viewer) {
+
+ $headers = array();
+ $comments = array();
+
+ foreach ($xactions as $xaction) {
+ if ($xaction->shouldHideForMail($xactions)) {
+ continue;
+ }
+
+ $header = $xaction->getTitleForMail();
+ if ($header !== null) {
+ $headers[] = $header;
+ }
+
+ $comment = $xaction->getBodyForMail();
+ if ($comment !== null) {
+ $comments[] = $comment;
+ }
+ }
+
+ $body = new PhabricatorMetaMTAMailBody();
+ $body->setViewer($viewer);
+ $body->addRawSection(implode("\n", $headers));
+
+ foreach ($comments as $comment) {
+ $body->addRemarkupSection($comment);
+ }
+
+ if ($object instanceof PhabricatorCustomFieldInterface) {
+ $field_list = PhabricatorCustomField::getObjectFields(
+ $object,
+ PhabricatorCustomField::ROLE_TRANSACTIONMAIL);
+ $field_list->setViewer($viewer);
+ $field_list->readFieldsFromStorage($object);
+
+ foreach ($field_list->getFields() as $field) {
+ $field->updateTransactionMailBody(
+ $body,
+ $this,
+ $xactions);
+ }
+ }
+
+ return $body;
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 8, 8:57 PM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
9261068
Default Alt Text
D11329.id27202.diff (26 KB)

Event Timeline