Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14781983
D14261.id34429.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D14261.id34429.diff
View Options
diff --git a/resources/sql/autopatches/20141107.phriction.policy.2.php b/resources/sql/autopatches/20141107.phriction.policy.2.php
--- a/resources/sql/autopatches/20141107.phriction.policy.2.php
+++ b/resources/sql/autopatches/20141107.phriction.policy.2.php
@@ -24,12 +24,14 @@
$prefix = 'projects/';
if (($slug != $prefix) && (strncmp($slug, $prefix, strlen($prefix)) === 0)) {
$parts = explode('/', $slug);
- $project_slug = $parts[1].'/';
+
+ $project_slug = $parts[1];
+ $project_slug = PhabricatorSlug::normalizeProjectSlug($project_slug);
$project_slugs = array($project_slug);
$project = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withPhrictionSlugs($project_slugs)
+ ->withSlugs($project_slugs)
->executeOne();
if ($project) {
diff --git a/resources/sql/patches/090.forceuniqueprojectnames.php b/resources/sql/patches/090.forceuniqueprojectnames.php
--- a/resources/sql/patches/090.forceuniqueprojectnames.php
+++ b/resources/sql/patches/090.forceuniqueprojectnames.php
@@ -10,13 +10,14 @@
$slug_map = array();
foreach ($projects as $project) {
- $project->setPhrictionSlug($project->getName());
- $slug = $project->getPhrictionSlug();
- if ($slug == '/') {
+ $slug = PhabricatorSlug::normalizeProjectSlug($project->getName());
+
+ if (!strlen($slug)) {
$project_id = $project->getID();
echo pht("Project #%d doesn't have a meaningful name...", $project_id)."\n";
$project->setName(trim(pht('Unnamed Project %s', $project->getName())));
}
+
$slug_map[$slug][] = $project->getID();
}
@@ -47,8 +48,8 @@
foreach ($update as $key => $project) {
$id = $project->getID();
$name = $project->getName();
- $project->setPhrictionSlug($name);
- $slug = $project->getPhrictionSlug();
+
+ $slug = PhabricatorSlug::normalizeProjectSlug($name).'/';
echo pht("Updating project #%d '%s' (%s)... ", $id, $name, $slug);
try {
@@ -87,8 +88,8 @@
$suffix = 2;
while (true) {
$new_name = $project->getName().' ('.$suffix.')';
- $project->setPhrictionSlug($new_name);
- $new_slug = $project->getPhrictionSlug();
+
+ $new_slug = PhabricatorSlug::normalizeProjectSlug($new_name).'/';
$okay = true;
foreach ($projects as $other) {
diff --git a/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php b/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
--- a/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
+++ b/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
@@ -112,7 +112,7 @@
$slug_map = array();
if ($slugs) {
foreach ($slugs as $slug) {
- $normal = rtrim(PhabricatorSlug::normalize($slug), '/');
+ $normal = PhabricatorSlug::normalizeProjectSlug($slug);
foreach ($projects as $project) {
if (in_array($normal, $project['slugs'])) {
$slug_map[$slug] = $project['phid'];
diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
--- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
+++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
@@ -81,9 +81,9 @@
switch ($xaction->getTransactionType()) {
case PhabricatorProjectTransaction::TYPE_NAME:
- $object->setName($xaction->getNewValue());
- // TODO - this is really "setPrimarySlug"
- $object->setPhrictionSlug($xaction->getNewValue());
+ $name = $xaction->getNewValue();
+ $object->setName($name);
+ $object->setPrimarySlug(PhabricatorSlug::normalizeProjectSlug($name));
return;
case PhabricatorProjectTransaction::TYPE_SLUGS:
return;
@@ -265,9 +265,8 @@
$errors[] = $error;
}
- $slug_builder = clone $object;
- $slug_builder->setPhrictionSlug($name);
- $slug = $slug_builder->getPrimarySlug();
+ $slug = PhabricatorSlug::normalizeProjectSlug($name);
+
$slug_used_already = id(new PhabricatorProjectSlug())
->loadOneWhere('slug = %s', $slug);
if ($slug_used_already &&
diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php
--- a/src/applications/project/query/PhabricatorProjectQuery.php
+++ b/src/applications/project/query/PhabricatorProjectQuery.php
@@ -7,7 +7,6 @@
private $phids;
private $memberPHIDs;
private $slugs;
- private $phrictionSlugs;
private $names;
private $nameTokens;
private $icons;
@@ -50,11 +49,6 @@
return $this;
}
- public function withPhrictionSlugs(array $slugs) {
- $this->phrictionSlugs = $slugs;
- return $this;
- }
-
public function withNames(array $names) {
$this->names = $names;
return $this;
@@ -308,13 +302,6 @@
$this->slugs);
}
- if ($this->phrictionSlugs !== null) {
- $where[] = qsprintf(
- $conn,
- 'phrictionSlug IN (%Ls)',
- $this->phrictionSlugs);
- }
-
if ($this->names !== null) {
$where[] = qsprintf(
$conn,
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -189,24 +189,11 @@
return $this->assertAttached($this->memberPHIDs);
}
- public function setPhrictionSlug($slug) {
-
- // NOTE: We're doing a little magic here and stripping out '/' so that
- // project pages always appear at top level under projects/ even if the
- // display name is "Hack / Slash" or similar (it will become
- // 'hack_slash' instead of 'hack/slash').
-
- $slug = str_replace('/', ' ', $slug);
- $slug = PhabricatorSlug::normalize($slug);
- $this->phrictionSlug = $slug;
+ public function setPrimarySlug($slug) {
+ $this->phrictionSlug = $slug.'/';
return $this;
}
- public function getFullPhrictionSlug() {
- $slug = $this->getPhrictionSlug();
- return 'projects/'.$slug;
- }
-
// TODO - once we sever project => phriction automagicalness,
// migrate getPhrictionSlug to have no trailing slash and be called
// getPrimarySlug
diff --git a/src/infrastructure/util/PhabricatorSlug.php b/src/infrastructure/util/PhabricatorSlug.php
--- a/src/infrastructure/util/PhabricatorSlug.php
+++ b/src/infrastructure/util/PhabricatorSlug.php
@@ -4,21 +4,54 @@
public static function normalizeProjectSlug($slug) {
$slug = str_replace('/', ' ', $slug);
- $slug = self::normalize($slug);
+ $slug = self::normalize($slug, $hashtag = true);
return rtrim($slug, '/');
}
- public static function normalize($slug) {
+ public static function normalize($slug, $hashtag = false) {
$slug = preg_replace('@/+@', '/', $slug);
$slug = trim($slug, '/');
$slug = phutil_utf8_strtolower($slug);
- $slug = preg_replace("@[\\x00-\\x19#%&+=\\\\?<> ]+@", '_', $slug);
+
+ $ban =
+ // Ban control characters since users can't type them and they create
+ // various other problems with parsing and rendering.
+ "\\x00-\\x19".
+
+ // Ban characters with special meanings in URIs (and spaces), since we
+ // want slugs to produce nice URIs.
+ "#%&+=?".
+ " ".
+
+ // Ban backslashes and various brackets for parsing and URI quality.
+ "\\\\".
+ "<>{}\\[\\]".
+
+ // Ban single and double quotes since they can mess up URIs.
+ "'".
+ '"';
+
+ // In hashtag mode (used for Project hashtags), ban additional characters
+ // which cause parsing problems.
+ if ($hashtag) {
+ $ban .= '`~!@$^*,:;(|)';
+ }
+
+ $slug = preg_replace('(['.$ban.']+)', '_', $slug);
$slug = preg_replace('@_+@', '_', $slug);
+ $parts = explode('/', $slug);
+
+ // Convert "_-_" into "-". This is a little nicer for inputs with
+ // hyphens used as internal separators, and turns an input like "A - B"
+ // into "a-b" instead of "a_-_b";
+ foreach ($parts as $key => $part) {
+ $parts[$key] = str_replace('_-_', '-', $part);
+ }
+
// Remove leading and trailing underscores from each component, if the
// component has not been reduced to a single underscore. For example, "a?"
// converts to "a", but "??" converts to "_".
- $parts = explode('/', $slug);
foreach ($parts as $key => $part) {
if ($part != '_') {
$parts[$key] = trim($part, '_');
diff --git a/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php b/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php
--- a/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php
+++ b/src/infrastructure/util/__tests__/PhabricatorSlugTestCase.php
@@ -34,6 +34,9 @@
'a/??/c' => 'a/_/c/',
'a/?b/c' => 'a/b/c/',
'a/b?/c' => 'a/b/c/',
+ 'a - b' => 'a-b/',
+ 'a[b]' => 'a_b/',
+ 'ab!' => 'ab!/',
);
foreach ($slugs as $slug => $normal) {
@@ -44,6 +47,24 @@
}
}
+ public function testProjectSlugs() {
+ $slugs = array(
+ 'a:b' => 'a_b',
+ 'a!b' => 'a_b',
+ 'a - b' => 'a-b',
+ '' => '',
+ 'Demonology: HSA (Hexes, Signs, Alchemy)' =>
+ 'demonology_hsa_hexes_signs_alchemy',
+ );
+
+ foreach ($slugs as $slug => $normal) {
+ $this->assertEqual(
+ $normal,
+ PhabricatorSlug::normalizeProjectSlug($slug),
+ pht('Hashtag normalization of "%s"', $slug));
+ }
+ }
+
public function testSlugAncestry() {
$slugs = array(
'/' => array(),
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 25, 9:21 AM (12 h, 10 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7042803
Default Alt Text
D14261.id34429.diff (9 KB)
Attached To
Mode
D14261: Improve ruleset for generating project hashtags
Attached
Detach File
Event Timeline
Log In to Comment