mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Add mail support to generic transactions
Summary: - Adds mail support to the generic transaction construct. - Restores mail support to Pholio (now much improved; the mails are actually useful). Test Plan: Updated a Pholio mock, got mail. Reviewers: btrahan, chad, vrana Reviewed By: btrahan CC: aran Maniphest Tasks: T2104 Differential Revision: https://secure.phabricator.com/D4139
This commit is contained in:
parent
7341c74276
commit
1d5ace45bd
4 changed files with 282 additions and 85 deletions
|
@ -19,7 +19,6 @@ final class PholioMockEditor extends PhabricatorApplicationTransactionEditor {
|
||||||
protected function didApplyTransactions(
|
protected function didApplyTransactions(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
// $this->sendMail($object, $xactions);
|
|
||||||
// PholioIndexer::indexMock($mock);
|
// PholioIndexer::indexMock($mock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,92 +83,46 @@ final class PholioMockEditor extends PhabricatorApplicationTransactionEditor {
|
||||||
return parent::mergeTransactions($u, $v);
|
return parent::mergeTransactions($u, $v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function supportsMail() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private function sendMail(
|
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||||
PholioMock $mock,
|
return id(new PholioReplyHandler())
|
||||||
array $xactions,
|
->setMailReceiver($object);
|
||||||
$is_new,
|
}
|
||||||
array $mentioned_phids) {
|
|
||||||
|
|
||||||
$subscribed_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$mock->getPHID());
|
$id = $object->getID();
|
||||||
|
$name = $object->getName();
|
||||||
|
$original_name = $object->getOriginalName();
|
||||||
|
|
||||||
$email_to = array(
|
return id(new PhabricatorMetaMTAMail())
|
||||||
$mock->getAuthorPHID(),
|
->setSubject("M{$id}: {$name}")
|
||||||
|
->addHeader('Thread-Topic', "M{$id}: {$original_name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
return array(
|
||||||
|
$object->getAuthorPHID(),
|
||||||
$this->requireActor()->getPHID(),
|
$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);
|
protected function buildMailBody(
|
||||||
$template->addCCs($email_cc);
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
return $template;
|
$body = parent::buildMailBody($object, $xactions);
|
||||||
|
$body->addTextSection(
|
||||||
|
pht('MOCK DETAIL'),
|
||||||
|
PhabricatorEnv::getProductionURI('/M'.$object->getID()));
|
||||||
|
|
||||||
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMailTags(PholioMock $mock, array $xactions) {
|
protected function getMailSubjectPrefix() {
|
||||||
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');
|
return PhabricatorEnv::getEnvConfig('metamta.pholio.subject-prefix');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail Sending Mail
|
||||||
|
*/
|
||||||
abstract class PhabricatorApplicationTransactionEditor
|
abstract class PhabricatorApplicationTransactionEditor
|
||||||
extends PhabricatorEditor {
|
extends PhabricatorEditor {
|
||||||
|
|
||||||
|
@ -202,6 +205,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$xactions) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
$xactions = $this->sortTransactions($xactions);
|
$xactions = $this->sortTransactions($xactions);
|
||||||
|
|
||||||
$comment_editor = id(new PhabricatorApplicationTransactionCommentEditor())
|
$comment_editor = id(new PhabricatorApplicationTransactionCommentEditor())
|
||||||
|
@ -230,7 +237,15 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
$object->saveTransaction();
|
$object->saveTransaction();
|
||||||
|
|
||||||
// TODO: Send mail.
|
|
||||||
|
$this->loadHandles($xactions);
|
||||||
|
|
||||||
|
|
||||||
|
$mail = null;
|
||||||
|
if ($this->supportsMail()) {
|
||||||
|
$mail = $this->sendMail($object, $xactions);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Index object.
|
// TODO: Index object.
|
||||||
// TODO: Publish feed/notifications.
|
// TODO: Publish feed/notifications.
|
||||||
|
|
||||||
|
@ -239,6 +254,26 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function loadHandles(array $xactions) {
|
||||||
|
$phids = array();
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$phids[$xaction->getPHID()] = $xaction->getRequiredHandlePHIDs();
|
||||||
|
}
|
||||||
|
$handles = array();
|
||||||
|
$merged = array_mergev($phids);
|
||||||
|
if ($merged) {
|
||||||
|
$handles = id(new PhabricatorObjectHandleData($merged))
|
||||||
|
->setViewer($this->requireActor())
|
||||||
|
->loadHandles();
|
||||||
|
}
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$xaction->setHandles(
|
||||||
|
array_select_keys(
|
||||||
|
$handles,
|
||||||
|
$phids[$xaction->getPHID()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function validateEditParameters(
|
private function validateEditParameters(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
@ -484,4 +519,168 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Sending Mail )------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function supportsMail() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function sendMail(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$email_to = $this->getMailTo($object);
|
||||||
|
$email_cc = $this->getMailCC($object);
|
||||||
|
|
||||||
|
$phids = array_merge($email_to, $email_cc);
|
||||||
|
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||||
|
->setViewer($this->requireActor())
|
||||||
|
->loadHandles();
|
||||||
|
|
||||||
|
$template = $this->buildMailTemplate($object);
|
||||||
|
$body = $this->buildMailBody($object, $xactions);
|
||||||
|
|
||||||
|
$mail_tags = $this->getMailTags($object, $xactions);
|
||||||
|
|
||||||
|
$action = $this->getStrongestAction($object, $xactions);
|
||||||
|
|
||||||
|
$template
|
||||||
|
->setFrom($this->requireActor()->getPHID())
|
||||||
|
->setSubjectPrefix($this->getMailSubjectPrefix())
|
||||||
|
->setVarySubjectPrefix('['.$action.']')
|
||||||
|
->setThreadID($object->getPHID(), $this->getIsNewObject())
|
||||||
|
->setRelatedPHID($object->getPHID())
|
||||||
|
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
|
||||||
|
->setMailTags($mail_tags)
|
||||||
|
->setIsBulk(true)
|
||||||
|
->setBody($body->render());
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// ->setParentMessageID(...)
|
||||||
|
|
||||||
|
$mails = $this
|
||||||
|
->buildReplyHandler($object)
|
||||||
|
->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function getStrongestAction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
return last(msort($xactions, 'getActionStrength'))->getActionName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||||
|
throw new Exception("Capability not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function getMailSubjectPrefix() {
|
||||||
|
throw new Exception("Capability not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function getMailTags(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
$tags = array();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$tags[] = $xaction->getMailTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_mergev($tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
|
throw new Exception("Capability not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
throw new Exception("Capability not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function getMailCC(PhabricatorLiskDAO $object) {
|
||||||
|
if ($object instanceof PhabricatorSubscribableInterface) {
|
||||||
|
$phid = $object->getPHID();
|
||||||
|
return PhabricatorSubscribersQuery::loadSubscribersForPHID($phid);
|
||||||
|
}
|
||||||
|
throw new Exception("Capability not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task mail
|
||||||
|
*/
|
||||||
|
protected function buildMailBody(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$headers = array();
|
||||||
|
$comments = array();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$headers[] = id(clone $xaction)->setRenderingTarget('text')->getTitle();
|
||||||
|
$comment = $xaction->getComment();
|
||||||
|
if ($comment && strlen($comment->getContent())) {
|
||||||
|
$comments[] = $comment->getContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = new PhabricatorMetaMTAMailBody();
|
||||||
|
$body->addRawSection(implode("\n", $headers));
|
||||||
|
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
$body->addRawSection($comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ abstract class PhabricatorApplicationTransaction
|
||||||
|
|
||||||
const MARKUP_FIELD_COMMENT = 'markup:comment';
|
const MARKUP_FIELD_COMMENT = 'markup:comment';
|
||||||
|
|
||||||
|
const TARGET_TEXT = 'text';
|
||||||
|
const TARGET_HTML = 'html';
|
||||||
|
|
||||||
protected $phid;
|
protected $phid;
|
||||||
protected $objectPHID;
|
protected $objectPHID;
|
||||||
protected $authorPHID;
|
protected $authorPHID;
|
||||||
|
@ -25,6 +28,7 @@ abstract class PhabricatorApplicationTransaction
|
||||||
private $commentNotLoaded;
|
private $commentNotLoaded;
|
||||||
|
|
||||||
private $handles;
|
private $handles;
|
||||||
|
private $renderingTarget = self::TARGET_HTML;
|
||||||
|
|
||||||
abstract public function getApplicationTransactionType();
|
abstract public function getApplicationTransactionType();
|
||||||
abstract public function getApplicationTransactionCommentObject();
|
abstract public function getApplicationTransactionCommentObject();
|
||||||
|
@ -77,6 +81,15 @@ abstract class PhabricatorApplicationTransaction
|
||||||
|
|
||||||
/* -( Rendering )---------------------------------------------------------- */
|
/* -( Rendering )---------------------------------------------------------- */
|
||||||
|
|
||||||
|
public function setRenderingTarget($rendering_target) {
|
||||||
|
$this->renderingTarget = $rendering_target;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRenderingTarget() {
|
||||||
|
return $this->renderingTarget;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRequiredHandlePHIDs() {
|
public function getRequiredHandlePHIDs() {
|
||||||
$phids = array();
|
$phids = array();
|
||||||
|
|
||||||
|
@ -108,7 +121,11 @@ abstract class PhabricatorApplicationTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function renderHandleLink($phid) {
|
protected function renderHandleLink($phid) {
|
||||||
|
if ($this->renderingTarget == self::TARGET_HTML) {
|
||||||
return $this->getHandle($phid)->renderLink();
|
return $this->getHandle($phid)->renderLink();
|
||||||
|
} else {
|
||||||
|
return $this->getHandle($phid)->getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function renderHandleList(array $phids) {
|
protected function renderHandleList(array $phids) {
|
||||||
|
@ -203,6 +220,32 @@ abstract class PhabricatorApplicationTransaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getActionStrength() {
|
||||||
|
switch ($this->getTransactionType()) {
|
||||||
|
case PhabricatorTransactions::TYPE_COMMENT:
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionName() {
|
||||||
|
switch ($this->getTransactionType()) {
|
||||||
|
case PhabricatorTransactions::TYPE_COMMENT:
|
||||||
|
return pht('Commented On');
|
||||||
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
|
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||||
|
return pht('Changed Policy');
|
||||||
|
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||||
|
return pht('Changed Subscribers');
|
||||||
|
default:
|
||||||
|
return pht('Updated');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMailTags() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
|
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,7 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
// When the user scrolls down on the desktop, we move the local nav up until
|
// When the user scrolls down on the desktop, we move the local nav up until
|
||||||
// it hits the top of the page.
|
// it hits the top of the page.
|
||||||
|
|
||||||
|
if (local) {
|
||||||
JX.Stratcom.listen(['scroll', 'resize'], null, function(e) {
|
JX.Stratcom.listen(['scroll', 'resize'], null, function(e) {
|
||||||
if (JX.Device.getDevice() != 'desktop') {
|
if (JX.Device.getDevice() != 'desktop') {
|
||||||
return;
|
return;
|
||||||
|
@ -120,6 +121,7 @@ JX.behavior('phabricator-nav', function(config) {
|
||||||
var y = Math.max(0, config.menuSize - JX.Vector.getScroll().y);
|
var y = Math.max(0, config.menuSize - JX.Vector.getScroll().y);
|
||||||
local.style.top = y + 'px';
|
local.style.top = y + 'px';
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// - Navigation Reset ----------------------------------------------------------
|
// - Navigation Reset ----------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue