fixed slug generation for good now (hopefully)
This commit is contained in:
parent
52ea7a5dfc
commit
b72f47a99f
|
@ -33,11 +33,32 @@ public class ArticleTest {
|
||||||
Assert.That(Article.Slug, Is.EqualTo("article-title-that-is-longer-than-the-sixty-four-character-limit"));
|
Assert.That(Article.Slug, Is.EqualTo("article-title-that-is-longer-than-the-sixty-four-character-limit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SlugFromTitleLongerThan64CharacterWithSpecialCharacterEscapeSize3AtPosition55() {
|
||||||
|
Article.Title = "Auto generating slugs was a mistake I hate this ______ €";
|
||||||
|
Article.UpdateSlug();
|
||||||
|
Assert.That(Article.Slug, Is.EqualTo("auto-generating-slugs-was-a-mistake-i-hate-this-______-%E2%82%AC"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SlugFromTitleLongerThan64CharacterWithSpecialCharacterEscapeSize3AtPosition56() {
|
||||||
|
Article.Title = "Auto generating slugs was a mistake I hate this _______ €";
|
||||||
|
Article.UpdateSlug();
|
||||||
|
Assert.That(Article.Slug, Is.EqualTo("auto-generating-slugs-was-a-mistake-i-hate-this-_______-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SlugFromTitleLongerThan64CharacterWithSpecialCharacterEscapeSize3AtPosition57() {
|
||||||
|
Article.Title = "Auto generating slugs was a mistake I hate this ________ €";
|
||||||
|
Article.UpdateSlug();
|
||||||
|
Assert.That(Article.Slug, Is.EqualTo("auto-generating-slugs-was-a-mistake-i-hate-this-________-"));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SlugFromTitleLongerThan64CharacterWithSpecialCharacterAtPosition61() {
|
public void SlugFromTitleLongerThan64CharacterWithSpecialCharacterAtPosition61() {
|
||||||
Article.Title = "Article that ends with a special character and need special cäre";
|
Article.Title = "Article that ends with a special character and need special cäre";
|
||||||
Article.UpdateSlug();
|
Article.UpdateSlug();
|
||||||
Assert.That(Article.Slug, Is.EqualTo("article-that-ends-with-a-special-character-and-need-special-c%C3"));
|
Assert.That(Article.Slug, Is.EqualTo("article-that-ends-with-a-special-character-and-need-special-c"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using Wave.Utilities;
|
using Wave.Utilities;
|
||||||
|
|
||||||
namespace Wave.Data;
|
namespace Wave.Data;
|
||||||
|
@ -57,13 +58,21 @@ public class Article : ISoftDelete {
|
||||||
string baseSlug = potentialNewSlug ?? Title;
|
string baseSlug = potentialNewSlug ?? Title;
|
||||||
baseSlug = baseSlug.ToLowerInvariant()[..Math.Min(64, baseSlug.Length)];
|
baseSlug = baseSlug.ToLowerInvariant()[..Math.Min(64, baseSlug.Length)];
|
||||||
string slug = Uri.EscapeDataString(baseSlug).Replace("-", "+").Replace("%20", "-");
|
string slug = Uri.EscapeDataString(baseSlug).Replace("-", "+").Replace("%20", "-");
|
||||||
// if our escaping increases the slug length, there is a chance it ends with an escape
|
|
||||||
// character, so if this overshoot is not divisible by 3, then we risk cutting of the
|
// I hate my life
|
||||||
// escape character, so we need to remove it in it's entirely if that's the case
|
|
||||||
int escapeTrimOvershoot = 0;
|
int escapeTrimOvershoot = 0;
|
||||||
if (slug.Length > 64) escapeTrimOvershoot = slug[62..64].Contains('%') ? 1 : 0;
|
if (slug.Length > 64) {
|
||||||
// if the slug already fits 64 character, there will be no cutoff in the next operation anyway,
|
// Escape sequences come with a % and two hex digits, there may be up to 3 of such sequences
|
||||||
// so we don't need to fix what is described in the previous comment
|
// per character escaping ('?' has %3F, but € has %E2%82%AC), so we need to find the last group
|
||||||
|
// of such an escape parade and see if it's going over by less than 9, because then we need to
|
||||||
|
// remove more characters in the truncation, or we end up with a partial escape sequence.. parade
|
||||||
|
escapeTrimOvershoot = 64 - Regex.Match(slug,
|
||||||
|
@"(?<escape>(%[a-fA-F\d][a-fA-F\d])+)",
|
||||||
|
RegexOptions.None | RegexOptions.ExplicitCapture)
|
||||||
|
.Groups.Values.Last(g => g.Index < 64).Index;
|
||||||
|
if (escapeTrimOvershoot > 9) escapeTrimOvershoot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Slug = slug[..Math.Min(slug.Length, 64 - escapeTrimOvershoot)];
|
Slug = slug[..Math.Min(slug.Length, 64 - escapeTrimOvershoot)];
|
||||||
if (Slug.EndsWith("%")) Slug = Slug[..^1];
|
if (Slug.EndsWith("%")) Slug = Slug[..^1];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue