mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +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(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
// $this->sendMail($object, $xactions);
|
||||
// PholioIndexer::indexMock($mock);
|
||||
return;
|
||||
}
|
||||
|
@ -84,92 +83,46 @@ final class PholioMockEditor extends PhabricatorApplicationTransactionEditor {
|
|||
return parent::mergeTransactions($u, $v);
|
||||
}
|
||||
|
||||
protected function supportsMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private function sendMail(
|
||||
PholioMock $mock,
|
||||
array $xactions,
|
||||
$is_new,
|
||||
array $mentioned_phids) {
|
||||
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||
return id(new PholioReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
}
|
||||
|
||||
$subscribed_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$mock->getPHID());
|
||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||
$id = $object->getID();
|
||||
$name = $object->getName();
|
||||
$original_name = $object->getOriginalName();
|
||||
|
||||
$email_to = array(
|
||||
$mock->getAuthorPHID(),
|
||||
return id(new PhabricatorMetaMTAMail())
|
||||
->setSubject("M{$id}: {$name}")
|
||||
->addHeader('Thread-Topic', "M{$id}: {$original_name}");
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
return array(
|
||||
$object->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();
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
return $tags;
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
$body->addTextSection(
|
||||
pht('MOCK DETAIL'),
|
||||
PhabricatorEnv::getProductionURI('/M'.$object->getID()));
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
public function buildReplyHandler(PholioMock $mock) {
|
||||
$handler_object = new PholioReplyHandler();
|
||||
$handler_object->setMailReceiver($mock);
|
||||
|
||||
return $handler_object;
|
||||
}
|
||||
|
||||
private function getMailSubjectPrefix() {
|
||||
protected function getMailSubjectPrefix() {
|
||||
return PhabricatorEnv::getEnvConfig('metamta.pholio.subject-prefix');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @task mail Sending Mail
|
||||
*/
|
||||
abstract class PhabricatorApplicationTransactionEditor
|
||||
extends PhabricatorEditor {
|
||||
|
||||
|
@ -202,6 +205,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
}
|
||||
|
||||
if (!$xactions) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$xactions = $this->sortTransactions($xactions);
|
||||
|
||||
$comment_editor = id(new PhabricatorApplicationTransactionCommentEditor())
|
||||
|
@ -230,7 +237,15 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
$object->saveTransaction();
|
||||
|
||||
// TODO: Send mail.
|
||||
|
||||
$this->loadHandles($xactions);
|
||||
|
||||
|
||||
$mail = null;
|
||||
if ($this->supportsMail()) {
|
||||
$mail = $this->sendMail($object, $xactions);
|
||||
}
|
||||
|
||||
// TODO: Index object.
|
||||
// TODO: Publish feed/notifications.
|
||||
|
||||
|
@ -239,6 +254,26 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
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(
|
||||
PhabricatorLiskDAO $object,
|
||||
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 TARGET_TEXT = 'text';
|
||||
const TARGET_HTML = 'html';
|
||||
|
||||
protected $phid;
|
||||
protected $objectPHID;
|
||||
protected $authorPHID;
|
||||
|
@ -25,6 +28,7 @@ abstract class PhabricatorApplicationTransaction
|
|||
private $commentNotLoaded;
|
||||
|
||||
private $handles;
|
||||
private $renderingTarget = self::TARGET_HTML;
|
||||
|
||||
abstract public function getApplicationTransactionType();
|
||||
abstract public function getApplicationTransactionCommentObject();
|
||||
|
@ -77,6 +81,15 @@ abstract class PhabricatorApplicationTransaction
|
|||
|
||||
/* -( Rendering )---------------------------------------------------------- */
|
||||
|
||||
public function setRenderingTarget($rendering_target) {
|
||||
$this->renderingTarget = $rendering_target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRenderingTarget() {
|
||||
return $this->renderingTarget;
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = array();
|
||||
|
||||
|
@ -108,7 +121,11 @@ abstract class PhabricatorApplicationTransaction
|
|||
}
|
||||
|
||||
protected function renderHandleLink($phid) {
|
||||
return $this->getHandle($phid)->renderLink();
|
||||
if ($this->renderingTarget == self::TARGET_HTML) {
|
||||
return $this->getHandle($phid)->renderLink();
|
||||
} else {
|
||||
return $this->getHandle($phid)->getName();
|
||||
}
|
||||
}
|
||||
|
||||
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 )-------------------------- */
|
||||
|
||||
|
|
|
@ -112,14 +112,16 @@ JX.behavior('phabricator-nav', function(config) {
|
|||
// When the user scrolls down on the desktop, we move the local nav up until
|
||||
// it hits the top of the page.
|
||||
|
||||
JX.Stratcom.listen(['scroll', 'resize'], null, function(e) {
|
||||
if (JX.Device.getDevice() != 'desktop') {
|
||||
return;
|
||||
}
|
||||
if (local) {
|
||||
JX.Stratcom.listen(['scroll', 'resize'], null, function(e) {
|
||||
if (JX.Device.getDevice() != 'desktop') {
|
||||
return;
|
||||
}
|
||||
|
||||
var y = Math.max(0, config.menuSize - JX.Vector.getScroll().y);
|
||||
local.style.top = y + 'px';
|
||||
});
|
||||
var y = Math.max(0, config.menuSize - JX.Vector.getScroll().y);
|
||||
local.style.top = y + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// - Navigation Reset ----------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue