Page MenuHomePhabricator

D20528.diff
No OneTemporary

D20528.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1072,7 +1072,6 @@
'DivinerSymbolRemarkupRule' => 'applications/diviner/markup/DivinerSymbolRemarkupRule.php',
'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php',
'DoorkeeperAsanaFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php',
- 'DoorkeeperAsanaRemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperAsanaRemarkupRule.php',
'DoorkeeperBridge' => 'applications/doorkeeper/bridge/DoorkeeperBridge.php',
'DoorkeeperBridgeAsana' => 'applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php',
'DoorkeeperBridgeGitHub' => 'applications/doorkeeper/bridge/DoorkeeperBridgeGitHub.php',
@@ -1088,15 +1087,16 @@
'DoorkeeperExternalObjectQuery' => 'applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php',
'DoorkeeperFeedStoryPublisher' => 'applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php',
'DoorkeeperFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperFeedWorker.php',
+ 'DoorkeeperHyperlinkEngineExtension' => 'applications/doorkeeper/engineextension/DoorkeeperHyperlinkEngineExtension.php',
'DoorkeeperImportEngine' => 'applications/doorkeeper/engine/DoorkeeperImportEngine.php',
'DoorkeeperJIRAFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php',
- 'DoorkeeperJIRARemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperJIRARemarkupRule.php',
'DoorkeeperMissingLinkException' => 'applications/doorkeeper/exception/DoorkeeperMissingLinkException.php',
'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php',
- 'DoorkeeperRemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php',
+ 'DoorkeeperRemarkupURIInterface' => 'applications/doorkeeper/interface/DoorkeeperRemarkupURIInterface.php',
'DoorkeeperSchemaSpec' => 'applications/doorkeeper/storage/DoorkeeperSchemaSpec.php',
'DoorkeeperTagView' => 'applications/doorkeeper/view/DoorkeeperTagView.php',
'DoorkeeperTagsController' => 'applications/doorkeeper/controller/DoorkeeperTagsController.php',
+ 'DoorkeeperURIRef' => 'applications/doorkeeper/engine/DoorkeeperURIRef.php',
'DrydockAcquiredBrokenResourceException' => 'applications/drydock/exception/DrydockAcquiredBrokenResourceException.php',
'DrydockAlmanacServiceHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php',
'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php',
@@ -6761,7 +6761,6 @@
'DivinerSymbolRemarkupRule' => 'PhutilRemarkupRule',
'DivinerWorkflow' => 'PhabricatorManagementWorkflow',
'DoorkeeperAsanaFeedWorker' => 'DoorkeeperFeedWorker',
- 'DoorkeeperAsanaRemarkupRule' => 'DoorkeeperRemarkupRule',
'DoorkeeperBridge' => 'Phobject',
'DoorkeeperBridgeAsana' => 'DoorkeeperBridge',
'DoorkeeperBridgeGitHub' => 'DoorkeeperBridge',
@@ -6779,15 +6778,15 @@
'DoorkeeperExternalObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DoorkeeperFeedStoryPublisher' => 'Phobject',
'DoorkeeperFeedWorker' => 'FeedPushWorker',
+ 'DoorkeeperHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension',
'DoorkeeperImportEngine' => 'Phobject',
'DoorkeeperJIRAFeedWorker' => 'DoorkeeperFeedWorker',
- 'DoorkeeperJIRARemarkupRule' => 'DoorkeeperRemarkupRule',
'DoorkeeperMissingLinkException' => 'Exception',
'DoorkeeperObjectRef' => 'Phobject',
- 'DoorkeeperRemarkupRule' => 'PhutilRemarkupRule',
'DoorkeeperSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'DoorkeeperTagView' => 'AphrontView',
'DoorkeeperTagsController' => 'PhabricatorController',
+ 'DoorkeeperURIRef' => 'Phobject',
'DrydockAcquiredBrokenResourceException' => 'Exception',
'DrydockAlmanacServiceHostBlueprintImplementation' => 'DrydockBlueprintImplementation',
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
@@ -8090,7 +8089,10 @@
'PhabricatorApplicationsController' => 'PhabricatorController',
'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController',
'PhabricatorApplyEditField' => 'PhabricatorEditField',
- 'PhabricatorAsanaAuthProvider' => 'PhabricatorOAuth2AuthProvider',
+ 'PhabricatorAsanaAuthProvider' => array(
+ 'PhabricatorOAuth2AuthProvider',
+ 'DoorkeeperRemarkupURIInterface',
+ ),
'PhabricatorAsanaConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorAsanaTaskHasObjectEdgeType' => 'PhabricatorEdgeType',
@@ -9569,7 +9571,10 @@
'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher',
'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase',
'PhabricatorIteratorFileUploadSource' => 'PhabricatorFileUploadSource',
- 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider',
+ 'PhabricatorJIRAAuthProvider' => array(
+ 'PhabricatorOAuth1AuthProvider',
+ 'DoorkeeperRemarkupURIInterface',
+ ),
'PhabricatorJSONConfigType' => 'PhabricatorTextConfigType',
'PhabricatorJSONDocumentEngine' => 'PhabricatorTextDocumentEngine',
'PhabricatorJSONExportFormat' => 'PhabricatorExportFormat',
diff --git a/src/applications/auth/provider/PhabricatorAsanaAuthProvider.php b/src/applications/auth/provider/PhabricatorAsanaAuthProvider.php
--- a/src/applications/auth/provider/PhabricatorAsanaAuthProvider.php
+++ b/src/applications/auth/provider/PhabricatorAsanaAuthProvider.php
@@ -1,6 +1,8 @@
<?php
-final class PhabricatorAsanaAuthProvider extends PhabricatorOAuth2AuthProvider {
+final class PhabricatorAsanaAuthProvider
+ extends PhabricatorOAuth2AuthProvider
+ implements DoorkeeperRemarkupURIInterface {
public function getProviderName() {
return pht('Asana');
@@ -46,4 +48,26 @@
return null;
}
+/* -( DoorkeeperRemarkupURIInterface )------------------------------------- */
+
+ public function getDoorkeeperURIRef(PhutilURI $uri) {
+ $uri_string = phutil_string_cast($uri);
+
+ $pattern = '(https://app\\.asana\\.com/0/(\\d+)/(\\d+))';
+ $matches = null;
+ if (!preg_match($pattern, $uri_string, $matches)) {
+ return null;
+ }
+
+ $context_id = $matches[1];
+ $task_id = $matches[2];
+
+ return id(new DoorkeeperURIRef())
+ ->setURI($uri)
+ ->setApplicationType(DoorkeeperBridgeAsana::APPTYPE_ASANA)
+ ->setApplicationDomain(DoorkeeperBridgeAsana::APPDOMAIN_ASANA)
+ ->setObjectType(DoorkeeperBridgeAsana::OBJTYPE_TASK)
+ ->setObjectID($task_id);
+ }
+
}
diff --git a/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php b/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php
--- a/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php
+++ b/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php
@@ -1,10 +1,8 @@
<?php
-final class PhabricatorJIRAAuthProvider extends PhabricatorOAuth1AuthProvider {
-
- public function getJIRABaseURI() {
- return $this->getProviderConfig()->getProperty(self::PROPERTY_JIRA_URI);
- }
+final class PhabricatorJIRAAuthProvider
+ extends PhabricatorOAuth1AuthProvider
+ implements DoorkeeperRemarkupURIInterface {
public function getProviderName() {
return pht('JIRA');
@@ -332,4 +330,33 @@
return $config->getProperty(self::PROPERTY_REPORT_COMMENT, true);
}
+/* -( DoorkeeperRemarkupURIInterface )------------------------------------- */
+
+ public function getDoorkeeperURIRef(PhutilURI $uri) {
+ $uri_string = phutil_string_cast($uri);
+
+ $pattern = '((https?://\S+?)/browse/([A-Z]+-[1-9]\d*))';
+ $matches = null;
+ if (!preg_match($pattern, $uri_string, $matches)) {
+ return null;
+ }
+
+ $domain = $matches[1];
+ $issue = $matches[2];
+
+ $config = $this->getProviderConfig();
+ $base_uri = $config->getProperty(self::PROPERTY_JIRA_URI);
+
+ if ($domain !== rtrim($base_uri, '/')) {
+ return null;
+ }
+
+ return id(new DoorkeeperURIRef())
+ ->setURI($uri)
+ ->setApplicationType(DoorkeeperBridgeJIRA::APPTYPE_JIRA)
+ ->setApplicationDomain($this->getProviderDomain())
+ ->setObjectType(DoorkeeperBridgeJIRA::OBJTYPE_ISSUE)
+ ->setObjectID($issue);
+ }
+
}
diff --git a/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php b/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php
--- a/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php
+++ b/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php
@@ -22,13 +22,6 @@
return pht('Connect to Other Software');
}
- public function getRemarkupRules() {
- return array(
- new DoorkeeperAsanaRemarkupRule(),
- new DoorkeeperJIRARemarkupRule(),
- );
- }
-
public function getRoutes() {
return array(
'/doorkeeper/' => array(
diff --git a/src/applications/doorkeeper/engine/DoorkeeperURIRef.php b/src/applications/doorkeeper/engine/DoorkeeperURIRef.php
new file mode 100644
--- /dev/null
+++ b/src/applications/doorkeeper/engine/DoorkeeperURIRef.php
@@ -0,0 +1,91 @@
+<?php
+
+final class DoorkeeperURIRef extends Phobject {
+
+ private $uri;
+ private $applicationType;
+ private $applicationDomain;
+ private $objectType;
+ private $objectID;
+ private $text;
+ private $displayMode = self::DISPLAY_FULL;
+
+ const DISPLAY_FULL = 'full';
+ const DISPLAY_SHORT = 'short';
+
+ public function setURI(PhutilURI $uri) {
+ $this->uri = $uri;
+ return $this;
+ }
+
+ public function getURI() {
+ return $this->uri;
+ }
+
+ public function setApplicationType($application_type) {
+ $this->applicationType = $application_type;
+ return $this;
+ }
+
+ public function getApplicationType() {
+ return $this->applicationType;
+ }
+
+ public function setApplicationDomain($application_domain) {
+ $this->applicationDomain = $application_domain;
+ return $this;
+ }
+
+ public function getApplicationDomain() {
+ return $this->applicationDomain;
+ }
+
+ public function setObjectType($object_type) {
+ $this->objectType = $object_type;
+ return $this;
+ }
+
+ public function getObjectType() {
+ return $this->objectType;
+ }
+
+ public function setObjectID($object_id) {
+ $this->objectID = $object_id;
+ return $this;
+ }
+
+ public function getObjectID() {
+ return $this->objectID;
+ }
+
+ public function setText($text) {
+ $this->text = $text;
+ return $this;
+ }
+
+ public function getText() {
+ return $this->text;
+ }
+
+ public function setDisplayMode($display_mode) {
+ $options = array(
+ self::DISPLAY_FULL => true,
+ self::DISPLAY_SHORT => true,
+ );
+
+ if (!isset($options[$display_mode])) {
+ throw new Exception(
+ pht(
+ 'DoorkeeperURIRef display mode "%s" is unknown.',
+ $display_mode));
+ }
+
+ $this->displayMode = $display_mode;
+ return $this;
+ }
+
+ public function getDisplayMode() {
+ return $this->displayMode;
+ }
+
+}
diff --git a/src/applications/doorkeeper/engineextension/DoorkeeperHyperlinkEngineExtension.php b/src/applications/doorkeeper/engineextension/DoorkeeperHyperlinkEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/doorkeeper/engineextension/DoorkeeperHyperlinkEngineExtension.php
@@ -0,0 +1,92 @@
+<?php
+
+final class DoorkeeperHyperlinkEngineExtension
+ extends PhutilRemarkupHyperlinkEngineExtension {
+
+ const LINKENGINEKEY = 'doorkeeper';
+
+ public function processHyperlinks(array $hyperlinks) {
+ $engine = $this->getEngine();
+ $viewer = $engine->getConfig('viewer');
+
+ if (!$viewer) {
+ return;
+ }
+
+ $configs = id(new PhabricatorAuthProviderConfigQuery())
+ ->setViewer($viewer)
+ ->withIsEnabled(true)
+ ->execute();
+
+ $providers = array();
+ foreach ($configs as $key => $config) {
+ $provider = $config->getProvider();
+ if (($provider instanceof DoorkeeperRemarkupURIInterface)) {
+ $providers[] = $provider;
+ }
+ }
+
+ if (!$providers) {
+ return;
+ }
+
+ $refs = array();
+ foreach ($hyperlinks as $hyperlink) {
+ $uri = $hyperlink->getURI();
+ $uri = new PhutilURI($uri);
+
+ foreach ($providers as $provider) {
+ $ref = $provider->getDoorkeeperURIRef($uri);
+
+ if (($ref !== null) && !($ref instanceof DoorkeeperURIRef)) {
+ throw new Exception(
+ pht(
+ 'Expected "getDoorkeeperURIRef()" to return "null" or an '.
+ 'object of type "DoorkeeperURIRef", but got %s from provider '.
+ '"%s".',
+ phutil_describe_type($ref),
+ get_class($provider)));
+ }
+
+ if ($ref === null) {
+ continue;
+ }
+
+ $tag_id = celerity_generate_unique_node_id();
+ $href = phutil_string_cast($ref->getURI());
+
+ $refs[] = array(
+ 'id' => $tag_id,
+ 'href' => $href,
+ 'ref' => array(
+ $ref->getApplicationType(),
+ $ref->getApplicationDomain(),
+ $ref->getObjectType(),
+ $ref->getObjectID(),
+ ),
+ 'view' => $ref->getDisplayMode(),
+ );
+
+ $text = $ref->getText();
+ if ($text === null) {
+ $text = $href;
+ }
+
+ $view = id(new PHUITagView())
+ ->setID($tag_id)
+ ->setName($text)
+ ->setHref($href)
+ ->setType(PHUITagView::TYPE_OBJECT)
+ ->setExternal(true);
+
+ $hyperlink->setResult($view);
+ break;
+ }
+ }
+
+ if ($refs) {
+ Javelin::initBehavior('doorkeeper-tag', array('tags' => $refs));
+ }
+ }
+
+}
diff --git a/src/applications/doorkeeper/interface/DoorkeeperRemarkupURIInterface.php b/src/applications/doorkeeper/interface/DoorkeeperRemarkupURIInterface.php
new file mode 100644
--- /dev/null
+++ b/src/applications/doorkeeper/interface/DoorkeeperRemarkupURIInterface.php
@@ -0,0 +1,7 @@
+<?php
+
+interface DoorkeeperRemarkupURIInterface {
+
+ public function getDoorkeeperURIRef(PhutilURI $uri);
+
+}
diff --git a/src/applications/doorkeeper/remarkup/DoorkeeperAsanaRemarkupRule.php b/src/applications/doorkeeper/remarkup/DoorkeeperAsanaRemarkupRule.php
deleted file mode 100644
--- a/src/applications/doorkeeper/remarkup/DoorkeeperAsanaRemarkupRule.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-final class DoorkeeperAsanaRemarkupRule
- extends DoorkeeperRemarkupRule {
-
- public function apply($text) {
- return preg_replace_callback(
- '@https://app\\.asana\\.com/0/(\\d+)/(\\d+)@',
- array($this, 'markupAsanaLink'),
- $text);
- }
-
- public function markupAsanaLink($matches) {
- return $this->addDoorkeeperTag(
- array(
- 'href' => $matches[0],
- 'tag' => array(
- 'ref' => array(
- DoorkeeperBridgeAsana::APPTYPE_ASANA,
- DoorkeeperBridgeAsana::APPDOMAIN_ASANA,
- DoorkeeperBridgeAsana::OBJTYPE_TASK,
- $matches[2],
- ),
- 'extra' => array(
- 'asana.context' => $matches[1],
- ),
- ),
- ));
- }
-
-}
diff --git a/src/applications/doorkeeper/remarkup/DoorkeeperJIRARemarkupRule.php b/src/applications/doorkeeper/remarkup/DoorkeeperJIRARemarkupRule.php
deleted file mode 100644
--- a/src/applications/doorkeeper/remarkup/DoorkeeperJIRARemarkupRule.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-final class DoorkeeperJIRARemarkupRule
- extends DoorkeeperRemarkupRule {
-
- public function apply($text) {
- return preg_replace_callback(
- '@(https?://\S+?)/browse/([A-Z]+-[1-9]\d*)@',
- array($this, 'markupJIRALink'),
- $text);
- }
-
- public function markupJIRALink($matches) {
- $match_domain = $matches[1];
- $match_issue = $matches[2];
-
- // TODO: When we support multiple instances, deal with them here.
- $provider = PhabricatorJIRAAuthProvider::getJIRAProvider();
- if (!$provider) {
- return $matches[0];
- }
-
-
- $jira_base = $provider->getJIRABaseURI();
- if ($match_domain != rtrim($jira_base, '/')) {
- return $matches[0];
- }
-
- return $this->addDoorkeeperTag(
- array(
- 'href' => $matches[0],
- 'tag' => array(
- 'ref' => array(
- DoorkeeperBridgeJIRA::APPTYPE_JIRA,
- $provider->getProviderDomain(),
- DoorkeeperBridgeJIRA::OBJTYPE_ISSUE,
- $match_issue,
- ),
- ),
- ));
- }
-
-
-}
diff --git a/src/applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php b/src/applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php
deleted file mode 100644
--- a/src/applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-abstract class DoorkeeperRemarkupRule extends PhutilRemarkupRule {
-
- const KEY_TAGS = 'doorkeeper.tags';
-
- const VIEW_FULL = 'full';
- const VIEW_SHORT = 'short';
-
- public function getPriority() {
- return 350.0;
- }
-
- protected function addDoorkeeperTag(array $spec) {
- PhutilTypeSpec::checkMap(
- $spec,
- array(
- 'href' => 'string',
- 'tag' => 'map<string, wild>',
-
- 'name' => 'optional string',
- 'view' => 'optional string',
- ));
-
- $spec = $spec + array(
- 'view' => self::VIEW_FULL,
- );
-
- $views = array(
- self::VIEW_FULL,
- self::VIEW_SHORT,
- );
- $views = array_fuse($views);
- if (!isset($views[$spec['view']])) {
- throw new Exception(
- pht(
- 'Unsupported Doorkeeper tag view mode "%s". Supported modes are: %s.',
- $spec['view'],
- implode(', ', $views)));
- }
-
- $key = self::KEY_TAGS;
- $engine = $this->getEngine();
- $token = $engine->storeText(get_class($this));
-
- $tags = $engine->getTextMetadata($key, array());
-
- $tags[] = array(
- 'token' => $token,
- ) + $spec + array(
- 'extra' => array(),
- );
-
- $engine->setTextMetadata($key, $tags);
- return $token;
- }
-
- public function didMarkupText() {
- $key = self::KEY_TAGS;
- $engine = $this->getEngine();
- $tags = $engine->getTextMetadata($key, array());
-
- if (!$tags) {
- return;
- }
-
- $refs = array();
- foreach ($tags as $spec) {
- $href = $spec['href'];
- $name = idx($spec, 'name', $href);
-
- $this->assertFlatText($href);
- $this->assertFlatText($name);
-
- if ($this->getEngine()->isTextMode()) {
- $view = "{$name} <{$href}>";
- } else {
- $tag_id = celerity_generate_unique_node_id();
-
- $refs[] = array(
- 'id' => $tag_id,
- 'view' => $spec['view'],
- ) + $spec['tag'];
-
- $view = id(new PHUITagView())
- ->setID($tag_id)
- ->setName($name)
- ->setHref($href)
- ->setType(PHUITagView::TYPE_OBJECT)
- ->setExternal(true);
- }
-
- $engine->overwriteStoredText($spec['token'], $view);
- }
-
- if ($refs) {
- Javelin::initBehavior('doorkeeper-tag', array('tags' => $refs));
- }
-
- $engine->setTextMetadata($key, array());
- }
-
-}

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 15, 3:15 PM (1 w, 23 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7600962
Default Alt Text
D20528.diff (19 KB)

Event Timeline