Prepare Diffusion for hovercards
Summary:
Move Diffusion to be hovercard-ready, and expand our ability to resolve commit references.
  - Link unqualified hashes of 7 characters or more which match a commit.
  - Link qualified hashes of 5 characters or more which match a commit.
  - Support `{...}` syntax.
Test Plan: {F33896}
Reviewers: chad, vrana
Reviewed By: vrana
CC: aran
Differential Revision: https://secure.phabricator.com/D5121
			
			
This commit is contained in:
		
							
								
								
									
										5
									
								
								resources/sql/patches/20130226.commitkey.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								resources/sql/patches/20130226.commitkey.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | ALTER TABLE {$NAMESPACE}_repository.repository_commit | ||||||
|  |   DROP KEY `repositoryID`; | ||||||
|  |  | ||||||
|  | ALTER TABLE {$NAMESPACE}_repository.repository_commit | ||||||
|  |   ADD UNIQUE KEY `key_commit_identity` (commitIdentifier, repositoryID); | ||||||
| @@ -374,6 +374,7 @@ phutil_register_library_map(array( | |||||||
|     'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php', |     'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php', | ||||||
|     'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', |     'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', | ||||||
|     'DiffusionCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionCommitParentsQuery.php', |     'DiffusionCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionCommitParentsQuery.php', | ||||||
|  |     'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php', | ||||||
|     'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', |     'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', | ||||||
|     'DiffusionCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionCommitTagsQuery.php', |     'DiffusionCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionCommitTagsQuery.php', | ||||||
|     'DiffusionContainsQuery' => 'applications/diffusion/query/contains/DiffusionContainsQuery.php', |     'DiffusionContainsQuery' => 'applications/diffusion/query/contains/DiffusionContainsQuery.php', | ||||||
| @@ -1186,7 +1187,6 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorRemarkupRuleMeme' => 'applications/macro/remarkup/PhabricatorRemarkupRuleMeme.php', |     'PhabricatorRemarkupRuleMeme' => 'applications/macro/remarkup/PhabricatorRemarkupRuleMeme.php', | ||||||
|     'PhabricatorRemarkupRuleMention' => 'applications/people/remarkup/PhabricatorRemarkupRuleMention.php', |     'PhabricatorRemarkupRuleMention' => 'applications/people/remarkup/PhabricatorRemarkupRuleMention.php', | ||||||
|     'PhabricatorRemarkupRuleObject' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php', |     'PhabricatorRemarkupRuleObject' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php', | ||||||
|     'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObjectName.php', |  | ||||||
|     'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php', |     'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php', | ||||||
|     'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', |     'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', | ||||||
|     'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php', |     'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php', | ||||||
| @@ -1898,6 +1898,7 @@ phutil_register_library_map(array( | |||||||
|     'DiffusionCommitController' => 'DiffusionController', |     'DiffusionCommitController' => 'DiffusionController', | ||||||
|     'DiffusionCommitEditController' => 'DiffusionController', |     'DiffusionCommitEditController' => 'DiffusionController', | ||||||
|     'DiffusionCommitParentsQuery' => 'DiffusionQuery', |     'DiffusionCommitParentsQuery' => 'DiffusionQuery', | ||||||
|  |     'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', | ||||||
|     'DiffusionCommitTagsController' => 'DiffusionController', |     'DiffusionCommitTagsController' => 'DiffusionController', | ||||||
|     'DiffusionCommitTagsQuery' => 'DiffusionQuery', |     'DiffusionCommitTagsQuery' => 'DiffusionQuery', | ||||||
|     'DiffusionContainsQuery' => 'DiffusionQuery', |     'DiffusionContainsQuery' => 'DiffusionQuery', | ||||||
| @@ -1953,7 +1954,7 @@ phutil_register_library_map(array( | |||||||
|     'DiffusionPathValidateController' => 'DiffusionController', |     'DiffusionPathValidateController' => 'DiffusionController', | ||||||
|     'DiffusionPeopleMenuEventListener' => 'PhutilEventListener', |     'DiffusionPeopleMenuEventListener' => 'PhutilEventListener', | ||||||
|     'DiffusionRawDiffQuery' => 'DiffusionQuery', |     'DiffusionRawDiffQuery' => 'DiffusionQuery', | ||||||
|     'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObjectName', |     'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObject', | ||||||
|     'DiffusionRepositoryController' => 'DiffusionController', |     'DiffusionRepositoryController' => 'DiffusionController', | ||||||
|     'DiffusionSetupException' => 'AphrontUsageException', |     'DiffusionSetupException' => 'AphrontUsageException', | ||||||
|     'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery', |     'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery', | ||||||
| @@ -2661,7 +2662,6 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorRemarkupRuleMeme' => 'PhutilRemarkupRule', |     'PhabricatorRemarkupRuleMeme' => 'PhutilRemarkupRule', | ||||||
|     'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule', |     'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule', | ||||||
|     'PhabricatorRemarkupRuleObject' => 'PhutilRemarkupRule', |     'PhabricatorRemarkupRuleObject' => 'PhutilRemarkupRule', | ||||||
|     'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule', |  | ||||||
|     'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', |     'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', | ||||||
|     'PhabricatorRepository' => |     'PhabricatorRepository' => | ||||||
|     array( |     array( | ||||||
| @@ -2673,7 +2673,11 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', |     'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', | ||||||
|     'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO', |     'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO', | ||||||
|     'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', |     'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', | ||||||
|     'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO', |     'PhabricatorRepositoryCommit' => | ||||||
|  |     array( | ||||||
|  |       0 => 'PhabricatorRepositoryDAO', | ||||||
|  |       1 => 'PhabricatorPolicyInterface', | ||||||
|  |     ), | ||||||
|     'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', |     'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', | ||||||
|     'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', |     'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', | ||||||
|     'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', |     'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', | ||||||
|   | |||||||
| @@ -30,6 +30,12 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public function getRemarkupRules() { | ||||||
|  |     return array( | ||||||
|  |       new DiffusionRemarkupRule(), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   public function getRoutes() { |   public function getRoutes() { | ||||||
|     return array( |     return array( | ||||||
|       '/r(?P<callsign>[A-Z]+)(?P<commit>[a-z0-9]+)' |       '/r(?P<callsign>[A-Z]+)(?P<commit>[a-z0-9]+)' | ||||||
|   | |||||||
							
								
								
									
										140
									
								
								src/applications/diffusion/query/DiffusionCommitQuery.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/applications/diffusion/query/DiffusionCommitQuery.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class DiffusionCommitQuery | ||||||
|  |   extends PhabricatorCursorPagedPolicyAwareQuery { | ||||||
|  |  | ||||||
|  |   private $identifiers; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Load commits by partial or full identifiers, e.g. "rXab82393", "rX1234", | ||||||
|  |    * or "a9caf12". When an identifier matches multiple commits, they will all | ||||||
|  |    * be returned; callers should be prepared to deal with more results than | ||||||
|  |    * they queried for. | ||||||
|  |    */ | ||||||
|  |   public function withIdentifiers(array $identifiers) { | ||||||
|  |     $this->identifiers = $identifiers; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function loadPage() { | ||||||
|  |     $table = new PhabricatorRepositoryCommit(); | ||||||
|  |     $conn_r = $table->establishConnection('r'); | ||||||
|  |  | ||||||
|  |     $data = queryfx_all( | ||||||
|  |       $conn_r, | ||||||
|  |       'SELECT * FROM %T %Q %Q %Q', | ||||||
|  |       $table->getTableName(), | ||||||
|  |       $this->buildWhereClause($conn_r), | ||||||
|  |       $this->buildOrderClause($conn_r), | ||||||
|  |       $this->buildLimitClause($conn_r)); | ||||||
|  |  | ||||||
|  |     return $table->loadAllFromArray($data); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function willFilterPage(array $commits) { | ||||||
|  |     if (!$commits) { | ||||||
|  |       return array(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $repository_ids = mpull($commits, 'getRepositoryID', 'getRepositoryID'); | ||||||
|  |     $repos = id(new PhabricatorRepositoryQuery()) | ||||||
|  |       ->setViewer($this->getViewer()) | ||||||
|  |       ->withIDs($repository_ids) | ||||||
|  |       ->execute(); | ||||||
|  |  | ||||||
|  |     foreach ($commits as $key => $commit) { | ||||||
|  |       $repo = idx($repos, $commit->getRepositoryID()); | ||||||
|  |       if ($repo) { | ||||||
|  |         $commit->attachRepository($repo); | ||||||
|  |       } else { | ||||||
|  |         unset($commits[$key]); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $commits; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private function buildWhereClause(AphrontDatabaseConnection $conn_r) { | ||||||
|  |     $where = array(); | ||||||
|  |  | ||||||
|  |     if ($this->identifiers) { | ||||||
|  |       $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; | ||||||
|  |       $min_qualified   = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; | ||||||
|  |  | ||||||
|  |       $refs = array(); | ||||||
|  |       $bare = array(); | ||||||
|  |       foreach ($this->identifiers as $identifier) { | ||||||
|  |         $matches = null; | ||||||
|  |         preg_match('/^(?:r([A-Z]+))?(.*)$/', $identifier, $matches); | ||||||
|  |         $repo = nonempty($matches[1], null); | ||||||
|  |         $identifier = nonempty($matches[2], null); | ||||||
|  |  | ||||||
|  |         if ($repo === null) { | ||||||
|  |           if (strlen($identifier) < $min_unqualified) { | ||||||
|  |             continue; | ||||||
|  |           } | ||||||
|  |           $bare[] = $identifier; | ||||||
|  |         } else { | ||||||
|  |           $refs[] = array( | ||||||
|  |             'callsign' => $repo, | ||||||
|  |             'identifier' => $identifier, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       $sql = array(); | ||||||
|  |  | ||||||
|  |       foreach ($bare as $identifier) { | ||||||
|  |         $sql[] = qsprintf( | ||||||
|  |           $conn_r, | ||||||
|  |           '(commitIdentifier LIKE %> AND LENGTH(commitIdentifier) = 40)', | ||||||
|  |           $identifier); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if ($refs) { | ||||||
|  |         $callsigns = ipull($refs, 'callsign'); | ||||||
|  |         $repos = id(new PhabricatorRepositoryQuery()) | ||||||
|  |           ->setViewer($this->getViewer()) | ||||||
|  |           ->withCallsigns($callsigns) | ||||||
|  |           ->execute(); | ||||||
|  |         $repos = mpull($repos, null, 'getCallsign'); | ||||||
|  |  | ||||||
|  |         foreach ($refs as $key => $ref) { | ||||||
|  |           $repo = idx($repos, $ref['callsign']); | ||||||
|  |           if (!$repo) { | ||||||
|  |             continue; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           if ($repo->isSVN()) { | ||||||
|  |             $sql[] = qsprintf( | ||||||
|  |               $conn_r, | ||||||
|  |               '(repositoryID = %d AND commitIdentifier = %d)', | ||||||
|  |               $repo->getID(), | ||||||
|  |               $ref['identifier']); | ||||||
|  |           } else { | ||||||
|  |             if (strlen($ref['identifier']) < $min_qualified) { | ||||||
|  |               continue; | ||||||
|  |             } | ||||||
|  |             $sql[] = qsprintf( | ||||||
|  |               $conn_r, | ||||||
|  |               '(repositoryID = %d AND commitIdentifier LIKE %>)', | ||||||
|  |               $repo->getID(), | ||||||
|  |               $ref['identifier']); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if ($sql) { | ||||||
|  |         $where[] = '('.implode(' OR ', $sql).')'; | ||||||
|  |       } else { | ||||||
|  |         // If we discarded all possible identifiers (e.g., they all referenced | ||||||
|  |         // bogus repositories or were all too short), make sure the query finds | ||||||
|  |         // nothing. | ||||||
|  |         $where[] = qsprintf($conn_r, '1 = 0'); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $this->formatWhereClause($where); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,17 +1,79 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @group markup |  | ||||||
|  */ |  | ||||||
| final class DiffusionRemarkupRule | final class DiffusionRemarkupRule | ||||||
|   extends PhabricatorRemarkupRuleObjectName { |   extends PhabricatorRemarkupRuleObject { | ||||||
|  |  | ||||||
|   protected function getObjectNamePrefix() { |   protected function getObjectNamePrefix() { | ||||||
|     return 'r'; |     return ''; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected function getObjectIDPattern() { |   protected function getObjectIDPattern() { | ||||||
|     return '[A-Z]+[a-f0-9]+'; |     $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; | ||||||
|  |     $min_qualified   = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; | ||||||
|  |  | ||||||
|  |     return | ||||||
|  |       '(?:r[A-Z]+)?[0-9]+'. | ||||||
|  |       '|'. | ||||||
|  |       '(?:r[A-Z]+)?[a-f0-9]{'.$min_qualified.',40}'. | ||||||
|  |       '|'. | ||||||
|  |       '[a-f0-9]{'.$min_unqualified.',40}'; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function loadObjects(array $ids) { | ||||||
|  |     $viewer = $this->getEngine()->getConfig('viewer'); | ||||||
|  |     $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; | ||||||
|  |  | ||||||
|  |     if (!$viewer) { | ||||||
|  |       return array(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $commits = id(new DiffusionCommitQuery()) | ||||||
|  |       ->setViewer($viewer) | ||||||
|  |       ->withIdentifiers($ids) | ||||||
|  |       ->execute(); | ||||||
|  |  | ||||||
|  |     if (!$commits) { | ||||||
|  |       return array(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $ids = array_fuse($ids); | ||||||
|  |  | ||||||
|  |     $result = array(); | ||||||
|  |     foreach ($commits as $commit) { | ||||||
|  |       $prefix = 'r'.$commit->getRepository()->getCallsign(); | ||||||
|  |       $suffix = $commit->getCommitIdentifier(); | ||||||
|  |  | ||||||
|  |       if ($commit->getRepository()->isSVN()) { | ||||||
|  |         if (isset($ids[$prefix.$suffix])) { | ||||||
|  |           $result[$prefix.$suffix][] = $commit; | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         // This awkward contruction is so we can link the commits up in O(N) | ||||||
|  |         // time instead of O(N^2). | ||||||
|  |         for ($ii = $min_qualified; $ii <= strlen($suffix); $ii++) { | ||||||
|  |           $part = substr($suffix, 0, $ii); | ||||||
|  |           if (isset($ids[$prefix.$part])) { | ||||||
|  |             $result[$prefix.$part][] = $commit; | ||||||
|  |           } | ||||||
|  |           if (isset($ids[$part])) { | ||||||
|  |             $result[$part][] = $commit; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     foreach ($result as $identifier => $commits) { | ||||||
|  |       if (count($commits) == 1) { | ||||||
|  |         $result[$identifier] = head($commits); | ||||||
|  |       } else { | ||||||
|  |         // This reference is ambiguous -- it matches more than one commit -- so | ||||||
|  |         // don't link it. We could potentially improve this, but it's a bit | ||||||
|  |         // tricky since the superclass expects a single object. | ||||||
|  |         unset($result[$identifier]); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $result; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,16 @@ | |||||||
| final class PhabricatorRepository extends PhabricatorRepositoryDAO | final class PhabricatorRepository extends PhabricatorRepositoryDAO | ||||||
|   implements PhabricatorPolicyInterface { |   implements PhabricatorPolicyInterface { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Shortest hash we'll recognize in raw "a829f32" form. | ||||||
|  |    */ | ||||||
|  |   const MINIMUM_UNQUALIFIED_HASH = 7; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Shortest hash we'll recognize in qualified "rXab7ef2f8" form. | ||||||
|  |    */ | ||||||
|  |   const MINIMUM_QUALIFIED_HASH = 5; | ||||||
|  |  | ||||||
|   const TABLE_PATH = 'repository_path'; |   const TABLE_PATH = 'repository_path'; | ||||||
|   const TABLE_PATHCHANGE = 'repository_pathchange'; |   const TABLE_PATHCHANGE = 'repository_pathchange'; | ||||||
|   const TABLE_FILESYSTEM = 'repository_filesystem'; |   const TABLE_FILESYSTEM = 'repository_filesystem'; | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| final class PhabricatorRepositoryCommit extends PhabricatorRepositoryDAO { | final class PhabricatorRepositoryCommit | ||||||
|  |   extends PhabricatorRepositoryDAO | ||||||
|  |   implements PhabricatorPolicyInterface { | ||||||
|  |  | ||||||
|   protected $repositoryID; |   protected $repositoryID; | ||||||
|   protected $phid; |   protected $phid; | ||||||
| @@ -14,6 +16,19 @@ final class PhabricatorRepositoryCommit extends PhabricatorRepositoryDAO { | |||||||
|   private $commitData; |   private $commitData; | ||||||
|   private $audits; |   private $audits; | ||||||
|   private $isUnparsed; |   private $isUnparsed; | ||||||
|  |   private $repository; | ||||||
|  |  | ||||||
|  |   public function attachRepository(PhabricatorRepository $repository) { | ||||||
|  |     $this->repository = $repository; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getRepository() { | ||||||
|  |     if ($this->repository === null) { | ||||||
|  |       throw new Exception("Call attachRepository() before getRepository()!"); | ||||||
|  |     } | ||||||
|  |     return $this->repository; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   public function setIsUnparsed($is_unparsed) { |   public function setIsUnparsed($is_unparsed) { | ||||||
|     $this->isUnparsed = $is_unparsed; |     $this->isUnparsed = $is_unparsed; | ||||||
| @@ -138,4 +153,22 @@ final class PhabricatorRepositoryCommit extends PhabricatorRepositoryDAO { | |||||||
|  |  | ||||||
|     return $this->setAuditStatus($status); |     return $this->setAuditStatus($status); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* -(  PhabricatorPolicyInterface  )----------------------------------------- */ | ||||||
|  |  | ||||||
|  |   public function getCapabilities() { | ||||||
|  |     return array( | ||||||
|  |       PhabricatorPolicyCapability::CAN_VIEW, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getPolicy($capability) { | ||||||
|  |     return $this->getRepository()->getPolicy($capability); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { | ||||||
|  |     return $this->getRepository()->hasAutomaticCapability($capability, $viewer); | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ final class PhabricatorMarkupEngine { | |||||||
|  |  | ||||||
|   private $objects = array(); |   private $objects = array(); | ||||||
|   private $viewer; |   private $viewer; | ||||||
|   private $version = 4; |   private $version = 5; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* -(  Markup Pipeline  )---------------------------------------------------- */ | /* -(  Markup Pipeline  )---------------------------------------------------- */ | ||||||
| @@ -401,9 +401,6 @@ final class PhabricatorMarkupEngine { | |||||||
|     $rules[] = new PhrictionRemarkupRule(); |     $rules[] = new PhrictionRemarkupRule(); | ||||||
|  |  | ||||||
|     $rules[] = new PhabricatorRemarkupRuleEmbedFile(); |     $rules[] = new PhabricatorRemarkupRuleEmbedFile(); | ||||||
|  |  | ||||||
|     $rules[] = new DiffusionRemarkupRule(); |  | ||||||
|  |  | ||||||
|     $rules[] = new PhabricatorCountdownRemarkupRule(); |     $rules[] = new PhabricatorCountdownRemarkupRule(); | ||||||
|  |  | ||||||
|     $applications = PhabricatorApplication::getAllInstalledApplications(); |     $applications = PhabricatorApplication::getAllInstalledApplications(); | ||||||
|   | |||||||
| @@ -36,9 +36,9 @@ abstract class PhabricatorRemarkupRuleObject | |||||||
|     return $result; |     return $result; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected function renderObjectRef($object, $handle, $anchor) { |   protected function renderObjectRef($object, $handle, $anchor, $id) { | ||||||
|     $href = $handle->getURI(); |     $href = $handle->getURI(); | ||||||
|     $text = $this->getObjectNamePrefix().$object->getID(); |     $text = $this->getObjectNamePrefix().$id; | ||||||
|     if ($anchor) { |     if ($anchor) { | ||||||
|       $matches = null; |       $matches = null; | ||||||
|       if (preg_match('@^#(?:comment-)?(\d{1,7})$@', $anchor, $matches)) { |       if (preg_match('@^#(?:comment-)?(\d{1,7})$@', $anchor, $matches)) { | ||||||
| @@ -172,7 +172,11 @@ abstract class PhabricatorRemarkupRuleObject | |||||||
|       $object = $objects[$spec['id']]; |       $object = $objects[$spec['id']]; | ||||||
|       switch ($spec['type']) { |       switch ($spec['type']) { | ||||||
|         case 'ref': |         case 'ref': | ||||||
|           $view = $this->renderObjectRef($object, $handle, $spec['anchor']); |           $view = $this->renderObjectRef( | ||||||
|  |             $object, | ||||||
|  |             $handle, | ||||||
|  |             $spec['anchor'], | ||||||
|  |             $spec['id']); | ||||||
|           break; |           break; | ||||||
|         case 'embed': |         case 'embed': | ||||||
|           $view = $this->renderObjectEmbed($object, $handle, $spec['options']); |           $view = $this->renderObjectEmbed($object, $handle, $spec['options']); | ||||||
|   | |||||||
| @@ -1,51 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @group markup |  | ||||||
|  */ |  | ||||||
| abstract class PhabricatorRemarkupRuleObjectName |  | ||||||
|   extends PhutilRemarkupRule { |  | ||||||
|  |  | ||||||
|   abstract protected function getObjectNamePrefix(); |  | ||||||
|  |  | ||||||
|   protected function getObjectIDPattern() { |  | ||||||
|     return '[1-9]\d*'; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public function apply($text) { |  | ||||||
|     $prefix = $this->getObjectNamePrefix(); |  | ||||||
|     $id = $this->getObjectIDPattern(); |  | ||||||
|     return preg_replace_callback( |  | ||||||
|       "@\b({$prefix})({$id})(?:#([-\w\d]+))?\b@", |  | ||||||
|       array($this, 'markupObjectNameLink'), |  | ||||||
|       $text); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public function markupObjectNameLink($matches) { |  | ||||||
|     list(, $prefix, $id) = $matches; |  | ||||||
|  |  | ||||||
|     if (isset($matches[3])) { |  | ||||||
|       $href = $matches[3]; |  | ||||||
|       $text = $matches[3]; |  | ||||||
|       if (preg_match('@^(?:comment-)?(\d{1,7})$@', $href, $matches)) { |  | ||||||
|         // Maximum length is 7 because 12345678 could be a file hash. |  | ||||||
|         $href = "comment-{$matches[1]}"; |  | ||||||
|         $text = $matches[1]; |  | ||||||
|       } |  | ||||||
|       $href = "/{$prefix}{$id}#{$href}"; |  | ||||||
|       $text = "{$prefix}{$id}#{$text}"; |  | ||||||
|     } else { |  | ||||||
|       $href = "/{$prefix}{$id}"; |  | ||||||
|       $text = "{$prefix}{$id}"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return $this->getEngine()->storeText( |  | ||||||
|       phutil_tag( |  | ||||||
|         'a', |  | ||||||
|         array( |  | ||||||
|           'href' => $href, |  | ||||||
|         ), |  | ||||||
|         $text)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1153,6 +1153,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList { | |||||||
|         'type'    => 'sql', |         'type'    => 'sql', | ||||||
|         'name'    => $this->getPatchPath('20130222.dropchannel.sql'), |         'name'    => $this->getPatchPath('20130222.dropchannel.sql'), | ||||||
|       ), |       ), | ||||||
|  |       '20130226.commitkey.sql' => array( | ||||||
|  |         'type'    => 'sql', | ||||||
|  |         'name'    => $this->getPatchPath('20130226.commitkey.sql'), | ||||||
|  |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley