Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Umbraco.Core/Models/DeliveryApi/ApiContentRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ public ApiContentRoute(string path, ApiContentStartItem startItem)

public string Path { get; }

public string? QueryString { get; set; }

public IApiContentStartItem StartItem { get; }
}
2 changes: 2 additions & 0 deletions src/Umbraco.Core/Models/DeliveryApi/IApiContentRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ public interface IApiContentRoute
{
string Path { get; }

public string? QueryString { get; set; }

IApiContentStartItem StartItem { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private void ReplaceLocalLinks(HtmlDocument doc, IPublishedSnapshot publishedSna
link.GetAttributeValue("href", string.Empty),
route =>
{
link.SetAttributeValue("href", route.Path);
link.SetAttributeValue("href", $"{route.Path}{route.QueryString}");
link.SetAttributeValue("data-start-item-path", route.StartItem.Path);
link.SetAttributeValue("data-start-item-id", route.StartItem.Id.ToString("D"));
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Extensions;

namespace Umbraco.Cms.Infrastructure.DeliveryApi;

Expand Down Expand Up @@ -41,6 +42,7 @@ protected void ReplaceLocalLinks(IPublishedSnapshot publishedSnapshot, string hr
: null;
if (route != null)
{
route.QueryString = match.Groups["query"].Value.NullOrWhiteSpaceAsNull();
handled = true;
handleContentRoute(route);
}
Expand Down Expand Up @@ -79,6 +81,6 @@ protected void ReplaceLocalImages(IPublishedSnapshot publishedSnapshot, string u
handleMediaUrl(_apiMediaUrlProvider.GetUrl(media));
}

[GeneratedRegex("{localLink:(?<udi>umb:.+)}")]
[GeneratedRegex("{localLink:(?<udi>umb:.+)}(?<query>[^\"]*)")]
private static partial Regex LocalLinkRegex();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2269,6 +2269,10 @@ public async Task Validate_OpenApi_Contract()
"type": "string",
"readOnly": true
},
"queryString": {
"type": "string",
"nullable": true
},
"startItem": {
"$ref": "#/components/schemas/IApiContentStartItemModel"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.DeliveryApi;
using Umbraco.Extensions;

namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi;

Expand Down Expand Up @@ -127,12 +128,16 @@ public void ParseElement_DataAttributesDoNotOverwriteExistingAttributes()
Assert.AreEqual("the original something", span.Attributes.First().Value);
}

[Test]
public void ParseElement_CanParseContentLink()

[TestCase(null)]
[TestCase("")]
[TestCase("#some-anchor")]
[TestCase("?something=true")]
public void ParseElement_CanParseContentLink(string? postfix)
{
var parser = CreateRichTextElementParser();

var element = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}\"></a></p>") as RichTextRootElement;
var element = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}{postfix}\"></a></p>") as RichTextRootElement;
Assert.IsNotNull(element);
var link = element.Elements.OfType<RichTextGenericElement>().Single().Elements.Single() as RichTextGenericElement;
Assert.IsNotNull(link);
Expand All @@ -142,6 +147,7 @@ public void ParseElement_CanParseContentLink()
var route = link.Attributes.First().Value as IApiContentRoute;
Assert.IsNotNull(route);
Assert.AreEqual("/some-content-path", route.Path);
Assert.AreEqual(postfix.NullOrWhiteSpaceAsNull(), route.QueryString);
Assert.AreEqual(_contentRootKey, route.StartItem.Id);
Assert.AreEqual("the-root-path", route.StartItem.Path);
}
Expand Down Expand Up @@ -176,6 +182,22 @@ public void ParseElement_CanHandleNonLocalLink()
Assert.AreEqual("https://some.where/else/", link.Attributes.First().Value);
}

[TestCase("#some-anchor")]
[TestCase("?something=true")]
public void ParseElement_CanHandleNonLocalLink_WithPostfix(string postfix)
{
var parser = CreateRichTextElementParser();

var element = parser.Parse($"<p><a href=\"https://some.where/else/{postfix}\"></a></p>") as RichTextRootElement;
Assert.IsNotNull(element);
var link = element.Elements.OfType<RichTextGenericElement>().Single().Elements.Single() as RichTextGenericElement;
Assert.IsNotNull(link);
Assert.AreEqual("a", link.Tag);
Assert.AreEqual(1, link.Attributes.Count);
Assert.AreEqual("href", link.Attributes.First().Key);
Assert.AreEqual($"https://some.where/else/{postfix}", link.Attributes.First().Value);
}

[Test]
public void ParseElement_LinkTextIsWrappedInTextElement()
{
Expand Down Expand Up @@ -465,6 +487,18 @@ public void ParseMarkup_CanParseContentLink()
Assert.IsTrue(result.Contains($"data-start-item-id=\"{_contentRootKey:D}\""));
}

[TestCase("#some-anchor")]
[TestCase("?something=true")]
public void ParseMarkup_CanParseContentLink_WithPostfix(string postfix)
{
var parser = CreateRichTextMarkupParser();

var result = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}{postfix}\"></a></p>");
Assert.IsTrue(result.Contains($"href=\"/some-content-path{postfix}\""));
Assert.IsTrue(result.Contains("data-start-item-path=\"the-root-path\""));
Assert.IsTrue(result.Contains($"data-start-item-id=\"{_contentRootKey:D}\""));
}

[Test]
public void ParseMarkup_CanParseMediaLink()
{
Expand All @@ -485,6 +519,8 @@ public void ParseMarkup_InvalidLocalLinkYieldsEmptyLink(string href)
}

[TestCase("<p><a href=\"https://some.where/else/\"></a></p>")]
[TestCase("<p><a href=\"https://some.where/else/#some-anchor\"></a></p>")]
[TestCase("<p><a href=\"https://some.where/else/?something=true\"></a></p>")]
[TestCase("<p><img src=\"https://some.where/something.png?rmode=max&amp;width=500\"></p>")]
public void ParseMarkup_CanHandleNonLocalReferences(string html)
{
Expand Down
Loading