mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-20 10:48:40 +01:00
Implement #yoloswag
Summary: Ref T3190. #shipit Likely future work: - Extract project mentions from remarkup for ApplicationTransactions; this isn't relevant in any apps right now (but will be in Pholio before tooo long). Ref T3189. - Allow projects to have alternate short names. As written, this is fine for most projects ("Differential" is `#differential`) but not so great for other projects ("Phabricator Public & Media Relations" is `#phabricator_public_media_relations`). This also breaks refs when you rename a project. Better would be letting long project names have short aliases (`#pr`) as permitted alternatives. Since this mention uses `#` instead of a letter, I needed to do a small amount of regexp gymnastics. Test Plan: you only #yolo once {F43615} Reviewers: btrahan, chad Reviewed By: btrahan CC: aran Maniphest Tasks: T3189, T3190 Differential Revision: https://secure.phabricator.com/D5954
This commit is contained in:
parent
0ade49fbe4
commit
79fa8e40cb
4 changed files with 71 additions and 1 deletions
|
@ -1714,6 +1714,7 @@ phutil_register_library_map(array(
|
||||||
'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php',
|
'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php',
|
||||||
'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php',
|
'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php',
|
||||||
'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php',
|
'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php',
|
||||||
|
'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php',
|
||||||
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
|
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
|
||||||
'ReleephActiveProjectListView' => 'applications/releeph/view/project/list/ReleephActiveProjectListView.php',
|
'ReleephActiveProjectListView' => 'applications/releeph/view/project/list/ReleephActiveProjectListView.php',
|
||||||
'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php',
|
'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php',
|
||||||
|
@ -3504,6 +3505,7 @@ phutil_register_library_map(array(
|
||||||
'PonderVotableView' => 'AphrontView',
|
'PonderVotableView' => 'AphrontView',
|
||||||
'PonderVoteEditor' => 'PhabricatorEditor',
|
'PonderVoteEditor' => 'PhabricatorEditor',
|
||||||
'PonderVoteSaveController' => 'PonderController',
|
'PonderVoteSaveController' => 'PonderController',
|
||||||
|
'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
||||||
'QueryFormattingTestCase' => 'PhabricatorTestCase',
|
'QueryFormattingTestCase' => 'PhabricatorTestCase',
|
||||||
'ReleephActiveProjectListView' => 'AphrontView',
|
'ReleephActiveProjectListView' => 'AphrontView',
|
||||||
'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification',
|
'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification',
|
||||||
|
|
|
@ -26,6 +26,12 @@ final class PhabricatorApplicationProject extends PhabricatorApplication {
|
||||||
return self::GROUP_ORGANIZATION;
|
return self::GROUP_ORGANIZATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRemarkupRules() {
|
||||||
|
return array(
|
||||||
|
new ProjectRemarkupRule(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
'/project/' => array(
|
'/project/' => array(
|
||||||
|
|
50
src/applications/project/remarkup/ProjectRemarkupRule.php
Normal file
50
src/applications/project/remarkup/ProjectRemarkupRule.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group project
|
||||||
|
*/
|
||||||
|
final class ProjectRemarkupRule
|
||||||
|
extends PhabricatorRemarkupRuleObject {
|
||||||
|
|
||||||
|
protected function getObjectNamePrefix() {
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectIDPattern() {
|
||||||
|
// NOTE: This explicitly does not match strings which contain only
|
||||||
|
// digits, because digit strings like "#123" are used to reference tasks at
|
||||||
|
// Facebook and are somewhat conventional in general.
|
||||||
|
return '[^\s.!,:;]*[^\s\d.!,:;]+[^\s.!,:;]*';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadObjects(array $ids) {
|
||||||
|
$viewer = $this->getEngine()->getConfig('viewer');
|
||||||
|
|
||||||
|
// If the user types "#YoloSwag", we still want to match "#yoloswag", so
|
||||||
|
// we normalize, query, and then map back to the original inputs.
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($ids as $key => $slug) {
|
||||||
|
$map[PhabricatorSlug::normalize($slug)][] = $slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
$projects = id(new PhabricatorProjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPhrictionSlugs(array_keys($map))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach ($projects as $project) {
|
||||||
|
$slugs = array($project->getPhrictionSlug());
|
||||||
|
foreach ($slugs as $slug) {
|
||||||
|
foreach ($map[$slug] as $original) {
|
||||||
|
$result[$original] = $project;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -99,11 +99,23 @@ abstract class PhabricatorRemarkupRuleObject
|
||||||
array($this, 'markupObjectEmbed'),
|
array($this, 'markupObjectEmbed'),
|
||||||
$text);
|
$text);
|
||||||
|
|
||||||
|
// If the prefix starts with a word character (like "D"), we want to
|
||||||
|
// require a word boundary so that we don't match "XD1" as "D1". If the
|
||||||
|
// prefix does not start with a word character, we want to require no word
|
||||||
|
// boundary for the same reasons. Test if the prefix starts with a word
|
||||||
|
// character.
|
||||||
|
if (preg_match('/^\w/', $prefix)) {
|
||||||
|
$boundary = '\\b';
|
||||||
|
} else {
|
||||||
|
$boundary = '\\B';
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: The "(?<!#)" prevents us from linking "#abcdef" or similar. The
|
// NOTE: The "(?<!#)" prevents us from linking "#abcdef" or similar. The
|
||||||
// "\b" allows us to link "(abcdef)" or similar without linking things
|
// "\b" allows us to link "(abcdef)" or similar without linking things
|
||||||
// in the middle of words.
|
// in the middle of words.
|
||||||
|
|
||||||
$text = preg_replace_callback(
|
$text = preg_replace_callback(
|
||||||
'@(?<!#)\b'.$prefix.'('.$id.')(?:#([-\w\d]+))?\b@',
|
'((?<!#)'.$boundary.$prefix.'('.$id.')(?:#([-\w\d]+))?\b)',
|
||||||
array($this, 'markupObjectReference'),
|
array($this, 'markupObjectReference'),
|
||||||
$text);
|
$text);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue