@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+570 -17
+16
src/__phutil_library_map__.php
··· 2247 2247 'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php', 2248 2248 'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php', 2249 2249 'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php', 2250 + 'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php', 2251 + 'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php', 2252 + 'PhabricatorMailEmailSubjectHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php', 2250 2253 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php', 2251 2254 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php', 2252 2255 'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php', ··· 2263 2266 'PhabricatorMailManagementShowOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php', 2264 2267 'PhabricatorMailManagementVolumeWorkflow' => 'applications/metamta/management/PhabricatorMailManagementVolumeWorkflow.php', 2265 2268 'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php', 2269 + 'PhabricatorMailOutboundMailHeraldAdapter' => 'applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php', 2270 + 'PhabricatorMailOutboundRoutingHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingHeraldAction.php', 2271 + 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php', 2272 + 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfNotificationHeraldAction.php', 2266 2273 'PhabricatorMailOutboundStatus' => 'applications/metamta/constants/PhabricatorMailOutboundStatus.php', 2267 2274 'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php', 2268 2275 'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php', 2269 2276 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 2277 + 'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php', 2270 2278 'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php', 2271 2279 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', 2272 2280 'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php', ··· 6178 6186 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment', 6179 6187 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 6180 6188 'PhabricatorMacroViewController' => 'PhabricatorMacroController', 6189 + 'PhabricatorMailEmailHeraldField' => 'HeraldField', 6190 + 'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup', 6191 + 'PhabricatorMailEmailSubjectHeraldField' => 'PhabricatorMailEmailHeraldField', 6181 6192 'PhabricatorMailImplementationAdapter' => 'Phobject', 6182 6193 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 6183 6194 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter', ··· 6194 6205 'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 6195 6206 'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow', 6196 6207 'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow', 6208 + 'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter', 6209 + 'PhabricatorMailOutboundRoutingHeraldAction' => 'HeraldAction', 6210 + 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 6211 + 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 6197 6212 'PhabricatorMailOutboundStatus' => 'Phobject', 6198 6213 'PhabricatorMailReceiver' => 'Phobject', 6199 6214 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', 6200 6215 'PhabricatorMailReplyHandler' => 'Phobject', 6216 + 'PhabricatorMailRoutingRule' => 'Phobject', 6201 6217 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 6202 6218 'PhabricatorMailTarget' => 'Phobject', 6203 6219 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
+3
src/applications/herald/controller/HeraldTestConsoleController.php
··· 48 48 } else if ($object instanceof PonderQuestion) { 49 49 $adapter = id(new HeraldPonderQuestionAdapter()) 50 50 ->setQuestion($object); 51 + } else if ($object instanceof PhabricatorMetaMTAMail) { 52 + $adapter = id(new PhabricatorMailOutboundMailHeraldAdapter()) 53 + ->setObject($object); 51 54 } else { 52 55 throw new Exception(pht('Can not build adapter for object!')); 53 56 }
+11 -1
src/applications/herald/controller/HeraldTranscriptController.php
··· 356 356 357 357 // Handle older transcripts which used a static string to record 358 358 // action results. 359 - if (!is_array($log)) { 359 + 360 + if ($xscript->getDryRun()) { 361 + $action_list->addItem( 362 + id(new PHUIStatusItemView()) 363 + ->setIcon('fa-ban', 'grey') 364 + ->setTarget(pht('Dry Run')) 365 + ->setNote( 366 + pht( 367 + 'This was a dry run, so no actions were taken.'))); 368 + continue; 369 + } else if (!is_array($log)) { 360 370 $action_list->addItem( 361 371 id(new PHUIStatusItemView()) 362 372 ->setIcon('fa-clock-o', 'grey')
+51
src/applications/metamta/constants/PhabricatorMailRoutingRule.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailRoutingRule extends Phobject { 4 + 5 + const ROUTE_AS_NOTIFICATION = 'route.notification'; 6 + const ROUTE_AS_MAIL = 'route.mail'; 7 + 8 + public static function isStrongerThan($rule_u, $rule_v) { 9 + $strength_u = self::getRuleStrength($rule_u); 10 + $strength_v = self::getRuleStrength($rule_v); 11 + 12 + return ($strength_u > $strength_v); 13 + } 14 + 15 + public static function getRuleStrength($const) { 16 + $strength = array( 17 + self::ROUTE_AS_NOTIFICATION => 1, 18 + self::ROUTE_AS_MAIL => 2, 19 + ); 20 + 21 + return idx($strength, $const, 0); 22 + } 23 + 24 + public static function getRuleName($const) { 25 + $names = array( 26 + self::ROUTE_AS_NOTIFICATION => pht('Route as Notification'), 27 + self::ROUTE_AS_MAIL => pht('Route as Mail'), 28 + ); 29 + 30 + return idx($names, $const, $const); 31 + } 32 + 33 + public static function getRuleIcon($const) { 34 + $icons = array( 35 + self::ROUTE_AS_NOTIFICATION => 'fa-bell', 36 + self::ROUTE_AS_MAIL => 'fa-envelope', 37 + ); 38 + 39 + return idx($icons, $const, 'fa-question-circle'); 40 + } 41 + 42 + public static function getRuleColor($const) { 43 + $colors = array( 44 + self::ROUTE_AS_NOTIFICATION => 'grey', 45 + self::ROUTE_AS_MAIL => 'grey', 46 + ); 47 + 48 + return idx($colors, $const, 'yellow'); 49 + } 50 + 51 + }
+136 -14
src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php
··· 86 86 pht('Cc'), 87 87 $cc_list); 88 88 89 + $properties->addProperty( 90 + pht('Sent'), 91 + phabricator_datetime($mail->getDateCreated(), $viewer)); 92 + 89 93 $properties->addSectionHeader( 90 94 pht('Message'), 91 95 PHUIPropertyListView::ICON_SUMMARY); ··· 144 148 $actors = $mail->getDeliveredActors(); 145 149 $reasons = null; 146 150 if (!$actors) { 147 - // TODO: We can get rid of this special-cased message after these changes 148 - // have been live for a while, but provide a more tailored message for 149 - // now so things are a little less confusing for users. 150 - if ($mail->getStatus() == PhabricatorMetaMTAMail::STATUS_SENT) { 151 - $delivery = phutil_tag( 152 - 'em', 153 - array(), 154 - pht( 155 - 'This is an older message that predates recording delivery '. 156 - 'information, so none is available.')); 157 - } else { 158 - $delivery = phutil_tag( 159 - 'em', 160 - array(), 151 + if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) { 152 + $delivery = $this->renderEmptyMessage( 161 153 pht( 162 154 'This message has not been delivered yet, so delivery information '. 163 155 'is not available.')); 156 + } else { 157 + $delivery = $this->renderEmptyMessage( 158 + pht( 159 + 'This is an older message that predates recording delivery '. 160 + 'information, so none is available.')); 164 161 } 165 162 } else { 166 163 $actor = idx($actors, $viewer->getPHID()); ··· 214 211 $properties->addProperty(pht('Delivery'), $delivery); 215 212 if ($reasons) { 216 213 $properties->addProperty(pht('Reasons'), $reasons); 214 + $properties->addProperty( 215 + null, 216 + $this->renderEmptyMessage( 217 + pht( 218 + 'Delivery reasons are listed from weakest to strongest.'))); 219 + } 220 + 221 + $properties->addSectionHeader(pht('Routing Rules')); 222 + 223 + $map = $mail->getDeliveredRoutingMap(); 224 + $routing_detail = null; 225 + if ($map === null) { 226 + if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) { 227 + $routing_result = $this->renderEmptyMessage( 228 + pht( 229 + 'This message has not been sent yet, so routing rules have '. 230 + 'not been computed.')); 231 + } else { 232 + $routing_result = $this->renderEmptyMessage( 233 + pht( 234 + 'This is an older message which predates routing rules.')); 235 + } 236 + } else { 237 + $rule = idx($map, $viewer->getPHID()); 238 + if ($rule === null) { 239 + $rule = idx($map, 'default'); 240 + } 241 + 242 + if ($rule === null) { 243 + $routing_result = $this->renderEmptyMessage( 244 + pht( 245 + 'No routing rules applied when delivering this message to you.')); 246 + } else { 247 + $rule_const = $rule['rule']; 248 + $reason_phid = $rule['reason']; 249 + switch ($rule_const) { 250 + case PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION: 251 + $routing_result = pht( 252 + 'This message was routed as a notification because it '. 253 + 'matched %s.', 254 + $viewer->renderHandle($reason_phid)->render()); 255 + break; 256 + case PhabricatorMailRoutingRule::ROUTE_AS_MAIL: 257 + $routing_result = pht( 258 + 'This message was routed as an email because it matched %s.', 259 + $viewer->renderHandle($reason_phid)->render()); 260 + break; 261 + default: 262 + $routing_result = pht('Unknown routing rule "%s".', $rule_const); 263 + break; 264 + } 265 + } 266 + 267 + $routing_rules = $mail->getDeliveredRoutingRules(); 268 + if ($routing_rules) { 269 + $rules = array(); 270 + foreach ($routing_rules as $rule) { 271 + $phids = idx($rule, 'phids'); 272 + if ($phids === null) { 273 + $rules[] = $rule; 274 + } else if (in_array($viewer->getPHID(), $phids)) { 275 + $rules[] = $rule; 276 + } 277 + } 278 + 279 + // Reorder rules by strength. 280 + foreach ($rules as $key => $rule) { 281 + $const = $rule['routingRule']; 282 + $phids = $rule['phids']; 283 + 284 + if ($phids === null) { 285 + $type = 'A'; 286 + } else { 287 + $type = 'B'; 288 + } 289 + 290 + $rules[$key]['strength'] = sprintf( 291 + '~%s%08d', 292 + $type, 293 + PhabricatorMailRoutingRule::getRuleStrength($const)); 294 + } 295 + $rules = isort($rules, 'strength'); 296 + 297 + $routing_detail = id(new PHUIStatusListView()); 298 + foreach ($rules as $rule) { 299 + $const = $rule['routingRule']; 300 + $phids = $rule['phids']; 301 + 302 + $name = PhabricatorMailRoutingRule::getRuleName($const); 303 + 304 + $icon = PhabricatorMailRoutingRule::getRuleIcon($const); 305 + $color = PhabricatorMailRoutingRule::getRuleColor($const); 306 + 307 + if ($phids === null) { 308 + $kind = pht('Global'); 309 + } else { 310 + $kind = pht('Personal'); 311 + } 312 + 313 + $target = array($kind, ': ', $name); 314 + $target = phutil_tag('strong', array(), $target); 315 + 316 + $item = id(new PHUIStatusItemView()) 317 + ->setTarget($target) 318 + ->setNote($viewer->renderHandle($rule['reasonPHID'])) 319 + ->setIcon($icon, $color); 320 + 321 + $routing_detail->addItem($item); 322 + } 323 + } 324 + } 325 + 326 + $properties->addProperty(pht('Effective Rule'), $routing_result); 327 + 328 + if ($routing_detail !== null) { 329 + $properties->addProperty(pht('All Matching Rules'), $routing_detail); 330 + $properties->addProperty( 331 + null, 332 + $this->renderEmptyMessage( 333 + pht( 334 + 'Matching rules are listed from weakest to strongest.'))); 217 335 } 218 336 219 337 return $properties; ··· 250 368 $properties->addProperty(pht('Related Object'), $related); 251 369 252 370 return $properties; 371 + } 372 + 373 + private function renderEmptyMessage($message) { 374 + return phutil_tag('em', array(), $message); 253 375 } 254 376 255 377 }
+14
src/applications/metamta/herald/PhabricatorMailEmailHeraldField.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorMailEmailHeraldField 4 + extends HeraldField { 5 + 6 + public function supportsObject($object) { 7 + return ($object instanceof PhabricatorMetaMTAMail); 8 + } 9 + 10 + public function getFieldGroupKey() { 11 + return PhabricatorMailEmailHeraldFieldGroup::FIELDGROUPKEY; 12 + } 13 + 14 + }
+15
src/applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailEmailHeraldFieldGroup extends HeraldFieldGroup { 4 + 5 + const FIELDGROUPKEY = 'mail.message'; 6 + 7 + public function getGroupLabel() { 8 + return pht('Message Fields'); 9 + } 10 + 11 + protected function getGroupOrder() { 12 + return 1000; 13 + } 14 + 15 + }
+20
src/applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailEmailSubjectHeraldField 4 + extends PhabricatorMailEmailHeraldField { 5 + 6 + const FIELDCONST = 'mail.message.subject'; 7 + 8 + public function getHeraldFieldName() { 9 + return pht('Subject'); 10 + } 11 + 12 + public function getHeraldFieldValue($object) { 13 + return $object->getSubject(); 14 + } 15 + 16 + protected function getHeraldFieldStandardType() { 17 + return self::STANDARD_TEXT; 18 + } 19 + 20 + }
+62
src/applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailOutboundMailHeraldAdapter 4 + extends HeraldAdapter { 5 + 6 + private $mail; 7 + 8 + public function getAdapterApplicationClass() { 9 + return 'PhabricatorMetaMTAApplication'; 10 + } 11 + 12 + public function getAdapterContentDescription() { 13 + return pht('Route outbound email.'); 14 + } 15 + 16 + protected function initializeNewAdapter() { 17 + $this->mail = $this->newObject(); 18 + } 19 + 20 + protected function newObject() { 21 + return new PhabricatorMetaMTAMail(); 22 + } 23 + 24 + public function getObject() { 25 + return $this->mail; 26 + } 27 + 28 + public function setObject(PhabricatorMetaMTAMail $mail) { 29 + $this->mail = $mail; 30 + return $this; 31 + } 32 + 33 + public function getAdapterContentName() { 34 + return pht('Outbound Mail'); 35 + } 36 + 37 + public function isSingleEventAdapter() { 38 + return true; 39 + } 40 + 41 + public function getRepetitionOptions() { 42 + return array( 43 + HeraldRepetitionPolicyConfig::FIRST, 44 + ); 45 + } 46 + 47 + public function supportsRuleType($rule_type) { 48 + switch ($rule_type) { 49 + case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: 50 + case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: 51 + return true; 52 + case HeraldRuleTypeConfig::RULE_TYPE_OBJECT: 53 + default: 54 + return false; 55 + } 56 + } 57 + 58 + public function getHeraldName() { 59 + return pht('Mail %d', $this->getObject()->getID()); 60 + } 61 + 62 + }
+46
src/applications/metamta/herald/PhabricatorMailOutboundRoutingHeraldAction.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorMailOutboundRoutingHeraldAction 4 + extends HeraldAction { 5 + 6 + const DO_ROUTE = 'do.route'; 7 + 8 + public function supportsObject($object) { 9 + return ($object instanceof PhabricatorMetaMTAMail); 10 + } 11 + 12 + public function getActionGroupKey() { 13 + return HeraldApplicationActionGroup::ACTIONGROUPKEY; 14 + } 15 + 16 + protected function applyRouting(HeraldRule $rule, $route, $phids) { 17 + $adapter = $this->getAdapter(); 18 + $mail = $adapter->getObject(); 19 + $mail->addRoutingRule($route, $phids, $rule->getPHID()); 20 + 21 + $this->logEffect( 22 + self::DO_ROUTE, 23 + array( 24 + 'route' => $route, 25 + 'phids' => $phids, 26 + )); 27 + } 28 + 29 + protected function getActionEffectMap() { 30 + return array( 31 + self::DO_ROUTE => array( 32 + 'icon' => 'fa-arrow-right', 33 + 'color' => 'green', 34 + 'name' => pht('Routed Message'), 35 + ), 36 + ); 37 + } 38 + 39 + protected function renderActionEffectDescription($type, $data) { 40 + switch ($type) { 41 + case self::DO_ROUTE: 42 + return pht('Routed mail.'); 43 + } 44 + } 45 + 46 + }
+34
src/applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailOutboundRoutingSelfEmailHeraldAction 4 + extends PhabricatorMailOutboundRoutingHeraldAction { 5 + 6 + const ACTIONCONST = 'routing.self.email'; 7 + 8 + public function getHeraldActionName() { 9 + return pht('Deliver as email'); 10 + } 11 + 12 + public function supportsRuleType($rule_type) { 13 + return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL); 14 + } 15 + 16 + public function applyEffect($object, HeraldEffect $effect) { 17 + $rule = $effect->getRule(); 18 + $author_phid = $rule->getAuthorPHID(); 19 + 20 + $this->applyRouting( 21 + $rule, 22 + PhabricatorMailRoutingRule::ROUTE_AS_MAIL, 23 + array($author_phid)); 24 + } 25 + 26 + public function getHeraldActionStandardType() { 27 + return self::STANDARD_NONE; 28 + } 29 + 30 + public function renderActionDescription($value) { 31 + return pht('Deliver as email.'); 32 + } 33 + 34 + }
+34
src/applications/metamta/herald/PhabricatorMailOutboundRoutingSelfNotificationHeraldAction.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailOutboundRoutingSelfNotificationHeraldAction 4 + extends PhabricatorMailOutboundRoutingHeraldAction { 5 + 6 + const ACTIONCONST = 'routing.self.notification'; 7 + 8 + public function getHeraldActionName() { 9 + return pht('Deliver as notification'); 10 + } 11 + 12 + public function supportsRuleType($rule_type) { 13 + return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL); 14 + } 15 + 16 + public function applyEffect($object, HeraldEffect $effect) { 17 + $rule = $effect->getRule(); 18 + $author_phid = $rule->getAuthorPHID(); 19 + 20 + $this->applyRouting( 21 + $rule, 22 + PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION, 23 + array($author_phid)); 24 + } 25 + 26 + public function getHeraldActionStandardType() { 27 + return self::STANDARD_NONE; 28 + } 29 + 30 + public function renderActionDescription($value) { 31 + return pht('Deliver as notification.'); 32 + } 33 + 34 + }
+4
src/applications/metamta/herald/PhabricatorMetaMTAEmailHeraldAction.php
··· 14 14 return false; 15 15 } 16 16 17 + if ($object instanceof PhabricatorMetaMTAMail) { 18 + return false; 19 + } 20 + 17 21 return true; 18 22 } 19 23
+1 -1
src/applications/metamta/phid/PhabricatorMetaMTAMailPHIDType.php
··· 37 37 38 38 $handle 39 39 ->setName($name) 40 - ->setFullName($name); 40 + ->setURI('/mail/detail/'.$id.'/'); 41 41 } 42 42 } 43 43 }
+11
src/applications/metamta/query/PhabricatorMetaMTAActor.php
··· 18 18 const REASON_BOT = 'bot'; 19 19 const REASON_FORCE = 'force'; 20 20 const REASON_FORCE_HERALD = 'force-herald'; 21 + const REASON_ROUTE_AS_NOTIFICATION = 'route-as-notification'; 22 + const REASON_ROUTE_AS_MAIL = 'route-as-mail'; 21 23 22 24 private $phid; 23 25 private $emailAddress; ··· 77 79 case self::REASON_NONE: 78 80 case self::REASON_FORCE: 79 81 case self::REASON_FORCE_HERALD: 82 + case self::REASON_ROUTE_AS_MAIL: 80 83 return true; 81 84 default: 82 85 // All other reasons cause the message to not be delivered. ··· 99 102 self::REASON_UNLOADABLE => pht('Bad Recipient'), 100 103 self::REASON_FORCE => pht('Forced Mail'), 101 104 self::REASON_FORCE_HERALD => pht('Forced by Herald'), 105 + self::REASON_ROUTE_AS_NOTIFICATION => pht('Route as Notification'), 106 + self::REASON_ROUTE_AS_MAIL => pht('Route as Mail'), 102 107 ); 103 108 104 109 return idx($names, $reason, pht('Unknown ("%s")', $reason)); ··· 147 152 self::REASON_FORCE_HERALD => pht( 148 153 'This recipient was added by a "Send me an Email" rule in Herald, '. 149 154 'which overrides some delivery settings.'), 155 + self::REASON_ROUTE_AS_NOTIFICATION => pht( 156 + 'This message was downgraded to a notification by outbound mail '. 157 + 'rules in Herald.'), 158 + self::REASON_ROUTE_AS_MAIL => pht( 159 + 'This message was upgraded to email by outbound mail rules '. 160 + 'in Herald.'), 150 161 ); 151 162 152 163 return idx($descriptions, $reason, pht('Unknown Reason ("%s")', $reason));
+97 -1
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 16 16 protected $relatedPHID; 17 17 18 18 private $recipientExpansionMap; 19 + private $routingMap; 19 20 20 21 public function __construct() { 21 22 ··· 656 657 } 657 658 $this->setParam('actors.sent', $actor_list); 658 659 660 + $this->setParam('routing.sent', $this->getParam('routing')); 661 + $this->setParam('routingmap.sent', $this->getRoutingRuleMap()); 662 + 659 663 if (!$add_to && !$add_cc) { 660 664 $this->setStatus(PhabricatorMailOutboundStatus::STATUS_VOID); 661 665 $this->setMessage( ··· 963 967 } 964 968 } 965 969 970 + foreach ($deliverable as $phid) { 971 + switch ($this->getRoutingRule($phid)) { 972 + case PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION: 973 + $actors[$phid]->setUndeliverable( 974 + PhabricatorMetaMTAActor::REASON_ROUTE_AS_NOTIFICATION); 975 + break; 976 + case PhabricatorMailRoutingRule::ROUTE_AS_MAIL: 977 + $actors[$phid]->setDeliverable( 978 + PhabricatorMetaMTAActor::REASON_ROUTE_AS_MAIL); 979 + break; 980 + default: 981 + // No change. 982 + break; 983 + } 984 + } 985 + 966 986 // If recipients were initially deliverable and were added by "Send me an 967 987 // email" Herald rules, annotate them as such and make them deliverable 968 - // again, overriding any changes made by the "self mail" and "mail tags" 988 + // again, overriding any changes made by the "self mail" and "mail tags" 969 989 // settings. 970 990 $force_recipients = $this->getForceHeraldMailRecipientPHIDs(); 971 991 $force_recipients = array_fuse($force_recipients); ··· 1063 1083 1064 1084 public function getDeliveredActors() { 1065 1085 return $this->getParam('actors.sent'); 1086 + } 1087 + 1088 + public function getDeliveredRoutingRules() { 1089 + return $this->getParam('routing.sent'); 1090 + } 1091 + 1092 + public function getDeliveredRoutingMap() { 1093 + return $this->getParam('routingmap.sent'); 1094 + } 1095 + 1096 + 1097 + /* -( Routing )------------------------------------------------------------ */ 1098 + 1099 + 1100 + public function addRoutingRule($routing_rule, $phids, $reason_phid) { 1101 + $routing = $this->getParam('routing', array()); 1102 + $routing[] = array( 1103 + 'routingRule' => $routing_rule, 1104 + 'phids' => $phids, 1105 + 'reasonPHID' => $reason_phid, 1106 + ); 1107 + $this->setParam('routing', $routing); 1108 + 1109 + // Throw the routing map away so we rebuild it. 1110 + $this->routingMap = null; 1111 + 1112 + return $this; 1113 + } 1114 + 1115 + private function getRoutingRule($phid) { 1116 + $map = $this->getRoutingRuleMap(); 1117 + 1118 + $info = idx($map, $phid, idx($map, 'default')); 1119 + if ($info) { 1120 + return idx($info, 'rule'); 1121 + } 1122 + 1123 + return null; 1124 + } 1125 + 1126 + private function getRoutingRuleMap() { 1127 + if ($this->routingMap === null) { 1128 + $map = array(); 1129 + 1130 + $routing = $this->getParam('routing', array()); 1131 + foreach ($routing as $route) { 1132 + $phids = $route['phids']; 1133 + if ($phids === null) { 1134 + $phids = array('default'); 1135 + } 1136 + 1137 + foreach ($phids as $phid) { 1138 + $new_rule = $route['routingRule']; 1139 + 1140 + $current_rule = idx($map, $phid); 1141 + if ($current_rule === null) { 1142 + $is_stronger = true; 1143 + } else { 1144 + $is_stronger = PhabricatorMailRoutingRule::isStrongerThan( 1145 + $new_rule, 1146 + $current_rule); 1147 + } 1148 + 1149 + if ($is_stronger) { 1150 + $map[$phid] = array( 1151 + 'rule' => $new_rule, 1152 + 'reason' => $route['reasonPHID'], 1153 + ); 1154 + } 1155 + } 1156 + } 1157 + 1158 + $this->routingMap = $map; 1159 + } 1160 + 1161 + return $this->routingMap; 1066 1162 } 1067 1163 1068 1164
+15
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 1055 1055 } 1056 1056 1057 1057 if ($this->shouldPublishFeedStory($object, $xactions)) { 1058 + 1058 1059 $mailed = array(); 1059 1060 foreach ($messages as $mail) { 1060 1061 foreach ($mail->buildRecipientList() as $phid) { ··· 2299 2300 } 2300 2301 } 2301 2302 2303 + $this->runHeraldMailRules($messages); 2304 + 2302 2305 return $messages; 2303 2306 } 2304 2307 ··· 3138 3141 'feedNotifyPHIDs', 3139 3142 'feedRelatedPHIDs', 3140 3143 ); 3144 + } 3145 + 3146 + private function runHeraldMailRules(array $messages) { 3147 + foreach ($messages as $message) { 3148 + $engine = new HeraldEngine(); 3149 + $adapter = id(new PhabricatorMailOutboundMailHeraldAdapter()) 3150 + ->setObject($message); 3151 + 3152 + $rules = $engine->loadRulesForAdapter($adapter); 3153 + $effects = $engine->applyRules($rules, $adapter); 3154 + $engine->applyEffects($effects, $adapter, $rules); 3155 + } 3141 3156 } 3142 3157 3143 3158 }