@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.

Process Remarkup in text and HTML email bodies appropriately

Summary: Ref T6343, adding HTMLMailMode to remarkup, and most objects should now be processed and appear pretty in emails.

Test Plan: Add a comment to a Maniphest task containing a mention of an object like '{T1}' or 'T1'. Emails should show a styled version of the object similar to how the object looks in the context of the Maniphest task in the UI.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: chad, Korvin, epriestley

Maniphest Tasks: T6343, T2617

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

authored by

lkassianik and committed by
epriestley
1b438a8b 81a13ed8

+178 -29
+4
src/applications/diviner/markup/DivinerSymbolRemarkupRule.php
··· 140 140 $link = $title; 141 141 } 142 142 } else if ($href) { 143 + if ($this->getEngine()->isHTMLMailMode()) { 144 + $href = PhabricatorEnv::getProductionURI($href); 145 + } 146 + 143 147 $link = $this->newTag( 144 148 'a', 145 149 array(
+6 -1
src/applications/macro/markup/PhabricatorIconRemarkupRule.php
··· 14 14 } 15 15 16 16 public function markupIcon($matches) { 17 - if (!$this->isFlatText($matches[0])) { 17 + $engine = $this->getEngine(); 18 + $text_mode = $engine->isTextMode(); 19 + $mail_mode = $engine->isHTMLMailMode(); 20 + 21 + if (!$this->isFlatText($matches[0]) || $text_mode || $mail_mode) { 18 22 return $matches[0]; 19 23 } 20 24 ··· 68 72 69 73 $icon_view = id(new PHUIIconView()) 70 74 ->setIconFont('fa-'.$icon, $color); 75 + 71 76 72 77 return $this->getEngine()->storeText($icon_view); 73 78 }
+2
src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php
··· 109 109 $result = $spec['original'].' <'.$src_uri.'>'; 110 110 $engine->overwriteStoredText($spec['token'], $result); 111 111 continue; 112 + } else if ($this->getEngine()->isHTMLMailMode()) { 113 + $src_uri = PhabricatorEnv::getProductionURI($src_uri); 112 114 } 113 115 114 116 $file_data = $file->getMetadata();
+4
src/applications/macro/markup/PhabricatorMemeRemarkupRule.php
··· 34 34 ->alter('uppertext', $options['above']) 35 35 ->alter('lowertext', $options['below']); 36 36 37 + if ($this->getEngine()->isHTMLMailMode()) { 38 + $uri = PhabricatorEnv::getProductionURI($uri); 39 + } 40 + 37 41 if ($this->getEngine()->isTextMode()) { 38 42 $img = 39 43 ($options['above'] != '' ? "\"{$options['above']}\"\n" : '').
+42
src/applications/metamta/view/PhabricatorMetaMTAMailBody.php
··· 12 12 private $htmlSections = array(); 13 13 private $attachments = array(); 14 14 15 + private $viewer; 16 + 17 + public function getViewer() { 18 + return $this->viewer; 19 + } 20 + 21 + public function setViewer($viewer) { 22 + $this->viewer = $viewer; 23 + } 15 24 16 25 /* -( Composition )-------------------------------------------------------- */ 17 26 ··· 30 39 $this->htmlSections[] = phutil_escape_html_newlines( 31 40 phutil_tag('div', array(), $text)); 32 41 } 42 + return $this; 43 + } 44 + 45 + public function addRemarkupSection($text) { 46 + try { 47 + $engine = PhabricatorMarkupEngine::newMarkupEngine(array()); 48 + $engine->setConfig('viewer', $this->getViewer()); 49 + $engine->setMode(PhutilRemarkupEngine::MODE_TEXT); 50 + $styled_text = $engine->markupText($text); 51 + $this->sections[] = $styled_text; 52 + } catch (Exception $ex) { 53 + phlog($ex); 54 + $this->sections[] = $text; 55 + } 56 + 57 + try { 58 + $mail_engine = PhabricatorMarkupEngine::newMarkupEngine(array()); 59 + $mail_engine->setConfig('viewer', $this->getViewer()); 60 + $mail_engine->setMode(PhutilRemarkupEngine::MODE_HTML_MAIL); 61 + $mail_engine->setConfig( 62 + 'uri.base', 63 + PhabricatorEnv::getProductionURI('/')); 64 + $html = $mail_engine->markupText($text); 65 + $this->htmlSections[] = $html; 66 + } catch (Exception $ex) { 67 + phlog($ex); 68 + $this->htmlSections[] = phutil_escape_html_newlines( 69 + phutil_tag( 70 + 'div', 71 + array(), 72 + $text)); 73 + } 74 + 33 75 return $this; 34 76 } 35 77
+33 -14
src/applications/people/markup/PhabricatorMentionRemarkupRule.php
··· 100 100 $user = $actual_users[$username]; 101 101 Javelin::initBehavior('phabricator-hovercards'); 102 102 103 - $tag = id(new PHUITagView()) 104 - ->setType(PHUITagView::TYPE_PERSON) 105 - ->setPHID($user->getPHID()) 106 - ->setName('@'.$user->getUserName()) 107 - ->setHref('/p/'.$user->getUserName().'/'); 103 + $user_href = '/p/'.$user->getUserName().'/'; 108 104 109 - if (!$user->isUserActivated()) { 110 - $tag->setDotColor(PHUITagView::COLOR_GREY); 105 + if ($engine->isHTMLMailMode()) { 106 + $user_href = PhabricatorEnv::getProductionURI($user_href); 107 + $tag = phutil_tag( 108 + 'a', 109 + array( 110 + 'href' => $user_href, 111 + 'style' => 'background-color: #f1f7ff; 112 + border-color: #f1f7ff; 113 + border: 1px solid transparent; 114 + border-radius: 3px; 115 + color: #19558d; 116 + font-weight: bold; 117 + padding: 0 4px;', 118 + ), 119 + '@'.$user->getUserName()); 111 120 } else { 112 - $status = idx($user_statuses, $user->getPHID()); 113 - if ($status) { 114 - $status = $status->getStatus(); 115 - if ($status == PhabricatorCalendarEvent::STATUS_AWAY) { 116 - $tag->setDotColor(PHUITagView::COLOR_RED); 117 - } else if ($status == PhabricatorCalendarEvent::STATUS_AWAY) { 118 - $tag->setDotColor(PHUITagView::COLOR_ORANGE); 121 + $tag = id(new PHUITagView()) 122 + ->setType(PHUITagView::TYPE_PERSON) 123 + ->setPHID($user->getPHID()) 124 + ->setName('@'.$user->getUserName()) 125 + ->setHref($user_href); 126 + 127 + if (!$user->isUserActivated()) { 128 + $tag->setDotColor(PHUITagView::COLOR_GREY); 129 + } else { 130 + $status = idx($user_statuses, $user->getPHID()); 131 + if ($status) { 132 + $status = $status->getStatus(); 133 + if ($status == PhabricatorCalendarEvent::STATUS_AWAY) { 134 + $tag->setDotColor(PHUITagView::COLOR_RED); 135 + } else if ($status == PhabricatorCalendarEvent::STATUS_AWAY) { 136 + $tag->setDotColor(PHUITagView::COLOR_ORANGE); 137 + } 119 138 } 120 139 } 121 140 }
+4 -1
src/applications/phriction/markup/PhrictionRemarkupRule.php
··· 29 29 $slug = PhrictionDocument::getSlugURI($slug); 30 30 $href = (string)id(new PhutilURI($slug))->setFragment($fragment); 31 31 32 + $text_mode = $this->getEngine()->isTextMode(); 33 + $mail_mode = $this->getEngine()->isHTMLMailMode(); 34 + 32 35 if ($this->getEngine()->getState('toc')) { 33 36 $text = $name; 34 - } else if ($this->getEngine()->isTextMode()) { 37 + } else if ($text_mode || $mail_mode) { 35 38 return PhabricatorEnv::getProductionURI($href); 36 39 } else { 37 40 $text = $this->newTag(
+2 -1
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 2159 2159 } 2160 2160 2161 2161 $body = new PhabricatorMetaMTAMailBody(); 2162 + $body->setViewer($this->requireActor()); 2162 2163 $body->addRawSection(implode("\n", $headers)); 2163 2164 2164 2165 foreach ($comments as $comment) { 2165 - $body->addRawSection($comment); 2166 + $body->addRemarkupSection($comment); 2166 2167 } 2167 2168 2168 2169 if ($object instanceof PhabricatorCustomFieldInterface) {
+16 -6
src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php
··· 80 80 $out[] = $tag; 81 81 } 82 82 83 + if ($this->getEngine()->isHTMLMailMode()) { 84 + $arrow_attr = array( 85 + 'style' => 'color: #92969D;', 86 + ); 87 + $nav_attr = array(); 88 + } else { 89 + $arrow_attr = array( 90 + 'class' => 'remarkup-nav-sequence-arrow', 91 + ); 92 + $nav_attr = array( 93 + 'class' => 'remarkup-nav-sequence', 94 + ); 95 + } 96 + 83 97 $joiner = phutil_tag( 84 98 'span', 85 - array( 86 - 'class' => 'remarkup-nav-sequence-arrow', 87 - ), 99 + $arrow_attr, 88 100 " \xE2\x86\x92 "); 89 101 90 102 $out = phutil_implode_html($joiner, $out); 91 103 92 104 $out = phutil_tag( 93 105 'span', 94 - array( 95 - 'class' => 'remarkup-nav-sequence', 96 - ), 106 + $nav_attr, 97 107 $out); 98 108 99 109 return $this->getEngine()->storeText($out);
+62 -5
src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php
··· 44 44 return $handle->getURI(); 45 45 } 46 46 47 - protected function renderObjectRef($object, $handle, $anchor, $id) { 47 + protected function renderObjectRefForAnyMedia ( 48 + $object, 49 + $handle, 50 + $anchor, 51 + $id) { 48 52 $href = $this->getObjectHref($object, $handle, $id); 49 53 $text = $this->getObjectNamePrefix().$id; 50 54 ··· 55 59 56 60 if ($this->getEngine()->isTextMode()) { 57 61 return PhabricatorEnv::getProductionURI($href); 62 + } else if ($this->getEngine()->isHTMLMailMode()) { 63 + $href = PhabricatorEnv::getProductionURI($href); 64 + return $this->renderObjectTagForMail($text, $href, $handle); 58 65 } 59 66 67 + return $this->renderObjectRef($object, $handle, $anchor, $id); 68 + 69 + } 70 + 71 + protected function renderObjectRef($object, $handle, $anchor, $id) { 72 + $href = $this->getObjectHref($object, $handle, $id); 73 + $text = $this->getObjectNamePrefix().$id; 60 74 $status_closed = PhabricatorObjectHandleStatus::STATUS_CLOSED; 75 + 76 + if ($anchor) { 77 + $href = $href.'#'.$anchor; 78 + $text = $text.'#'.$anchor; 79 + } 61 80 62 81 $attr = array( 63 82 'phid' => $handle->getPHID(), ··· 67 86 return $this->renderHovertag($text, $href, $attr); 68 87 } 69 88 70 - protected function renderObjectEmbed($object, $handle, $options) { 89 + protected function renderObjectEmbedForAnyMedia($object, $handle, $options) { 71 90 $name = $handle->getFullName(); 72 91 $href = $handle->getURI(); 73 - $status_closed = PhabricatorObjectHandleStatus::STATUS_CLOSED; 74 92 75 93 if ($this->getEngine()->isTextMode()) { 76 94 return $name.' <'.PhabricatorEnv::getProductionURI($href).'>'; 95 + } else if ($this->getEngine()->isHTMLMailMode()) { 96 + $href = PhabricatorEnv::getProductionURI($href); 97 + return $this->renderObjectTagForMail($name, $href, $handle); 77 98 } 78 99 100 + return $this->renderObjectEmbed($object, $handle, $options); 101 + } 102 + 103 + protected function renderObjectEmbed($object, $handle, $options) { 104 + $name = $handle->getFullName(); 105 + $href = $handle->getURI(); 106 + $status_closed = PhabricatorObjectHandleStatus::STATUS_CLOSED; 79 107 $attr = array( 80 108 'phid' => $handle->getPHID(), 81 109 'closed' => ($handle->getStatus() == $status_closed), 82 110 ); 83 111 84 112 return $this->renderHovertag($name, $href, $attr); 113 + } 114 + 115 + protected function renderObjectTagForMail( 116 + $text, 117 + $href, 118 + $handle) { 119 + 120 + $status_closed = PhabricatorObjectHandleStatus::STATUS_CLOSED; 121 + $strikethrough = $handle->getStatus() == $status_closed ? 122 + 'text-decoration: line-through;' : 123 + 'text-decoration: none;'; 124 + 125 + return phutil_tag( 126 + 'a', 127 + array( 128 + 'href' => $href, 129 + 'style' => 'background-color: #e7e7e7; 130 + border-color: #e7e7e7; 131 + border-radius: 3px; 132 + padding: 0 4px; 133 + font-weight: bold; 134 + color: black;' 135 + .$strikethrough, 136 + ), 137 + $text); 85 138 } 86 139 87 140 protected function renderHovertag($name, $href, array $attr = array()) { ··· 282 335 $object = $objects[$spec['id']]; 283 336 switch ($spec['type']) { 284 337 case 'ref': 285 - $view = $this->renderObjectRef( 338 + 339 + $view = $this->renderObjectRefForAnyMedia( 286 340 $object, 287 341 $handle, 288 342 $spec['anchor'], ··· 290 344 break; 291 345 case 'embed': 292 346 $spec['options'] = $this->assertFlatText($spec['options']); 293 - $view = $this->renderObjectEmbed($object, $handle, $spec['options']); 347 + $view = $this->renderObjectEmbedForAnyMedia( 348 + $object, 349 + $handle, 350 + $spec['options']); 294 351 break; 295 352 } 296 353 $engine->overwriteStoredText($spec['token'], $view);
+3 -1
src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php
··· 20 20 21 21 public function markupYoutubeLink() { 22 22 $v = idx($this->uri->getQueryParams(), 'v'); 23 + $text_mode = $this->getEngine()->isTextMode(); 24 + $mail_mode = $this->getEngine()->isHTMLMailMode(); 23 25 24 - if ($this->getEngine()->isTextMode()) { 26 + if ($text_mode || $mail_mode) { 25 27 return $this->getEngine()->storeText('http://youtu.be/'.$v); 26 28 } 27 29