@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 mail "stamps" to improve client mail routing

Summary:
Ref T10448. Currently, we use "mail tags" (in {nav Settings > Email Preferences}) to give users some ability to route mail. There are a number of major issues with this:

- It isn't modular and can't be extended by third-party applications.
- The UI is a giant mess of 5,000 individual settings.
- Settings don't map clearly to actual edits.
- A lot of stuff isn't covered by any setting.

This adds a new system, called "mail stamps", which is similar to "mail tags" but tries to fix all these problems.

I called these "stamps" because: stamps make sense with mail; we can't throw away the old system just yet and need to keep it around for a bit; we don't use this term for anything else; it avoids confusion with project tags.

(Conceptually, imagine these as ink stamps like "RETURN TO SENDER" or "FRAGILE", not actual postage stamps.)

The only real "trick" here is that later versions of this will need to enumerate possible stamps for an object and maybe all possible stamps for all objects in the system. This is why stamp generation is separated into a "template" phase and a "value" phase. In future changes, the "template" phase can be used on its own to generate documentation and typeaheads and let users build rules. This may need some more refinement before it really works since I haven't built any of that yet.

Also adds a preference for getting stamps in the header only (default) or header and body (better for Gmail, which can't route based on headers).

Test Plan:
Fiddled with preference, sent some mail and saw a "STAMPS" setting in the body and an "X-Phabricator-Stamps" header.

{F5411694}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T10448

Differential Revision: https://secure.phabricator.com/D18991

+507 -4
+10
src/__phutil_library_map__.php
··· 1958 1958 'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php', 1959 1959 'PhabricatorApplicationEditor' => 'applications/meta/editor/PhabricatorApplicationEditor.php', 1960 1960 'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php', 1961 + 'PhabricatorApplicationObjectMailEngineExtension' => 'applications/transactions/engineextension/PhabricatorApplicationObjectMailEngineExtension.php', 1961 1962 'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php', 1962 1963 'PhabricatorApplicationPolicyChangeTransaction' => 'applications/meta/xactions/PhabricatorApplicationPolicyChangeTransaction.php', 1963 1964 'PhabricatorApplicationProfileMenuItem' => 'applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php', ··· 2828 2829 'PhabricatorEmailPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php', 2829 2830 'PhabricatorEmailRePrefixSetting' => 'applications/settings/setting/PhabricatorEmailRePrefixSetting.php', 2830 2831 'PhabricatorEmailSelfActionsSetting' => 'applications/settings/setting/PhabricatorEmailSelfActionsSetting.php', 2832 + 'PhabricatorEmailStampsSetting' => 'applications/settings/setting/PhabricatorEmailStampsSetting.php', 2831 2833 'PhabricatorEmailTagsSetting' => 'applications/settings/setting/PhabricatorEmailTagsSetting.php', 2832 2834 'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php', 2833 2835 'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php', ··· 3174 3176 'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php', 3175 3177 'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php', 3176 3178 'PhabricatorMailEmailSubjectHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php', 3179 + 'PhabricatorMailEngineExtension' => 'applications/metamta/engine/PhabricatorMailEngineExtension.php', 3177 3180 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php', 3178 3181 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php', 3179 3182 'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php', ··· 3202 3205 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 3203 3206 'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php', 3204 3207 'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php', 3208 + 'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php', 3205 3209 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', 3206 3210 'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php', 3207 3211 'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php', ··· 4204 4208 'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php', 4205 4209 'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php', 4206 4210 'PhabricatorStringListExportField' => 'infrastructure/export/field/PhabricatorStringListExportField.php', 4211 + 'PhabricatorStringMailStamp' => 'applications/metamta/stamp/PhabricatorStringMailStamp.php', 4207 4212 'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php', 4208 4213 'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php', 4209 4214 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', ··· 7269 7274 'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView', 7270 7275 'PhabricatorApplicationEditor' => 'PhabricatorApplicationTransactionEditor', 7271 7276 'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController', 7277 + 'PhabricatorApplicationObjectMailEngineExtension' => 'PhabricatorMailEngineExtension', 7272 7278 'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController', 7273 7279 'PhabricatorApplicationPolicyChangeTransaction' => 'PhabricatorApplicationTransactionType', 7274 7280 'PhabricatorApplicationProfileMenuItem' => 'PhabricatorProfileMenuItem', ··· 8276 8282 'PhabricatorEmailPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 8277 8283 'PhabricatorEmailRePrefixSetting' => 'PhabricatorSelectSetting', 8278 8284 'PhabricatorEmailSelfActionsSetting' => 'PhabricatorSelectSetting', 8285 + 'PhabricatorEmailStampsSetting' => 'PhabricatorSelectSetting', 8279 8286 'PhabricatorEmailTagsSetting' => 'PhabricatorInternalSetting', 8280 8287 'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting', 8281 8288 'PhabricatorEmailVerificationController' => 'PhabricatorAuthController', ··· 8662 8669 'PhabricatorMailEmailHeraldField' => 'HeraldField', 8663 8670 'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup', 8664 8671 'PhabricatorMailEmailSubjectHeraldField' => 'PhabricatorMailEmailHeraldField', 8672 + 'PhabricatorMailEngineExtension' => 'Phobject', 8665 8673 'PhabricatorMailImplementationAdapter' => 'Phobject', 8666 8674 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 8667 8675 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter', ··· 8690 8698 'PhabricatorMailReplyHandler' => 'Phobject', 8691 8699 'PhabricatorMailRoutingRule' => 'Phobject', 8692 8700 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 8701 + 'PhabricatorMailStamp' => 'Phobject', 8693 8702 'PhabricatorMailTarget' => 'Phobject', 8694 8703 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions', 8695 8704 'PhabricatorMainMenuBarExtension' => 'Phobject', ··· 9907 9916 'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType', 9908 9917 'PhabricatorStringListEditField' => 'PhabricatorEditField', 9909 9918 'PhabricatorStringListExportField' => 'PhabricatorListExportField', 9919 + 'PhabricatorStringMailStamp' => 'PhabricatorMailStamp', 9910 9920 'PhabricatorStringSetting' => 'PhabricatorSetting', 9911 9921 'PhabricatorSubmitEditField' => 'PhabricatorEditField', 9912 9922 'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
+47
src/applications/metamta/engine/PhabricatorMailEngineExtension.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorMailEngineExtension 4 + extends Phobject { 5 + 6 + private $viewer; 7 + private $editor; 8 + 9 + final public function getExtensionKey() { 10 + return $this->getPhobjectClassConstant('EXTENSIONKEY'); 11 + } 12 + 13 + final public function setViewer($viewer) { 14 + $this->viewer = $viewer; 15 + return $this; 16 + } 17 + 18 + final public function getViewer() { 19 + return $this->viewer; 20 + } 21 + 22 + final public function setEditor( 23 + PhabricatorApplicationTransactionEditor $editor) { 24 + $this->editor = $editor; 25 + return $this; 26 + } 27 + 28 + final public function getEditor() { 29 + return $this->editor; 30 + } 31 + 32 + abstract public function supportsObject($object); 33 + abstract public function newMailStampTemplates($object); 34 + abstract public function newMailStamps($object, array $xactions); 35 + 36 + final public static function getAllExtensions() { 37 + return id(new PhutilClassMapQuery()) 38 + ->setAncestorClass(__CLASS__) 39 + ->setUniqueMethod('getExtensionKey') 40 + ->execute(); 41 + } 42 + 43 + final protected function getMailStamp($key) { 44 + return $this->getEditor()->getMailStamp($key); 45 + } 46 + 47 + }
+29 -4
src/applications/metamta/replyhandler/PhabricatorMailTarget.php
··· 58 58 public function willSendMail(PhabricatorMetaMTAMail $mail) { 59 59 $viewer = $this->getViewer(); 60 60 61 + $show_stamps = $mail->shouldRenderMailStampsInBody($viewer); 62 + 63 + $body = $mail->getBody(); 64 + $html_body = $mail->getHTMLBody(); 65 + $has_html = (strlen($html_body) > 0); 66 + 67 + if ($show_stamps) { 68 + $stamps = $mail->getMailStamps(); 69 + 70 + $body .= "\n"; 71 + $body .= pht('STAMPS'); 72 + $body .= "\n"; 73 + $body .= implode(', ', $stamps); 74 + $body .= "\n"; 75 + 76 + if ($has_html) { 77 + $html = array(); 78 + $html[] = phutil_tag('strong', array(), pht('STAMPS')); 79 + $html[] = phutil_tag('br'); 80 + $html[] = phutil_implode_html(', ', $stamps); 81 + $html[] = phutil_tag('br'); 82 + $html = phutil_tag('div', array(), $html); 83 + $html_body .= hsprintf('%s', $html); 84 + } 85 + } 86 + 61 87 $mail->addPHIDHeaders('X-Phabricator-To', $this->rawToPHIDs); 62 88 $mail->addPHIDHeaders('X-Phabricator-Cc', $this->rawCCPHIDs); 63 89 64 90 $to_handles = $viewer->loadHandles($this->rawToPHIDs); 65 91 $cc_handles = $viewer->loadHandles($this->rawCCPHIDs); 66 92 67 - $body = $mail->getBody(); 68 93 $body .= "\n"; 69 94 $body .= $this->getRecipientsSummary($to_handles, $cc_handles); 70 - $mail->setBody($body); 71 95 72 - $html_body = $mail->getHTMLBody(); 73 - if (strlen($html_body)) { 96 + if ($has_html) { 74 97 $html_body .= hsprintf( 75 98 '%s', 76 99 $this->getRecipientsSummaryHTML($to_handles, $cc_handles)); 77 100 } 101 + 102 + $mail->setBody($body); 78 103 $mail->setHTMLBody($html_body); 79 104 80 105 $reply_to = $this->getReplyTo();
+88
src/applications/metamta/stamp/PhabricatorMailStamp.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorMailStamp 4 + extends Phobject { 5 + 6 + private $key; 7 + private $value; 8 + private $label; 9 + private $viewer; 10 + 11 + final public function getStampType() { 12 + return $this->getPhobjectClassConstant('STAMPTYPE'); 13 + } 14 + 15 + final public function setKey($key) { 16 + $this->key = $key; 17 + return $this; 18 + } 19 + 20 + final public function getKey() { 21 + return $this->key; 22 + } 23 + 24 + final protected function setRawValue($value) { 25 + $this->value = $value; 26 + return $this; 27 + } 28 + 29 + final protected function getRawValue() { 30 + return $this->value; 31 + } 32 + 33 + final public function setViewer(PhabricatorUser $viewer) { 34 + $this->viewer = $viewer; 35 + return $this; 36 + } 37 + 38 + final public function getViewer() { 39 + return $this->viewer; 40 + } 41 + 42 + final public function setLabel($label) { 43 + $this->label = $label; 44 + return $this; 45 + } 46 + 47 + final public function getLabel() { 48 + return $this->label; 49 + } 50 + 51 + public function setValue($value) { 52 + return $this->setRawValue($value); 53 + } 54 + 55 + final public function toDictionary() { 56 + return array( 57 + 'type' => $this->getStampType(), 58 + 'key' => $this->getKey(), 59 + 'value' => $this->getValueForDictionary(), 60 + ); 61 + } 62 + 63 + final public static function getAllStamps() { 64 + return id(new PhutilClassMapQuery()) 65 + ->setAncestorClass(__CLASS__) 66 + ->setUniqueMethod('getStampType') 67 + ->execute(); 68 + } 69 + 70 + protected function getValueForDictionary() { 71 + return $this->getRawValue(); 72 + } 73 + 74 + public function setValueFromDictionary($value) { 75 + return $this->setRawValue($value); 76 + } 77 + 78 + public function getValueForRendering() { 79 + return $this->getRawValue(); 80 + } 81 + 82 + abstract public function renderStamps($value); 83 + 84 + final protected function renderStamp($key, $value = null) { 85 + return $key.'('.$value.')'; 86 + } 87 + 88 + }
+16
src/applications/metamta/stamp/PhabricatorStringMailStamp.php
··· 1 + <?php 2 + 3 + final class PhabricatorStringMailStamp 4 + extends PhabricatorMailStamp { 5 + 6 + const STAMPTYPE = 'string'; 7 + 8 + public function renderStamps($value) { 9 + if (!strlen($value)) { 10 + return null; 11 + } 12 + 13 + return $this->renderStamp($this->getKey(), $value); 14 + } 15 + 16 + }
+29
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 299 299 return $this->getParam('mustEncryptReasons', array()); 300 300 } 301 301 302 + public function setMailStamps(array $stamps) { 303 + return $this->setParam('stamps', $stamps); 304 + } 305 + 306 + public function getMailStamps() { 307 + return $this->getParam('stamps', array()); 308 + } 309 + 310 + public function setMailStampMetadata($metadata) { 311 + return $this->setParam('stampMetadata', $metadata); 312 + } 313 + 314 + public function getMailStampMetadata() { 315 + return $this->getParam('stampMetadata', array()); 316 + } 317 + 302 318 public function setHTMLBody($html) { 303 319 $this->setParam('html-body', $html); 304 320 return $this; ··· 635 651 // constructing the message. 636 652 break; 637 653 } 654 + } 655 + 656 + $stamps = $this->getMailStamps(); 657 + if ($stamps) { 658 + $headers[] = array('X-Phabricator-Stamps', implode(', ', $stamps)); 638 659 } 639 660 640 661 $raw_body = idx($params, 'body', ''); ··· 1302 1323 PhabricatorEmailFormatSetting::SETTINGKEY); 1303 1324 1304 1325 return ($value == PhabricatorEmailFormatSetting::VALUE_HTML_EMAIL); 1326 + } 1327 + 1328 + public function shouldRenderMailStampsInBody($viewer) { 1329 + $preferences = $this->loadPreferences($viewer->getPHID()); 1330 + $value = $preferences->getSettingValue( 1331 + PhabricatorEmailStampsSetting::SETTINGKEY); 1332 + 1333 + return ($value == PhabricatorEmailStampsSetting::VALUE_BODY_STAMPS); 1305 1334 } 1306 1335 1307 1336
+47
src/applications/settings/setting/PhabricatorEmailStampsSetting.php
··· 1 + <?php 2 + 3 + final class PhabricatorEmailStampsSetting 4 + extends PhabricatorSelectSetting { 5 + 6 + const SETTINGKEY = 'stamps'; 7 + 8 + const VALUE_BODY_STAMPS = 'body'; 9 + const VALUE_HEADER_STAMPS = 'header'; 10 + 11 + public function getSettingName() { 12 + return pht('Send Stamps'); 13 + } 14 + 15 + public function getSettingPanelKey() { 16 + return PhabricatorEmailFormatSettingsPanel::PANELKEY; 17 + } 18 + 19 + protected function getSettingOrder() { 20 + return 400; 21 + } 22 + 23 + protected function getControlInstructions() { 24 + return pht(<<<EOREMARKUP 25 + Phabricator stamps mail with labels like `actor(alice)` which can be used to 26 + write client mail rules to organize mail. By default, these stamps are sent 27 + in an `X-Phabricator-Stamps` header. 28 + 29 + If you use a client which can not use headers to route mail (like Gmail), 30 + you can also include the stamps in the message body so mail rules based on 31 + body content can route messages. 32 + EOREMARKUP 33 + ); 34 + } 35 + 36 + public function getSettingDefaultValue() { 37 + return self::VALUE_HEADER_STAMPS; 38 + } 39 + 40 + protected function getSelectOptions() { 41 + return array( 42 + self::VALUE_HEADER_STAMPS => pht('Mail Headers'), 43 + self::VALUE_BODY_STAMPS => pht('Mail Headers and Body'), 44 + ); 45 + } 46 + 47 + }
+149
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 72 72 private $modularTypes; 73 73 private $silent; 74 74 private $mustEncrypt; 75 + private $stampTemplates = array(); 76 + private $mailStamps = array(); 75 77 76 78 private $transactionQueue = array(); 77 79 ··· 1181 1183 $this->mailShouldSend = true; 1182 1184 $this->mailToPHIDs = $this->getMailTo($object); 1183 1185 $this->mailCCPHIDs = $this->getMailCC($object); 1186 + 1187 + $mail_xactions = $this->getTransactionsForMail($object, $xactions); 1188 + $stamps = $this->newMailStamps($object, $xactions); 1189 + foreach ($stamps as $stamp) { 1190 + $this->mailStamps[] = $stamp->toDictionary(); 1191 + } 1184 1192 } 1185 1193 1186 1194 if ($this->shouldPublishFeedStory($object, $xactions)) { ··· 2611 2619 2612 2620 $mail_tags = $this->getMailTags($object, $mail_xactions); 2613 2621 $action = $this->getMailAction($object, $mail_xactions); 2622 + $stamps = $this->generateMailStamps($object, $this->mailStamps); 2614 2623 2615 2624 if (PhabricatorEnv::getEnvConfig('metamta.email-preferences')) { 2616 2625 $this->addEmailPreferenceSectionToMailBody( ··· 2649 2658 $mail->setParentMessageID($this->getParentMessageID()); 2650 2659 } 2651 2660 2661 + // If we have stamps, attach the raw dictionary version (not the actual 2662 + // objects) to the mail so that debugging tools can see what we used to 2663 + // render the final list. 2664 + if ($this->mailStamps) { 2665 + $mail->setMailStampMetadata($this->mailStamps); 2666 + } 2667 + 2668 + // If we have rendered stamps, attach them to the mail. 2669 + if ($stamps) { 2670 + $mail->setMailStamps($stamps); 2671 + } 2672 + 2652 2673 return $target->willSendMail($mail); 2653 2674 } 2654 2675 ··· 3569 3590 'feedShouldPublish', 3570 3591 'mailShouldSend', 3571 3592 'mustEncrypt', 3593 + 'mailStamps', 3572 3594 ); 3573 3595 } 3574 3596 ··· 3959 3981 } 3960 3982 3961 3983 return $editor; 3984 + } 3985 + 3986 + 3987 + /* -( Stamps )------------------------------------------------------------- */ 3988 + 3989 + 3990 + public function newMailStampTemplates($object) { 3991 + $actor = $this->getActor(); 3992 + 3993 + $templates = array(); 3994 + 3995 + $extensions = $this->newMailExtensions($object); 3996 + foreach ($extensions as $extension) { 3997 + $stamps = $extension->newMailStampTemplates($object); 3998 + foreach ($stamps as $stamp) { 3999 + $key = $stamp->getKey(); 4000 + if (isset($templates[$key])) { 4001 + throw new Exception( 4002 + pht( 4003 + 'Mail extension ("%s") defines a stamp template with the '. 4004 + 'same key ("%s") as another template. Each stamp template '. 4005 + 'must have a unique key.', 4006 + get_class($extension), 4007 + $key)); 4008 + } 4009 + 4010 + $stamp->setViewer($actor); 4011 + 4012 + $templates[$key] = $stamp; 4013 + } 4014 + } 4015 + 4016 + return $templates; 4017 + } 4018 + 4019 + final public function getMailStamp($key) { 4020 + if (!isset($this->stampTemplates)) { 4021 + throw new PhutilInvalidStateException('newMailStampTemplates'); 4022 + } 4023 + 4024 + if (!isset($this->stampTemplates[$key])) { 4025 + throw new Exception( 4026 + pht( 4027 + 'Editor ("%s") has no mail stamp template with provided key ("%s").', 4028 + get_class($this), 4029 + $key)); 4030 + } 4031 + 4032 + return $this->stampTemplates[$key]; 4033 + } 4034 + 4035 + private function newMailStamps($object, array $xactions) { 4036 + $actor = $this->getActor(); 4037 + 4038 + $this->stampTemplates = $this->newMailStampTemplates($object); 4039 + 4040 + $extensions = $this->newMailExtensions($object); 4041 + $stamps = array(); 4042 + foreach ($extensions as $extension) { 4043 + $extension->newMailStamps($object, $xactions); 4044 + } 4045 + 4046 + return $this->stampTemplates; 4047 + } 4048 + 4049 + private function newMailExtensions($object) { 4050 + $actor = $this->getActor(); 4051 + 4052 + $all_extensions = PhabricatorMailEngineExtension::getAllExtensions(); 4053 + 4054 + $extensions = array(); 4055 + foreach ($all_extensions as $key => $template) { 4056 + $extension = id(clone $template) 4057 + ->setViewer($actor) 4058 + ->setEditor($this); 4059 + 4060 + if ($extension->supportsObject($object)) { 4061 + $extensions[$key] = $extension; 4062 + } 4063 + } 4064 + 4065 + return $extensions; 4066 + } 4067 + 4068 + private function generateMailStamps($object, $data) { 4069 + if (!$data || !is_array($data)) { 4070 + return null; 4071 + } 4072 + 4073 + $templates = $this->newMailStampTemplates($object); 4074 + foreach ($data as $spec) { 4075 + if (!is_array($spec)) { 4076 + continue; 4077 + } 4078 + 4079 + $key = idx($spec, 'key'); 4080 + if (!isset($templates[$key])) { 4081 + continue; 4082 + } 4083 + 4084 + $type = idx($spec, 'type'); 4085 + if ($templates[$key]->getStampType() !== $type) { 4086 + continue; 4087 + } 4088 + 4089 + $value = idx($spec, 'value'); 4090 + $templates[$key]->setValueFromDictionary($value); 4091 + } 4092 + 4093 + $results = array(); 4094 + foreach ($templates as $template) { 4095 + $value = $template->getValueForRendering(); 4096 + 4097 + $rendered = $template->renderStamps($value); 4098 + if ($rendered === null) { 4099 + continue; 4100 + } 4101 + 4102 + $rendered = (array)$rendered; 4103 + foreach ($rendered as $stamp) { 4104 + $results[] = $stamp; 4105 + } 4106 + } 4107 + 4108 + sort($results); 4109 + 4110 + return $results; 3962 4111 } 3963 4112 3964 4113 }
+92
src/applications/transactions/engineextension/PhabricatorApplicationObjectMailEngineExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorApplicationObjectMailEngineExtension 4 + extends PhabricatorMailEngineExtension { 5 + 6 + const EXTENSIONKEY = 'application/object'; 7 + 8 + public function supportsObject($object) { 9 + return true; 10 + } 11 + 12 + public function newMailStampTemplates($object) { 13 + $templates = array( 14 + id(new PhabricatorStringMailStamp()) 15 + ->setKey('application') 16 + ->setLabel(pht('Application')), 17 + ); 18 + 19 + if ($this->hasMonogram($object)) { 20 + $templates[] = id(new PhabricatorStringMailStamp()) 21 + ->setKey('monogram') 22 + ->setLabel(pht('Object Monogram')); 23 + } 24 + 25 + if ($this->hasPHID($object)) { 26 + // This is a PHID, but we always want to render it as a raw string, so 27 + // use a string mail stamp. 28 + $templates[] = id(new PhabricatorStringMailStamp()) 29 + ->setKey('phid') 30 + ->setLabel(pht('Object PHID')); 31 + 32 + $templates[] = id(new PhabricatorStringMailStamp()) 33 + ->setKey('object-type') 34 + ->setLabel(pht('Object Type')); 35 + } 36 + 37 + return $templates; 38 + } 39 + 40 + public function newMailStamps($object, array $xactions) { 41 + $editor = $this->getEditor(); 42 + $viewer = $this->getViewer(); 43 + 44 + $application = null; 45 + $class = $editor->getEditorApplicationClass(); 46 + if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { 47 + $application = newv($class, array()); 48 + } 49 + 50 + if ($application) { 51 + $application_name = $application->getName(); 52 + $this->getMailStamp('application') 53 + ->setValue($application_name); 54 + } 55 + 56 + if ($this->hasMonogram($object)) { 57 + $monogram = $object->getMonogram(); 58 + $this->getMailStamp('monogram') 59 + ->setValue($monogram); 60 + } 61 + 62 + if ($this->hasPHID($object)) { 63 + $object_phid = $object->getPHID(); 64 + 65 + $this->getMailStamp('phid') 66 + ->setValue($object_phid); 67 + 68 + $phid_type = phid_get_type($object_phid); 69 + if ($phid_type != PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { 70 + $this->getMailStamp('object-type') 71 + ->setValue($phid_type); 72 + } 73 + } 74 + } 75 + 76 + private function hasPHID($object) { 77 + if (!($object instanceof LiskDAO)) { 78 + return false; 79 + } 80 + 81 + if (!$object->getConfigOption(LiskDAO::CONFIG_AUX_PHID)) { 82 + return false; 83 + } 84 + 85 + return true; 86 + } 87 + 88 + private function hasMonogram($object) { 89 + return method_exists($object, 'getMonogram'); 90 + } 91 + 92 + }