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

Recognize self-URI links to Diffusion files and give them special rendering behavior

Summary:
Depends on D20530. Ref T13291. When users paste links to files in Diffusion into remarkup contexts, identify them and specialize the rendering.

When the URIs are embedded with `{...}`, parse them in more detail.

This is a lead-up to a `{src ...}` rule which will use the same `View` but give users more options to customize presentation.

Test Plan: {F6463580}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13291

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

+348 -26
+8 -2
src/__phutil_library_map__.php
··· 999 999 'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php', 1000 1000 'DiffusionSetPasswordSettingsPanel' => 'applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php', 1001 1001 'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php', 1002 + 'DiffusionSourceHyperlinkEngineExtension' => 'applications/diffusion/engineextension/DiffusionSourceHyperlinkEngineExtension.php', 1003 + 'DiffusionSourceLinkView' => 'applications/diffusion/view/DiffusionSourceLinkView.php', 1002 1004 'DiffusionSubversionCommandEngine' => 'applications/diffusion/protocol/DiffusionSubversionCommandEngine.php', 1003 1005 'DiffusionSubversionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionSSHWorkflow.php', 1004 1006 'DiffusionSubversionServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php', ··· 4340 4342 'PhabricatorRemarkupDocumentEngine' => 'applications/files/document/PhabricatorRemarkupDocumentEngine.php', 4341 4343 'PhabricatorRemarkupEditField' => 'applications/transactions/editfield/PhabricatorRemarkupEditField.php', 4342 4344 'PhabricatorRemarkupFigletBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php', 4345 + 'PhabricatorRemarkupHyperlinkEngineExtension' => 'applications/remarkup/engineextension/PhabricatorRemarkupHyperlinkEngineExtension.php', 4343 4346 'PhabricatorRemarkupUIExample' => 'applications/uiexample/examples/PhabricatorRemarkupUIExample.php', 4344 4347 'PhabricatorRepositoriesSetupCheck' => 'applications/config/check/PhabricatorRepositoriesSetupCheck.php', 4345 4348 'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', ··· 6681 6684 'DiffusionServeController' => 'DiffusionController', 6682 6685 'DiffusionSetPasswordSettingsPanel' => 'PhabricatorSettingsPanel', 6683 6686 'DiffusionSetupException' => 'Exception', 6687 + 'DiffusionSourceHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension', 6688 + 'DiffusionSourceLinkView' => 'AphrontView', 6684 6689 'DiffusionSubversionCommandEngine' => 'DiffusionCommandEngine', 6685 6690 'DiffusionSubversionSSHWorkflow' => 'DiffusionSSHWorkflow', 6686 6691 'DiffusionSubversionServeSSHWorkflow' => 'DiffusionSubversionSSHWorkflow', ··· 6786 6791 'DoorkeeperExternalObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6787 6792 'DoorkeeperFeedStoryPublisher' => 'Phobject', 6788 6793 'DoorkeeperFeedWorker' => 'FeedPushWorker', 6789 - 'DoorkeeperHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension', 6794 + 'DoorkeeperHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension', 6790 6795 'DoorkeeperImportEngine' => 'Phobject', 6791 6796 'DoorkeeperJIRAFeedWorker' => 'DoorkeeperFeedWorker', 6792 6797 'DoorkeeperMissingLinkException' => 'Exception', ··· 10595 10600 'PhabricatorRemarkupDocumentEngine' => 'PhabricatorDocumentEngine', 10596 10601 'PhabricatorRemarkupEditField' => 'PhabricatorEditField', 10597 10602 'PhabricatorRemarkupFigletBlockInterpreter' => 'PhutilRemarkupBlockInterpreter', 10603 + 'PhabricatorRemarkupHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension', 10598 10604 'PhabricatorRemarkupUIExample' => 'PhabricatorUIExample', 10599 10605 'PhabricatorRepositoriesSetupCheck' => 'PhabricatorSetupCheck', 10600 10606 'PhabricatorRepository' => array( ··· 10883 10889 'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck', 10884 10890 'PhabricatorSelectEditField' => 'PhabricatorEditField', 10885 10891 'PhabricatorSelectSetting' => 'PhabricatorSetting', 10886 - 'PhabricatorSelfHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension', 10892 + 'PhabricatorSelfHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension', 10887 10893 'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel', 10888 10894 'PhabricatorSetConfigType' => 'PhabricatorTextConfigType', 10889 10895 'PhabricatorSetting' => 'Phobject',
+84
src/applications/diffusion/engineextension/DiffusionSourceHyperlinkEngineExtension.php
··· 1 + <?php 2 + 3 + final class DiffusionSourceHyperlinkEngineExtension 4 + extends PhabricatorRemarkupHyperlinkEngineExtension { 5 + 6 + const LINKENGINEKEY = 'diffusion-src'; 7 + 8 + public function processHyperlinks(array $hyperlinks) { 9 + $engine = $this->getEngine(); 10 + $viewer = $engine->getConfig('viewer'); 11 + 12 + if (!$viewer) { 13 + return; 14 + } 15 + 16 + $hyperlinks = $this->getSelfLinks($hyperlinks); 17 + 18 + $links = array(); 19 + foreach ($hyperlinks as $link) { 20 + $uri = $link->getURI(); 21 + $uri = new PhutilURI($uri); 22 + 23 + $path = $uri->getPath(); 24 + 25 + $pattern = 26 + '(^'. 27 + '/(?:diffusion|source)'. 28 + '/(?P<identifier>[^/]+)'. 29 + '/browse'. 30 + '/(?P<blob>.*)'. 31 + '\z)'; 32 + $matches = null; 33 + if (!preg_match($pattern, $path, $matches)) { 34 + continue; 35 + } 36 + 37 + $links[] = array( 38 + 'ref' => $link, 39 + 'identifier' => $matches['identifier'], 40 + 'blob' => $matches['blob'], 41 + ); 42 + } 43 + 44 + if (!$links) { 45 + return; 46 + } 47 + 48 + $identifiers = ipull($links, 'identifier'); 49 + 50 + $query = id(new PhabricatorRepositoryQuery()) 51 + ->setViewer($viewer) 52 + ->withIdentifiers($identifiers); 53 + 54 + $query->execute(); 55 + 56 + $repository_map = $query->getIdentifierMap(); 57 + 58 + foreach ($links as $link) { 59 + $identifier = $link['identifier']; 60 + 61 + $repository = idx($repository_map, $identifier); 62 + if (!$repository) { 63 + continue; 64 + } 65 + 66 + $ref = $link['ref']; 67 + $uri = $ref->getURI(); 68 + 69 + 70 + $tag = id(new DiffusionSourceLinkView()) 71 + ->setViewer($viewer) 72 + ->setRepository($repository) 73 + ->setURI($uri) 74 + ->setBlob($link['blob']); 75 + 76 + if (!$ref->isEmbed()) { 77 + $tag->setText($uri); 78 + } 79 + 80 + $ref->setResult($tag); 81 + } 82 + } 83 + 84 + }
-4
src/applications/diffusion/request/DiffusionGitRequest.php
··· 2 2 3 3 final class DiffusionGitRequest extends DiffusionRequest { 4 4 5 - public function supportsBranches() { 6 - return true; 7 - } 8 - 9 5 protected function isStableCommit($symbol) { 10 6 return preg_match('/^[a-f0-9]{40}\z/', $symbol); 11 7 }
-4
src/applications/diffusion/request/DiffusionMercurialRequest.php
··· 2 2 3 3 final class DiffusionMercurialRequest extends DiffusionRequest { 4 4 5 - public function supportsBranches() { 6 - return true; 7 - } 8 - 9 5 protected function isStableCommit($symbol) { 10 6 return preg_match('/^[a-f0-9]{40}\z/', $symbol); 11 7 }
+4 -1
src/applications/diffusion/request/DiffusionRequest.php
··· 28 28 private $branchObject = false; 29 29 private $refAlternatives; 30 30 31 - abstract public function supportsBranches(); 31 + final public function supportsBranches() { 32 + return $this->getRepository()->supportsRefs(); 33 + } 34 + 32 35 abstract protected function isStableCommit($symbol); 33 36 34 37 protected function didInitialize() {
-4
src/applications/diffusion/request/DiffusionSvnRequest.php
··· 2 2 3 3 final class DiffusionSvnRequest extends DiffusionRequest { 4 4 5 - public function supportsBranches() { 6 - return false; 7 - } 8 - 9 5 protected function isStableCommit($symbol) { 10 6 return preg_match('/^[1-9]\d*\z/', $symbol); 11 7 }
+208
src/applications/diffusion/view/DiffusionSourceLinkView.php
··· 1 + <?php 2 + 3 + final class DiffusionSourceLinkView 4 + extends AphrontView { 5 + 6 + private $repository; 7 + private $text; 8 + private $uri; 9 + private $blob; 10 + private $blobMap; 11 + private $refName; 12 + private $path; 13 + private $line; 14 + private $commit; 15 + 16 + public function setRepository($repository) { 17 + $this->repository = $repository; 18 + $this->blobMap = null; 19 + return $this; 20 + } 21 + 22 + public function getRepository() { 23 + return $this->repository; 24 + } 25 + 26 + public function setText($text) { 27 + $this->text = $text; 28 + return $this; 29 + } 30 + 31 + public function getText() { 32 + return $this->text; 33 + } 34 + 35 + public function setURI($uri) { 36 + $this->uri = $uri; 37 + return $this; 38 + } 39 + 40 + public function getURI() { 41 + return $this->uri; 42 + } 43 + 44 + public function setBlob($blob) { 45 + $this->blob = $blob; 46 + $this->blobMap = null; 47 + return $this; 48 + } 49 + 50 + public function getBlob() { 51 + return $this->blob; 52 + } 53 + 54 + public function setRefName($ref_name) { 55 + $this->refName = $ref_name; 56 + return $this; 57 + } 58 + 59 + public function getRefName() { 60 + return $this->refName; 61 + } 62 + 63 + public function setPath($path) { 64 + $this->path = $path; 65 + return $this; 66 + } 67 + 68 + public function getPath() { 69 + return $this->path; 70 + } 71 + 72 + public function setCommit($commit) { 73 + $this->commit = $commit; 74 + return $this; 75 + } 76 + 77 + public function getCommit() { 78 + return $this->commit; 79 + } 80 + 81 + public function setLine($line) { 82 + $this->line = $line; 83 + return $this; 84 + } 85 + 86 + public function getLine() { 87 + return $this->line; 88 + } 89 + 90 + public function getDisplayPath() { 91 + if ($this->path !== null) { 92 + return $this->path; 93 + } 94 + 95 + return $this->getBlobPath(); 96 + } 97 + 98 + public function getDisplayRefName() { 99 + if ($this->refName !== null) { 100 + return $this->refName; 101 + } 102 + 103 + return $this->getBlobRefName(); 104 + } 105 + 106 + public function getDisplayCommit() { 107 + if ($this->commit !== null) { 108 + return $this->commit; 109 + } 110 + 111 + return $this->getBlobCommit(); 112 + } 113 + 114 + public function getDisplayLine() { 115 + if ($this->line !== null) { 116 + return $this->line; 117 + } 118 + 119 + return $this->getBlobLine(); 120 + } 121 + 122 + private function getBlobPath() { 123 + return idx($this->getBlobMap(), 'path'); 124 + } 125 + 126 + private function getBlobRefName() { 127 + return idx($this->getBlobMap(), 'branch'); 128 + } 129 + 130 + private function getBlobLine() { 131 + return idx($this->getBlobMap(), 'line'); 132 + } 133 + 134 + private function getBlobCommit() { 135 + return idx($this->getBlobMap(), 'commit'); 136 + } 137 + 138 + private function getBlobMap() { 139 + if ($this->blobMap === null) { 140 + $repository = $this->getRepository(); 141 + $blob = $this->blob; 142 + 143 + if ($repository && ($blob !== null)) { 144 + $map = DiffusionRequest::parseRequestBlob( 145 + $blob, 146 + $repository->supportsRefs()); 147 + } else { 148 + $map = array(); 149 + } 150 + 151 + $this->blobMap = $map; 152 + } 153 + 154 + return $this->blobMap; 155 + } 156 + 157 + public function render() { 158 + $repository = $this->getRepository(); 159 + $uri = $this->getURI(); 160 + 161 + $color = 'blue'; 162 + $icon = 'fa-file-text-o'; 163 + 164 + $text = $this->getText(); 165 + if (!strlen($text)) { 166 + $path = $this->getDisplayPath(); 167 + 168 + $line = $this->getDisplayLine(); 169 + if ($line !== null) { 170 + $path = pht('%s:%s', $path, $line); 171 + } 172 + 173 + if ($repository) { 174 + $path = pht('%s %s', $repository->getMonogram(), $path); 175 + } 176 + 177 + if ($repository && $repository->supportsRefs()) { 178 + $default_ref = $repository->getDefaultBranch(); 179 + } else { 180 + $default_ref = null; 181 + } 182 + 183 + $ref_name = $this->getDisplayRefName(); 184 + if ($ref_name === $default_ref) { 185 + $ref_name = null; 186 + } 187 + 188 + $commit = $this->getDisplayCommit(); 189 + if ($ref_name !== null && $commit !== null) { 190 + $text = pht('%s (on %s at %s)', $path, $ref_name, $commit); 191 + } else if ($ref_name !== null) { 192 + $text = pht('%s (on %s)', $path, $ref_name); 193 + } else if ($commit !== null) { 194 + $text = pht('%s (at %s)', $path, $commit); 195 + } else { 196 + $text = $path; 197 + } 198 + } 199 + 200 + return id(new PHUITagView()) 201 + ->setType(PHUITagView::TYPE_SHADE) 202 + ->setColor($color) 203 + ->setIcon($icon) 204 + ->setHref($uri) 205 + ->setName($text); 206 + } 207 + 208 + }
+1 -1
src/applications/doorkeeper/engineextension/DoorkeeperHyperlinkEngineExtension.php
··· 1 1 <?php 2 2 3 3 final class DoorkeeperHyperlinkEngineExtension 4 - extends PhutilRemarkupHyperlinkEngineExtension { 4 + extends PhabricatorRemarkupHyperlinkEngineExtension { 5 5 6 6 const LINKENGINEKEY = 'doorkeeper'; 7 7
+2 -10
src/applications/meta/engineextension/PhabricatorSelfHyperlinkEngineExtension.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorSelfHyperlinkEngineExtension 4 - extends PhutilRemarkupHyperlinkEngineExtension { 4 + extends PhabricatorRemarkupHyperlinkEngineExtension { 5 5 6 6 const LINKENGINEKEY = 'phabricator-self'; 7 7 ··· 15 15 return; 16 16 } 17 17 18 - // Find links which point to resources on the Phabricator install itself. 19 - // We're going to try to enhance these. 20 - $self_links = array(); 21 - foreach ($hyperlinks as $link) { 22 - $uri = $link->getURI(); 23 - if (PhabricatorEnv::isSelfURI($uri)) { 24 - $self_links[] = $link; 25 - } 26 - } 18 + $self_links = $this->getSelfLinks($hyperlinks); 27 19 28 20 // For links in the form "/X123", we can reasonably guess that they are 29 21 // fairly likely to be object names. Try to look them up.
+32
src/applications/remarkup/engineextension/PhabricatorRemarkupHyperlinkEngineExtension.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorRemarkupHyperlinkEngineExtension 4 + extends PhutilRemarkupHyperlinkEngineExtension { 5 + 6 + final protected function getSelfLinks(array $hyperlinks) { 7 + assert_instances_of($hyperlinks, 'PhutilRemarkupHyperlinkRef'); 8 + 9 + $allowed_protocols = array( 10 + 'http' => true, 11 + 'https' => true, 12 + ); 13 + 14 + $results = array(); 15 + foreach ($hyperlinks as $link) { 16 + $uri = $link->getURI(); 17 + 18 + if (!PhabricatorEnv::isSelfURI($uri)) { 19 + continue; 20 + } 21 + 22 + $protocol = id(new PhutilURI($uri))->getProtocol(); 23 + if (!isset($allowed_protocols[$protocol])) { 24 + continue; 25 + } 26 + 27 + $results[] = $link; 28 + } 29 + 30 + return $results; 31 + } 32 + }
+9
src/applications/repository/storage/PhabricatorRepository.php
··· 2040 2040 return true; 2041 2041 } 2042 2042 2043 + 2044 + public function supportsRefs() { 2045 + if ($this->isSVN()) { 2046 + return false; 2047 + } 2048 + 2049 + return true; 2050 + } 2051 + 2043 2052 public function getAlmanacServiceCacheKey() { 2044 2053 $service_phid = $this->getAlmanacServicePHID(); 2045 2054 if (!$service_phid) {