mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 14:00:56 +01:00
Add basic support for Herald outbound rules
Summary: Ref T5791. This is still very basic (no global actions, no support for matching headers/bodies/recipients/etc) but gets the core in. Test Plan: {F715209} {F715211} Reviewers: chad Reviewed By: chad Maniphest Tasks: T5791 Differential Revision: https://secure.phabricator.com/D13897
This commit is contained in:
parent
bb0d13345d
commit
7a1bbe6634
17 changed files with 570 additions and 17 deletions
|
@ -2247,6 +2247,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php',
|
||||
'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php',
|
||||
'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php',
|
||||
'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php',
|
||||
'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php',
|
||||
'PhabricatorMailEmailSubjectHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php',
|
||||
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php',
|
||||
'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php',
|
||||
|
@ -2263,10 +2266,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailManagementShowOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php',
|
||||
'PhabricatorMailManagementVolumeWorkflow' => 'applications/metamta/management/PhabricatorMailManagementVolumeWorkflow.php',
|
||||
'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php',
|
||||
'PhabricatorMailOutboundMailHeraldAdapter' => 'applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php',
|
||||
'PhabricatorMailOutboundRoutingHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingHeraldAction.php',
|
||||
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php',
|
||||
'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfNotificationHeraldAction.php',
|
||||
'PhabricatorMailOutboundStatus' => 'applications/metamta/constants/PhabricatorMailOutboundStatus.php',
|
||||
'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php',
|
||||
'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php',
|
||||
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php',
|
||||
'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php',
|
||||
'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php',
|
||||
'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php',
|
||||
'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php',
|
||||
|
@ -6178,6 +6186,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMailEmailHeraldField' => 'HeraldField',
|
||||
'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'PhabricatorMailEmailSubjectHeraldField' => 'PhabricatorMailEmailHeraldField',
|
||||
'PhabricatorMailImplementationAdapter' => 'Phobject',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
|
||||
'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||
|
@ -6194,10 +6205,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow',
|
||||
'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow',
|
||||
'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter',
|
||||
'PhabricatorMailOutboundRoutingHeraldAction' => 'HeraldAction',
|
||||
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction',
|
||||
'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction',
|
||||
'PhabricatorMailOutboundStatus' => 'Phobject',
|
||||
'PhabricatorMailReceiver' => 'Phobject',
|
||||
'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorMailReplyHandler' => 'Phobject',
|
||||
'PhabricatorMailRoutingRule' => 'Phobject',
|
||||
'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorMailTarget' => 'Phobject',
|
||||
'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
|
|
@ -48,6 +48,9 @@ final class HeraldTestConsoleController extends HeraldController {
|
|||
} else if ($object instanceof PonderQuestion) {
|
||||
$adapter = id(new HeraldPonderQuestionAdapter())
|
||||
->setQuestion($object);
|
||||
} else if ($object instanceof PhabricatorMetaMTAMail) {
|
||||
$adapter = id(new PhabricatorMailOutboundMailHeraldAdapter())
|
||||
->setObject($object);
|
||||
} else {
|
||||
throw new Exception(pht('Can not build adapter for object!'));
|
||||
}
|
||||
|
|
|
@ -356,7 +356,17 @@ final class HeraldTranscriptController extends HeraldController {
|
|||
|
||||
// Handle older transcripts which used a static string to record
|
||||
// action results.
|
||||
if (!is_array($log)) {
|
||||
|
||||
if ($xscript->getDryRun()) {
|
||||
$action_list->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setIcon('fa-ban', 'grey')
|
||||
->setTarget(pht('Dry Run'))
|
||||
->setNote(
|
||||
pht(
|
||||
'This was a dry run, so no actions were taken.')));
|
||||
continue;
|
||||
} else if (!is_array($log)) {
|
||||
$action_list->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setIcon('fa-clock-o', 'grey')
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailRoutingRule extends Phobject {
|
||||
|
||||
const ROUTE_AS_NOTIFICATION = 'route.notification';
|
||||
const ROUTE_AS_MAIL = 'route.mail';
|
||||
|
||||
public static function isStrongerThan($rule_u, $rule_v) {
|
||||
$strength_u = self::getRuleStrength($rule_u);
|
||||
$strength_v = self::getRuleStrength($rule_v);
|
||||
|
||||
return ($strength_u > $strength_v);
|
||||
}
|
||||
|
||||
public static function getRuleStrength($const) {
|
||||
$strength = array(
|
||||
self::ROUTE_AS_NOTIFICATION => 1,
|
||||
self::ROUTE_AS_MAIL => 2,
|
||||
);
|
||||
|
||||
return idx($strength, $const, 0);
|
||||
}
|
||||
|
||||
public static function getRuleName($const) {
|
||||
$names = array(
|
||||
self::ROUTE_AS_NOTIFICATION => pht('Route as Notification'),
|
||||
self::ROUTE_AS_MAIL => pht('Route as Mail'),
|
||||
);
|
||||
|
||||
return idx($names, $const, $const);
|
||||
}
|
||||
|
||||
public static function getRuleIcon($const) {
|
||||
$icons = array(
|
||||
self::ROUTE_AS_NOTIFICATION => 'fa-bell',
|
||||
self::ROUTE_AS_MAIL => 'fa-envelope',
|
||||
);
|
||||
|
||||
return idx($icons, $const, 'fa-question-circle');
|
||||
}
|
||||
|
||||
public static function getRuleColor($const) {
|
||||
$colors = array(
|
||||
self::ROUTE_AS_NOTIFICATION => 'grey',
|
||||
self::ROUTE_AS_MAIL => 'grey',
|
||||
);
|
||||
|
||||
return idx($colors, $const, 'yellow');
|
||||
}
|
||||
|
||||
}
|
|
@ -86,6 +86,10 @@ final class PhabricatorMetaMTAMailViewController
|
|||
pht('Cc'),
|
||||
$cc_list);
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Sent'),
|
||||
phabricator_datetime($mail->getDateCreated(), $viewer));
|
||||
|
||||
$properties->addSectionHeader(
|
||||
pht('Message'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
@ -144,23 +148,16 @@ final class PhabricatorMetaMTAMailViewController
|
|||
$actors = $mail->getDeliveredActors();
|
||||
$reasons = null;
|
||||
if (!$actors) {
|
||||
// TODO: We can get rid of this special-cased message after these changes
|
||||
// have been live for a while, but provide a more tailored message for
|
||||
// now so things are a little less confusing for users.
|
||||
if ($mail->getStatus() == PhabricatorMetaMTAMail::STATUS_SENT) {
|
||||
$delivery = phutil_tag(
|
||||
'em',
|
||||
array(),
|
||||
pht(
|
||||
'This is an older message that predates recording delivery '.
|
||||
'information, so none is available.'));
|
||||
} else {
|
||||
$delivery = phutil_tag(
|
||||
'em',
|
||||
array(),
|
||||
if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) {
|
||||
$delivery = $this->renderEmptyMessage(
|
||||
pht(
|
||||
'This message has not been delivered yet, so delivery information '.
|
||||
'is not available.'));
|
||||
} else {
|
||||
$delivery = $this->renderEmptyMessage(
|
||||
pht(
|
||||
'This is an older message that predates recording delivery '.
|
||||
'information, so none is available.'));
|
||||
}
|
||||
} else {
|
||||
$actor = idx($actors, $viewer->getPHID());
|
||||
|
@ -214,6 +211,127 @@ final class PhabricatorMetaMTAMailViewController
|
|||
$properties->addProperty(pht('Delivery'), $delivery);
|
||||
if ($reasons) {
|
||||
$properties->addProperty(pht('Reasons'), $reasons);
|
||||
$properties->addProperty(
|
||||
null,
|
||||
$this->renderEmptyMessage(
|
||||
pht(
|
||||
'Delivery reasons are listed from weakest to strongest.')));
|
||||
}
|
||||
|
||||
$properties->addSectionHeader(pht('Routing Rules'));
|
||||
|
||||
$map = $mail->getDeliveredRoutingMap();
|
||||
$routing_detail = null;
|
||||
if ($map === null) {
|
||||
if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) {
|
||||
$routing_result = $this->renderEmptyMessage(
|
||||
pht(
|
||||
'This message has not been sent yet, so routing rules have '.
|
||||
'not been computed.'));
|
||||
} else {
|
||||
$routing_result = $this->renderEmptyMessage(
|
||||
pht(
|
||||
'This is an older message which predates routing rules.'));
|
||||
}
|
||||
} else {
|
||||
$rule = idx($map, $viewer->getPHID());
|
||||
if ($rule === null) {
|
||||
$rule = idx($map, 'default');
|
||||
}
|
||||
|
||||
if ($rule === null) {
|
||||
$routing_result = $this->renderEmptyMessage(
|
||||
pht(
|
||||
'No routing rules applied when delivering this message to you.'));
|
||||
} else {
|
||||
$rule_const = $rule['rule'];
|
||||
$reason_phid = $rule['reason'];
|
||||
switch ($rule_const) {
|
||||
case PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION:
|
||||
$routing_result = pht(
|
||||
'This message was routed as a notification because it '.
|
||||
'matched %s.',
|
||||
$viewer->renderHandle($reason_phid)->render());
|
||||
break;
|
||||
case PhabricatorMailRoutingRule::ROUTE_AS_MAIL:
|
||||
$routing_result = pht(
|
||||
'This message was routed as an email because it matched %s.',
|
||||
$viewer->renderHandle($reason_phid)->render());
|
||||
break;
|
||||
default:
|
||||
$routing_result = pht('Unknown routing rule "%s".', $rule_const);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$routing_rules = $mail->getDeliveredRoutingRules();
|
||||
if ($routing_rules) {
|
||||
$rules = array();
|
||||
foreach ($routing_rules as $rule) {
|
||||
$phids = idx($rule, 'phids');
|
||||
if ($phids === null) {
|
||||
$rules[] = $rule;
|
||||
} else if (in_array($viewer->getPHID(), $phids)) {
|
||||
$rules[] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
// Reorder rules by strength.
|
||||
foreach ($rules as $key => $rule) {
|
||||
$const = $rule['routingRule'];
|
||||
$phids = $rule['phids'];
|
||||
|
||||
if ($phids === null) {
|
||||
$type = 'A';
|
||||
} else {
|
||||
$type = 'B';
|
||||
}
|
||||
|
||||
$rules[$key]['strength'] = sprintf(
|
||||
'~%s%08d',
|
||||
$type,
|
||||
PhabricatorMailRoutingRule::getRuleStrength($const));
|
||||
}
|
||||
$rules = isort($rules, 'strength');
|
||||
|
||||
$routing_detail = id(new PHUIStatusListView());
|
||||
foreach ($rules as $rule) {
|
||||
$const = $rule['routingRule'];
|
||||
$phids = $rule['phids'];
|
||||
|
||||
$name = PhabricatorMailRoutingRule::getRuleName($const);
|
||||
|
||||
$icon = PhabricatorMailRoutingRule::getRuleIcon($const);
|
||||
$color = PhabricatorMailRoutingRule::getRuleColor($const);
|
||||
|
||||
if ($phids === null) {
|
||||
$kind = pht('Global');
|
||||
} else {
|
||||
$kind = pht('Personal');
|
||||
}
|
||||
|
||||
$target = array($kind, ': ', $name);
|
||||
$target = phutil_tag('strong', array(), $target);
|
||||
|
||||
$item = id(new PHUIStatusItemView())
|
||||
->setTarget($target)
|
||||
->setNote($viewer->renderHandle($rule['reasonPHID']))
|
||||
->setIcon($icon, $color);
|
||||
|
||||
$routing_detail->addItem($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$properties->addProperty(pht('Effective Rule'), $routing_result);
|
||||
|
||||
if ($routing_detail !== null) {
|
||||
$properties->addProperty(pht('All Matching Rules'), $routing_detail);
|
||||
$properties->addProperty(
|
||||
null,
|
||||
$this->renderEmptyMessage(
|
||||
pht(
|
||||
'Matching rules are listed from weakest to strongest.')));
|
||||
}
|
||||
|
||||
return $properties;
|
||||
|
@ -252,4 +370,8 @@ final class PhabricatorMetaMTAMailViewController
|
|||
return $properties;
|
||||
}
|
||||
|
||||
private function renderEmptyMessage($message) {
|
||||
return phutil_tag('em', array(), $message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorMailEmailHeraldField
|
||||
extends HeraldField {
|
||||
|
||||
public function supportsObject($object) {
|
||||
return ($object instanceof PhabricatorMetaMTAMail);
|
||||
}
|
||||
|
||||
public function getFieldGroupKey() {
|
||||
return PhabricatorMailEmailHeraldFieldGroup::FIELDGROUPKEY;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailEmailHeraldFieldGroup extends HeraldFieldGroup {
|
||||
|
||||
const FIELDGROUPKEY = 'mail.message';
|
||||
|
||||
public function getGroupLabel() {
|
||||
return pht('Message Fields');
|
||||
}
|
||||
|
||||
protected function getGroupOrder() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailEmailSubjectHeraldField
|
||||
extends PhabricatorMailEmailHeraldField {
|
||||
|
||||
const FIELDCONST = 'mail.message.subject';
|
||||
|
||||
public function getHeraldFieldName() {
|
||||
return pht('Subject');
|
||||
}
|
||||
|
||||
public function getHeraldFieldValue($object) {
|
||||
return $object->getSubject();
|
||||
}
|
||||
|
||||
protected function getHeraldFieldStandardType() {
|
||||
return self::STANDARD_TEXT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailOutboundMailHeraldAdapter
|
||||
extends HeraldAdapter {
|
||||
|
||||
private $mail;
|
||||
|
||||
public function getAdapterApplicationClass() {
|
||||
return 'PhabricatorMetaMTAApplication';
|
||||
}
|
||||
|
||||
public function getAdapterContentDescription() {
|
||||
return pht('Route outbound email.');
|
||||
}
|
||||
|
||||
protected function initializeNewAdapter() {
|
||||
$this->mail = $this->newObject();
|
||||
}
|
||||
|
||||
protected function newObject() {
|
||||
return new PhabricatorMetaMTAMail();
|
||||
}
|
||||
|
||||
public function getObject() {
|
||||
return $this->mail;
|
||||
}
|
||||
|
||||
public function setObject(PhabricatorMetaMTAMail $mail) {
|
||||
$this->mail = $mail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAdapterContentName() {
|
||||
return pht('Outbound Mail');
|
||||
}
|
||||
|
||||
public function isSingleEventAdapter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRepetitionOptions() {
|
||||
return array(
|
||||
HeraldRepetitionPolicyConfig::FIRST,
|
||||
);
|
||||
}
|
||||
|
||||
public function supportsRuleType($rule_type) {
|
||||
switch ($rule_type) {
|
||||
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
|
||||
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
|
||||
return true;
|
||||
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getHeraldName() {
|
||||
return pht('Mail %d', $this->getObject()->getID());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorMailOutboundRoutingHeraldAction
|
||||
extends HeraldAction {
|
||||
|
||||
const DO_ROUTE = 'do.route';
|
||||
|
||||
public function supportsObject($object) {
|
||||
return ($object instanceof PhabricatorMetaMTAMail);
|
||||
}
|
||||
|
||||
public function getActionGroupKey() {
|
||||
return HeraldApplicationActionGroup::ACTIONGROUPKEY;
|
||||
}
|
||||
|
||||
protected function applyRouting(HeraldRule $rule, $route, $phids) {
|
||||
$adapter = $this->getAdapter();
|
||||
$mail = $adapter->getObject();
|
||||
$mail->addRoutingRule($route, $phids, $rule->getPHID());
|
||||
|
||||
$this->logEffect(
|
||||
self::DO_ROUTE,
|
||||
array(
|
||||
'route' => $route,
|
||||
'phids' => $phids,
|
||||
));
|
||||
}
|
||||
|
||||
protected function getActionEffectMap() {
|
||||
return array(
|
||||
self::DO_ROUTE => array(
|
||||
'icon' => 'fa-arrow-right',
|
||||
'color' => 'green',
|
||||
'name' => pht('Routed Message'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function renderActionEffectDescription($type, $data) {
|
||||
switch ($type) {
|
||||
case self::DO_ROUTE:
|
||||
return pht('Routed mail.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailOutboundRoutingSelfEmailHeraldAction
|
||||
extends PhabricatorMailOutboundRoutingHeraldAction {
|
||||
|
||||
const ACTIONCONST = 'routing.self.email';
|
||||
|
||||
public function getHeraldActionName() {
|
||||
return pht('Deliver as email');
|
||||
}
|
||||
|
||||
public function supportsRuleType($rule_type) {
|
||||
return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL);
|
||||
}
|
||||
|
||||
public function applyEffect($object, HeraldEffect $effect) {
|
||||
$rule = $effect->getRule();
|
||||
$author_phid = $rule->getAuthorPHID();
|
||||
|
||||
$this->applyRouting(
|
||||
$rule,
|
||||
PhabricatorMailRoutingRule::ROUTE_AS_MAIL,
|
||||
array($author_phid));
|
||||
}
|
||||
|
||||
public function getHeraldActionStandardType() {
|
||||
return self::STANDARD_NONE;
|
||||
}
|
||||
|
||||
public function renderActionDescription($value) {
|
||||
return pht('Deliver as email.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailOutboundRoutingSelfNotificationHeraldAction
|
||||
extends PhabricatorMailOutboundRoutingHeraldAction {
|
||||
|
||||
const ACTIONCONST = 'routing.self.notification';
|
||||
|
||||
public function getHeraldActionName() {
|
||||
return pht('Deliver as notification');
|
||||
}
|
||||
|
||||
public function supportsRuleType($rule_type) {
|
||||
return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL);
|
||||
}
|
||||
|
||||
public function applyEffect($object, HeraldEffect $effect) {
|
||||
$rule = $effect->getRule();
|
||||
$author_phid = $rule->getAuthorPHID();
|
||||
|
||||
$this->applyRouting(
|
||||
$rule,
|
||||
PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION,
|
||||
array($author_phid));
|
||||
}
|
||||
|
||||
public function getHeraldActionStandardType() {
|
||||
return self::STANDARD_NONE;
|
||||
}
|
||||
|
||||
public function renderActionDescription($value) {
|
||||
return pht('Deliver as notification.');
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,10 @@ abstract class PhabricatorMetaMTAEmailHeraldAction
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($object instanceof PhabricatorMetaMTAMail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ final class PhabricatorMetaMTAMailPHIDType extends PhabricatorPHIDType {
|
|||
|
||||
$handle
|
||||
->setName($name)
|
||||
->setFullName($name);
|
||||
->setURI('/mail/detail/'.$id.'/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
|||
const REASON_BOT = 'bot';
|
||||
const REASON_FORCE = 'force';
|
||||
const REASON_FORCE_HERALD = 'force-herald';
|
||||
const REASON_ROUTE_AS_NOTIFICATION = 'route-as-notification';
|
||||
const REASON_ROUTE_AS_MAIL = 'route-as-mail';
|
||||
|
||||
private $phid;
|
||||
private $emailAddress;
|
||||
|
@ -77,6 +79,7 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
|||
case self::REASON_NONE:
|
||||
case self::REASON_FORCE:
|
||||
case self::REASON_FORCE_HERALD:
|
||||
case self::REASON_ROUTE_AS_MAIL:
|
||||
return true;
|
||||
default:
|
||||
// All other reasons cause the message to not be delivered.
|
||||
|
@ -99,6 +102,8 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
|||
self::REASON_UNLOADABLE => pht('Bad Recipient'),
|
||||
self::REASON_FORCE => pht('Forced Mail'),
|
||||
self::REASON_FORCE_HERALD => pht('Forced by Herald'),
|
||||
self::REASON_ROUTE_AS_NOTIFICATION => pht('Route as Notification'),
|
||||
self::REASON_ROUTE_AS_MAIL => pht('Route as Mail'),
|
||||
);
|
||||
|
||||
return idx($names, $reason, pht('Unknown ("%s")', $reason));
|
||||
|
@ -147,6 +152,12 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
|||
self::REASON_FORCE_HERALD => pht(
|
||||
'This recipient was added by a "Send me an Email" rule in Herald, '.
|
||||
'which overrides some delivery settings.'),
|
||||
self::REASON_ROUTE_AS_NOTIFICATION => pht(
|
||||
'This message was downgraded to a notification by outbound mail '.
|
||||
'rules in Herald.'),
|
||||
self::REASON_ROUTE_AS_MAIL => pht(
|
||||
'This message was upgraded to email by outbound mail rules '.
|
||||
'in Herald.'),
|
||||
);
|
||||
|
||||
return idx($descriptions, $reason, pht('Unknown Reason ("%s")', $reason));
|
||||
|
|
|
@ -16,6 +16,7 @@ final class PhabricatorMetaMTAMail
|
|||
protected $relatedPHID;
|
||||
|
||||
private $recipientExpansionMap;
|
||||
private $routingMap;
|
||||
|
||||
public function __construct() {
|
||||
|
||||
|
@ -656,6 +657,9 @@ final class PhabricatorMetaMTAMail
|
|||
}
|
||||
$this->setParam('actors.sent', $actor_list);
|
||||
|
||||
$this->setParam('routing.sent', $this->getParam('routing'));
|
||||
$this->setParam('routingmap.sent', $this->getRoutingRuleMap());
|
||||
|
||||
if (!$add_to && !$add_cc) {
|
||||
$this->setStatus(PhabricatorMailOutboundStatus::STATUS_VOID);
|
||||
$this->setMessage(
|
||||
|
@ -963,9 +967,25 @@ final class PhabricatorMetaMTAMail
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($deliverable as $phid) {
|
||||
switch ($this->getRoutingRule($phid)) {
|
||||
case PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION:
|
||||
$actors[$phid]->setUndeliverable(
|
||||
PhabricatorMetaMTAActor::REASON_ROUTE_AS_NOTIFICATION);
|
||||
break;
|
||||
case PhabricatorMailRoutingRule::ROUTE_AS_MAIL:
|
||||
$actors[$phid]->setDeliverable(
|
||||
PhabricatorMetaMTAActor::REASON_ROUTE_AS_MAIL);
|
||||
break;
|
||||
default:
|
||||
// No change.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If recipients were initially deliverable and were added by "Send me an
|
||||
// email" Herald rules, annotate them as such and make them deliverable
|
||||
// again, overriding any changes made by the "self mail" and "mail tags"
|
||||
// again, overriding any changes made by the "self mail" and "mail tags"
|
||||
// settings.
|
||||
$force_recipients = $this->getForceHeraldMailRecipientPHIDs();
|
||||
$force_recipients = array_fuse($force_recipients);
|
||||
|
@ -1065,6 +1085,82 @@ final class PhabricatorMetaMTAMail
|
|||
return $this->getParam('actors.sent');
|
||||
}
|
||||
|
||||
public function getDeliveredRoutingRules() {
|
||||
return $this->getParam('routing.sent');
|
||||
}
|
||||
|
||||
public function getDeliveredRoutingMap() {
|
||||
return $this->getParam('routingmap.sent');
|
||||
}
|
||||
|
||||
|
||||
/* -( Routing )------------------------------------------------------------ */
|
||||
|
||||
|
||||
public function addRoutingRule($routing_rule, $phids, $reason_phid) {
|
||||
$routing = $this->getParam('routing', array());
|
||||
$routing[] = array(
|
||||
'routingRule' => $routing_rule,
|
||||
'phids' => $phids,
|
||||
'reasonPHID' => $reason_phid,
|
||||
);
|
||||
$this->setParam('routing', $routing);
|
||||
|
||||
// Throw the routing map away so we rebuild it.
|
||||
$this->routingMap = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getRoutingRule($phid) {
|
||||
$map = $this->getRoutingRuleMap();
|
||||
|
||||
$info = idx($map, $phid, idx($map, 'default'));
|
||||
if ($info) {
|
||||
return idx($info, 'rule');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getRoutingRuleMap() {
|
||||
if ($this->routingMap === null) {
|
||||
$map = array();
|
||||
|
||||
$routing = $this->getParam('routing', array());
|
||||
foreach ($routing as $route) {
|
||||
$phids = $route['phids'];
|
||||
if ($phids === null) {
|
||||
$phids = array('default');
|
||||
}
|
||||
|
||||
foreach ($phids as $phid) {
|
||||
$new_rule = $route['routingRule'];
|
||||
|
||||
$current_rule = idx($map, $phid);
|
||||
if ($current_rule === null) {
|
||||
$is_stronger = true;
|
||||
} else {
|
||||
$is_stronger = PhabricatorMailRoutingRule::isStrongerThan(
|
||||
$new_rule,
|
||||
$current_rule);
|
||||
}
|
||||
|
||||
if ($is_stronger) {
|
||||
$map[$phid] = array(
|
||||
'rule' => $new_rule,
|
||||
'reason' => $route['reasonPHID'],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->routingMap = $map;
|
||||
}
|
||||
|
||||
return $this->routingMap;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -1055,6 +1055,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
|
||||
if ($this->shouldPublishFeedStory($object, $xactions)) {
|
||||
|
||||
$mailed = array();
|
||||
foreach ($messages as $mail) {
|
||||
foreach ($mail->buildRecipientList() as $phid) {
|
||||
|
@ -2299,6 +2300,8 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
}
|
||||
|
||||
$this->runHeraldMailRules($messages);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
|
@ -3140,4 +3143,16 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
);
|
||||
}
|
||||
|
||||
private function runHeraldMailRules(array $messages) {
|
||||
foreach ($messages as $message) {
|
||||
$engine = new HeraldEngine();
|
||||
$adapter = id(new PhabricatorMailOutboundMailHeraldAdapter())
|
||||
->setObject($message);
|
||||
|
||||
$rules = $engine->loadRulesForAdapter($adapter);
|
||||
$effects = $engine->applyRules($rules, $adapter);
|
||||
$engine->applyEffects($effects, $adapter, $rules);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue