diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
index 66e63a69d3..f402e2c036 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
@@ -312,16 +312,21 @@ namespace Umbraco.Core.Configuration
get { return "packages.umbraco.org"; }
}
+ static bool? _useDomainPrefixes = null;
+
///
/// Gets a value indicating whether umbraco will use domain prefixes.
///
/// true if umbraco will use domain prefixes; otherwise, false.
+ // TODO rename as EnforceAbsoluteUrls
public static bool UseDomainPrefixes
{
get
{
try
{
+ if (_useDomainPrefixes.HasValue)
+ return _useDomainPrefixes.Value;
bool result;
if (bool.TryParse(GetKey("/settings/requestHandler/useDomainPrefixes"), out result))
return result;
@@ -332,6 +337,11 @@ namespace Umbraco.Core.Configuration
return false;
}
}
+ // for unit tests only
+ internal set
+ {
+ _useDomainPrefixes = value;
+ }
}
static bool? _addTrailingSlash = null;
@@ -365,6 +375,7 @@ namespace Umbraco.Core.Configuration
return false;
}
}
+ // for unit tests only
internal set
{
_addTrailingSlash = value;
diff --git a/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs b/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs
index 59d9ee3e14..5adaa53212 100644
--- a/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs
+++ b/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs
@@ -78,23 +78,6 @@ namespace Umbraco.Tests.Routing
}
}
- //[TestCase(1046, "/home.aspx")]
- //[TestCase(1173, "/home/sub1.aspx")]
- //[TestCase(1174, "/home/sub1/sub2.aspx")]
- //[TestCase(1176, "/home/sub1/sub-3.aspx")]
- //[TestCase(1177, "/home/sub1/custom-sub-1.aspx")]
- //[TestCase(1178, "/home/sub1/custom-sub-2.aspx")]
- //[TestCase(1175, "/home/sub-2.aspx")]
- //[TestCase(1172, "/test-page.aspx")]
- //public void Get_Nice_Url_Not_Hiding_Top_Level_No_Directory_Urls(int nodeId, string niceUrlMatch)
- //{
- // var routingContext = GetRoutingContext("/test", 1111);
-
- // var result = routingContext.NiceUrlProvider.GetNiceUrl(nodeId);
-
- // Assert.AreEqual(niceUrlMatch, result);
- //}
-
// test hideTopLevelNodeFromPath false
[TestCase(1046, "/home")]
[TestCase(1173, "/home/sub1")]
@@ -111,6 +94,7 @@ namespace Umbraco.Tests.Routing
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false");
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
var result = routingContext.NiceUrlProvider.GetNiceUrl(nodeId);
Assert.AreEqual(niceUrlMatch, result);
@@ -118,25 +102,6 @@ namespace Umbraco.Tests.Routing
// no need for umbracoUseDirectoryUrls test = should be handled by UriUtilityTests
- //[TestCase(1046, "/")]
- //[TestCase(1173, "/sub1.aspx")]
- //[TestCase(1174, "/sub1/sub2.aspx")]
- //[TestCase(1176, "/sub1/sub-3.aspx")]
- //[TestCase(1177, "/sub1/custom-sub-1.aspx")]
- //[TestCase(1178, "/sub1/custom-sub-2.aspx")]
- //[TestCase(1175, "/sub-2.aspx")]
- //[TestCase(1172, "/test-page.aspx")]
- //public void Get_Nice_Url_Hiding_Top_Level_No_Directory_Urls(int nodeId, string niceUrlMatch)
- //{
- // var routingContext = GetRoutingContext("/test", 1111);
-
- // ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "true");
-
- // var result = routingContext.NiceUrlProvider.GetNiceUrl(nodeId);
-
- // Assert.AreEqual(niceUrlMatch, result);
- //}
-
// test hideTopLevelNodeFromPath true
[TestCase(1046, "/")]
[TestCase(1173, "/sub1")]
@@ -153,9 +118,46 @@ namespace Umbraco.Tests.Routing
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "true");
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
var result = routingContext.NiceUrlProvider.GetNiceUrl(nodeId);
Assert.AreEqual(niceUrlMatch, result);
}
+
+ [Test]
+ public void Get_Nice_Url_Relative_Or_Absolute()
+ {
+ var routingContext = GetRoutingContext("http://example.com/test", 1111);
+
+ ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
+ ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false");
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
+ Assert.AreEqual("/home/sub1/custom-sub-1", routingContext.NiceUrlProvider.GetNiceUrl(1177));
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = true;
+ Assert.AreEqual("http://example.com/home/sub1/custom-sub-1", routingContext.NiceUrlProvider.GetNiceUrl(1177));
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
+ routingContext.NiceUrlProvider.EnforceAbsoluteUrls = true;
+ Assert.AreEqual("http://example.com/home/sub1/custom-sub-1", routingContext.NiceUrlProvider.GetNiceUrl(1177));
+ }
+
+ [Test]
+ public void Get_Nice_Url_Unpublished()
+ {
+ var routingContext = GetRoutingContext("http://example.com/test", 1111);
+
+ ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
+ ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false");
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
+ Assert.AreEqual("#", routingContext.NiceUrlProvider.GetNiceUrl(999999));
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = true;
+ Assert.AreEqual("#", routingContext.NiceUrlProvider.GetNiceUrl(999999));
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
+ routingContext.NiceUrlProvider.EnforceAbsoluteUrls = true;
+ Assert.AreEqual("#", routingContext.NiceUrlProvider.GetNiceUrl(999999));
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs
index 406e305e68..50434a1ce8 100644
--- a/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs
+++ b/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs
@@ -91,6 +91,22 @@ namespace Umbraco.Tests.Routing
Domain.MakeNew("http://domain3.com/fr", 10032, langFr.id);
}
+ void SetDomains5()
+ {
+ var langEn = Language.GetByCultureCode("en-US");
+ var langFr = Language.GetByCultureCode("fr-FR");
+
+ Domain.MakeNew("http://domain1.com/en", 10011, langEn.id);
+ Domain.MakeNew("http://domain1a.com/en", 10011, langEn.id);
+ Domain.MakeNew("http://domain1b.com/en", 10011, langEn.id);
+ Domain.MakeNew("http://domain1.com/fr", 10012, langFr.id);
+ Domain.MakeNew("http://domain1a.com/fr", 10012, langFr.id);
+ Domain.MakeNew("http://domain1b.com/fr", 10012, langFr.id);
+
+ Domain.MakeNew("http://domain3.com/en", 10031, langEn.id);
+ Domain.MakeNew("http://domain3.com/fr", 10032, langFr.id);
+ }
+
protected override string GetXmlContent(int templateId)
{
return @"
@@ -194,6 +210,7 @@ namespace Umbraco.Tests.Routing
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false"); // ignored w/domains
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
InitializeLanguagesAndDomains();
SetDomains1();
@@ -223,6 +240,7 @@ namespace Umbraco.Tests.Routing
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false"); // ignored w/domains
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
InitializeLanguagesAndDomains();
SetDomains2();
@@ -244,6 +262,7 @@ namespace Umbraco.Tests.Routing
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false"); // ignored w/domains
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
InitializeLanguagesAndDomains();
SetDomains3();
@@ -268,6 +287,7 @@ namespace Umbraco.Tests.Routing
public void Get_Nice_Url_NestedDomains(int nodeId, string currentUrl, bool absolute, string expected)
{
var routingContext = GetRoutingContext("/test", 1111);
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false"); // ignored w/domains
@@ -287,6 +307,7 @@ namespace Umbraco.Tests.Routing
ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false"); // ignored w/domains
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
InitializeLanguagesAndDomains();
SetDomains4();
@@ -337,5 +358,52 @@ namespace Umbraco.Tests.Routing
Assert.IsTrue(ids.ContainsKey(route));
Assert.AreEqual(id, ids[route]);
}
+
+ [Test]
+ public void Get_Nice_Url_Relative_Or_Absolute()
+ {
+ var routingContext = GetRoutingContext("http://domain1.com/test", 1111);
+
+ ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
+ ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false");
+
+ InitializeLanguagesAndDomains();
+ SetDomains4();
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
+ Assert.AreEqual("/en/1001-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100111));
+ Assert.AreEqual("http://domain3.com/en/1003-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100311));
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = true;
+ Assert.AreEqual("http://domain1.com/en/1001-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100111));
+ Assert.AreEqual("http://domain3.com/en/1003-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100311));
+
+ Umbraco.Core.Configuration.UmbracoSettings.UseDomainPrefixes = false;
+ routingContext.NiceUrlProvider.EnforceAbsoluteUrls = true;
+ Assert.AreEqual("http://domain1.com/en/1001-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100111));
+ Assert.AreEqual("http://domain3.com/en/1003-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100311));
+ }
+
+ [Test]
+ public void Get_Nice_Url_Alternate()
+ {
+ var routingContext = GetRoutingContext("http://domain1.com/test", 1111);
+
+ ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", "true");
+ ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", "false");
+
+ InitializeLanguagesAndDomains();
+ SetDomains5();
+
+ var result = routingContext.NiceUrlProvider.GetAllAbsoluteNiceUrls(100111);
+
+ // will always get absolute urls
+ // all of them
+ // including the local one - duplicate?! - then must manually exclude?
+ Assert.AreEqual(3, result.Count());
+ Assert.IsTrue(result.Contains("http://domain1.com/en/1001-1-1"));
+ Assert.IsTrue(result.Contains("http://domain1a.com/en/1001-1-1"));
+ Assert.IsTrue(result.Contains("http://domain1b.com/en/1001-1-1"));
+ }
}
}
diff --git a/src/Umbraco.Tests/UriUtilityTests.cs b/src/Umbraco.Tests/UriUtilityTests.cs
index f01e065e86..46edb5e356 100644
--- a/src/Umbraco.Tests/UriUtilityTests.cs
+++ b/src/Umbraco.Tests/UriUtilityTests.cs
@@ -86,5 +86,37 @@ namespace Umbraco.Tests
{
return new Uri(url, url.StartsWith("http:") ? UriKind.Absolute : UriKind.Relative);
}
+
+ //
+ [TestCase("/", "/", "/")]
+ [TestCase("/", "/foo", "/foo")]
+ [TestCase("/", "~/foo", "/foo")]
+ [TestCase("/vdir", "/", "/vdir/")]
+ [TestCase("/vdir", "/foo", "/vdir/foo")]
+ [TestCase("/vdir", "/foo/", "/vdir/foo/")]
+ [TestCase("/vdir", "~/foo", "/vdir/foo")]
+
+ public void Uri_To_Absolute(string virtualPath, string sourceUrl, string expectedUrl)
+ {
+ UriUtility.SetAppDomainAppVirtualPath(virtualPath);
+ var resultUrl = UriUtility.ToAbsolute(sourceUrl);
+ Assert.AreEqual(expectedUrl, resultUrl);
+ }
+
+ //
+ [TestCase("/", "/", "/")]
+ [TestCase("/", "/foo", "/foo")]
+ [TestCase("/", "/foo/", "/foo/")]
+ [TestCase("/vdir", "/vdir", "/")]
+ [TestCase("/vdir", "/vdir/", "/")]
+ [TestCase("/vdir", "/vdir/foo", "/foo")]
+ [TestCase("/vdir", "/vdir/foo/", "/foo/")]
+
+ public void Url_To_App_Relative(string virtualPath, string sourceUrl, string expectedUrl)
+ {
+ UriUtility.SetAppDomainAppVirtualPath(virtualPath);
+ var resultUrl = UriUtility.ToAppRelative(sourceUrl);
+ Assert.AreEqual(expectedUrl, resultUrl);
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Routing/NiceUrlProvider.cs b/src/Umbraco.Web/Routing/NiceUrlProvider.cs
index efb1a25cf8..94b4717202 100644
--- a/src/Umbraco.Web/Routing/NiceUrlProvider.cs
+++ b/src/Umbraco.Web/Routing/NiceUrlProvider.cs
@@ -18,7 +18,6 @@ namespace Umbraco.Web.Routing
///
internal class NiceUrlProvider
{
-
internal const string NullUrl = "#";
///
@@ -30,37 +29,56 @@ namespace Umbraco.Web.Routing
{
_umbracoContext = umbracoContext;
_publishedContentStore = publishedContentStore;
+ this.EnforceAbsoluteUrls = false;
}
private readonly UmbracoContext _umbracoContext;
private readonly IPublishedContentStore _publishedContentStore;
-
+
+ public bool EnforceAbsoluteUrls { get; set; }
+
#region GetNiceUrl
///
/// Gets the nice url of a node.
///
- /// The node id.
+ /// The node identifier.
/// The nice url for the node.
- /// The url is absolute or relative depending on the current url.
+ /// The url is absolute or relative depending on the current url, settings, and options.
public string GetNiceUrl(int nodeId)
{
- return GetNiceUrl(nodeId, _umbracoContext.UmbracoUrl, false);
+ var absolute = UmbracoSettings.UseDomainPrefixes || this.EnforceAbsoluteUrls;
+ return GetNiceUrl(nodeId, _umbracoContext.UmbracoUrl, absolute);
+ }
+
+ ///
+ /// Gets the nice url of a node.
+ ///
+ /// The node identifier.
+ /// A value indicating whether the url should be absolute in any case.
+ /// The nice url for the node.
+ /// The url is absolute or relative depending on the current url, unless absolute is true, in which case the url is always absolute.
+ public string GetNiceUrl(int nodeId, bool absolute)
+ {
+ return GetNiceUrl(nodeId, _umbracoContext.UmbracoUrl, absolute);
}
///
/// Gets the nice url of a node.
///
/// The node id.
- /// The current url.
+ /// The current absolute url.
/// A value indicating whether the url should be absolute in any case.
/// The nice url for the node.
- /// The url is absolute or relative depending on the current url, unless absolute is true, and then it is always absolute.
+ /// The url is absolute or relative depending on url indicated by current, unless absolute is true, in which case the url is always absolute.
public string GetNiceUrl(int nodeId, Uri current, bool absolute)
{
Uri domainUri;
string path;
+ if (!current.IsAbsoluteUri)
+ throw new ArgumentException("Current url must be absolute.", "current");
+
// do not read cache if previewing
var route = _umbracoContext.InPreviewMode
? null
@@ -105,26 +123,7 @@ namespace Umbraco.Web.Routing
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
if (domainUri == null && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
- {
- // in theory if hideTopLevelNodeFromPath is true, then there should be only once
- // top-level node, or else domains should be assigned. but for backward compatibility
- // we add this check - we look for the document matching "/" and if it's not us, then
- // we do not hide the top level path
- // it has to be taken care of in IPublishedContentStore.GetDocumentByRoute too so if
- // "/foo" fails (looking for "/*/foo") we try also "/foo".
- // this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but
- // that's the way it works pre-4.10 and we try to be backward compat for the time being
- if (node.Parent == null)
- {
- var rootNode = _publishedContentStore.GetDocumentByRoute(_umbracoContext, "/", true);
- if (rootNode.Id == node.Id) // remove only if we're the default node
- pathParts.RemoveAt(pathParts.Count - 1);
- }
- else
- {
- pathParts.RemoveAt(pathParts.Count - 1);
- }
- }
+ ApplyHideTopLevelNodeFromPath(node, pathParts);
// assemble the route
pathParts.Reverse();
@@ -140,6 +139,15 @@ namespace Umbraco.Web.Routing
return AssembleUrl(domainUri, path, current, absolute).ToString();
}
+ #endregion
+
+ #region GetAlternateNiceUrls
+
+ public IEnumerable GetAllAbsoluteNiceUrls(int nodeId)
+ {
+ return GetAlternateNiceUrls(nodeId, _umbracoContext.UmbracoUrl);
+ }
+
///
/// Gets the nice urls of a node.
///
@@ -147,7 +155,7 @@ namespace Umbraco.Web.Routing
/// The current url.
/// An enumeration of all valid urls for the node.
/// The urls are absolute. A node can have more than one url if more than one domain is defined.
- public IEnumerable GetNiceUrls(int nodeId, Uri current)
+ public IEnumerable GetAlternateNiceUrls(int nodeId, Uri current)
{
// this is for editContent.aspx which had its own, highly buggy, implementation of NiceUrl...
//TODO: finalize & test implementation then replace in editContent.aspx
@@ -160,55 +168,77 @@ namespace Umbraco.Web.Routing
? null
: _umbracoContext.RoutesCache.GetRoute(nodeId);
- if (route != null)
+ if (!string.IsNullOrEmpty(route))
{
- // route is / eg "-1/", "-1/foo", "123/", "123/foo/bar"...
+ // there was a route in the cache - extract domainUri and path
+ // route is / or /
int pos = route.IndexOf('/');
- path = route.Substring(pos);
- int id = int.Parse(route.Substring(0, pos)); // will be -1 or 1234
- domainUris = id > 0 ? DomainUrisAtNode(id, current) : new Uri[] { };
+ path = pos == 0 ? route : route.Substring(pos);
+ domainUris = pos == 0 ? new Uri[] { } : DomainUrisAtNode(int.Parse(route.Substring(0, pos)), current);
}
else
{
+ // there was no route in the cache - create a route
var node = _publishedContentStore.GetDocumentById(_umbracoContext, nodeId);
if (node == null)
- return new string[] { NullUrl }; // legacy wrote to the log here...
-
- var pathParts = new List();
- int id = nodeId;
- domainUris = DomainUrisAtNode(id, current);
- while (!domainUris.Any() && id > 0)
{
+ LogHelper.Warn(
+ "Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.",
+ nodeId);
+
+ return new string[] { NullUrl };
+ }
+
+ // walk up from that node until we hit a node with domains,
+ // or we reach the content root, collecting urls in the way
+ var pathParts = new List();
+ var n = node;
+ domainUris = DomainUrisAtNode(n.Id, current);
+ while (!domainUris.Any() && n != null) // n is null at root
+ {
+ // get the url
var urlName = node.UrlName;
pathParts.Add(urlName);
- node = node.Parent; //set to parent node
- id = node.Id;
- domainUris = id > 0 ? DomainUrisAtNode(id, current) : new Uri[] { };
+
+ // move to parent node
+ n = n.Parent;
+ domainUris = n == null ? new Uri[] { } : DomainUrisAtNode(n.Id, current);
}
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
if (!domainUris.Any() && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath)
- pathParts.RemoveAt(pathParts.Count - 1);
+ ApplyHideTopLevelNodeFromPath(node, pathParts);
+ // assemble the route
pathParts.Reverse();
path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc
- route = id.ToString() + path;
+ route = (n == null ? "" : n.Id.ToString()) + path;
+ // do not store if previewing
if (!_umbracoContext.InPreviewMode)
_umbracoContext.RoutesCache.Store(nodeId, route);
}
+ // assemble the alternate urls from domainUris (maybe empty) and path
return AssembleUrls(domainUris, path, current).Select(uri => uri.ToString());
}
+ #endregion
+
+ #region Utilities
+
Uri AssembleUrl(Uri domainUri, string path, Uri current, bool absolute)
{
Uri uri;
if (domainUri == null)
{
- // no domain was found : return a relative url, add vdir if any
- uri = new Uri(SystemDirectories.Root + path, UriKind.Relative);
+ // no domain was found : return an absolute or relative url
+ // handle vdir if any
+ if (!absolute || current == null)
+ uri = new Uri(UriUtility.ToAbsolute(path), UriKind.Relative);
+ else
+ uri = new Uri(current.GetLeftPart(UriPartial.Authority) + UriUtility.ToAbsolute(path));
}
else
{
@@ -229,17 +259,26 @@ namespace Umbraco.Web.Routing
return path == "/" ? path : path.TrimEnd('/');
}
+ // always build absolute urls unless we really cannot
IEnumerable AssembleUrls(IEnumerable domainUris, string path, Uri current)
{
- if (domainUris.Any())
+ List uris = new List();
+ if (!domainUris.Any())
{
- return domainUris.Select(domainUri => new Uri(domainUri.GetLeftPart(UriPartial.Path).TrimEnd('/') + path));
+ // no domain was found : return an absolute or relative url
+ // handle vdir if any
+ if (current == null)
+ uris.Add(new Uri(UriUtility.ToAbsolute(path), UriKind.Relative));
+ else
+ uris.Add(new Uri(current.GetLeftPart(UriPartial.Authority) + UriUtility.ToAbsolute(path)));
}
else
{
- // no domain was found : return a relative url, add vdir if any
- return new Uri[] { new Uri(SystemDirectories.Root + path, UriKind.Relative) };
+ // domains were found : return -- FIXME?
+ uris.AddRange(domainUris.Select(domainUri => new Uri(domainUri.GetLeftPart(UriPartial.Path).TrimEnd('/') + path)));
}
+
+ return uris.Select(uri => UriUtility.UriFromUmbraco(uri));
}
Uri DomainUriAtNode(int nodeId, Uri current)
@@ -263,6 +302,28 @@ namespace Umbraco.Web.Routing
return domainAndUris.Select(d => d.Uri);
}
+ void ApplyHideTopLevelNodeFromPath(Core.Models.IDocument node, List pathParts)
+ {
+ // in theory if hideTopLevelNodeFromPath is true, then there should be only once
+ // top-level node, or else domains should be assigned. but for backward compatibility
+ // we add this check - we look for the document matching "/" and if it's not us, then
+ // we do not hide the top level path
+ // it has to be taken care of in IPublishedContentStore.GetDocumentByRoute too so if
+ // "/foo" fails (looking for "/*/foo") we try also "/foo".
+ // this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but
+ // that's the way it works pre-4.10 and we try to be backward compat for the time being
+ if (node.Parent == null)
+ {
+ var rootNode = _publishedContentStore.GetDocumentByRoute(_umbracoContext, "/", true);
+ if (rootNode.Id == node.Id) // remove only if we're the default node
+ pathParts.RemoveAt(pathParts.Count - 1);
+ }
+ else
+ {
+ pathParts.RemoveAt(pathParts.Count - 1);
+ }
+ }
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs
index 7d96407157..cd3488f14c 100644
--- a/src/Umbraco.Web/UmbracoHelper.cs
+++ b/src/Umbraco.Web/UmbracoHelper.cs
@@ -317,7 +317,7 @@ namespace Umbraco.Web
public string NiceUrlWithDomain(int nodeId)
{
var niceUrlsProvider = UmbracoContext.Current.NiceUrlProvider;
- return niceUrlsProvider.GetNiceUrl(nodeId, UmbracoContext.Current.UmbracoUrl, true);
+ return niceUrlsProvider.GetNiceUrl(nodeId, true);
}
#endregion
diff --git a/src/Umbraco.Web/UriUtility.cs b/src/Umbraco.Web/UriUtility.cs
index 34d7cead12..e411ba3cb5 100644
--- a/src/Umbraco.Web/UriUtility.cs
+++ b/src/Umbraco.Web/UriUtility.cs
@@ -7,47 +7,58 @@ using umbraco;
namespace Umbraco.Web
{
- static class UriUtility
+ public static class UriUtility
{
- static readonly string _appVirtualPath;
- static readonly string _appVirtualPathPrefix;
+ static string _appPath;
+ static string _appPathPrefix;
static UriUtility()
{
- // Virtual path
- _appVirtualPath = HttpRuntime.AppDomainAppVirtualPath ?? "/";
- _appVirtualPathPrefix = _appVirtualPath;
- if (_appVirtualPathPrefix == "/")
- _appVirtualPathPrefix = String.Empty;
+ SetAppDomainAppVirtualPath(HttpRuntime.AppDomainAppVirtualPath);
}
+ // internal for unit testing only
+ internal static void SetAppDomainAppVirtualPath(string appPath)
+ {
+ _appPath = appPath ?? "/";
+ _appPathPrefix = _appPath;
+ if (_appPathPrefix == "/")
+ _appPathPrefix = String.Empty;
+ }
+
// will be "/" or "/foo"
- public static string AppVirtualPath
+ public static string AppPath
{
- get { return _appVirtualPath; }
+ get { return _appPath; }
}
// will be "" or "/foo"
- public static string AppVirtualPathPrefix
+ public static string AppPathPrefix
{
- get { return _appVirtualPathPrefix; }
+ get { return _appPathPrefix; }
}
- public static string ToAbsolute(string url)
+ // adds the virtual directory if any
+ // see also VirtualPathUtility.ToAbsolute
+ // FIXME
+ public static string ToAbsolute(string url)
{
- return ResolveUrl(url);
+ //return ResolveUrl(url);
+ url = url.TrimStart('~');
+ return _appPathPrefix + url;
}
- public static string ToAppRelative(string url)
+ // strips the virtual directory if any
+ // see also VirtualPathUtility.ToAppRelative
+ public static string ToAppRelative(string virtualPath)
{
- if (url.StartsWith(_appVirtualPathPrefix))
- url = url.Substring(_appVirtualPathPrefix.Length);
- return url;
+ if (virtualPath.StartsWith(_appPathPrefix))
+ virtualPath = virtualPath.Substring(_appPathPrefix.Length);
+ return virtualPath;
}
- // fixme - what about vdir?
- // path = path.Substring(UriUtility.AppVirtualPathPrefix.Length); // remove virtual directory
-
+ // maps an internal umbraco uri to a public uri
+ // ie with virtual directory, .aspx if required...
public static Uri UriFromUmbraco(Uri uri)
{
var path = uri.GetSafeAbsolutePath();
@@ -59,19 +70,19 @@ namespace Umbraco.Web
else if (UmbracoSettings.AddTrailingSlash)
path += "/";
+ path = ToAbsolute(path);
+
return uri.Rewrite(path);
}
- ///
- /// Converts a Uri to a path based URI that is lower cased
- ///
- ///
- ///
- public static Uri UriToUmbraco(Uri uri)
+ // maps a public uri to an internal umbraco uri
+ // ie no virtual directory, no .aspx, lowercase...
+ public static Uri UriToUmbraco(Uri uri)
{
var path = uri.GetSafeAbsolutePath();
path = path.ToLower();
+ path = ToAppRelative(path); // strip vdir if any
//we need to check if the path is /default.aspx because this will occur when using a
//web server pre IIS 7 when requesting the root document
@@ -116,7 +127,7 @@ namespace Umbraco.Web
}
StringBuilder sbUrl = new StringBuilder();
- sbUrl.Append(HttpRuntime.AppDomainAppVirtualPath);
+ sbUrl.Append(_appPathPrefix);
if (sbUrl.Length == 0 || sbUrl[sbUrl.Length - 1] != '/') sbUrl.Append('/');
// found question mark already? query string, do not touch!
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs
index 121a585d00..201a02ee02 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs
@@ -20,6 +20,7 @@ using umbraco.cms.businesslogic.web;
using umbraco.presentation;
using umbraco.cms.businesslogic.skinning;
using System.Collections.Generic;
+using System.Linq;
namespace umbraco.cms.presentation
{
@@ -180,7 +181,7 @@ namespace umbraco.cms.presentation
publishProps.addProperty(ui.Text("content", "expireDate", base.getUser()), dpExpire);
// url's
- updateLinks();
+ UpdateNiceUrls();
linkProps.addProperty(ui.Text("content", "urls", base.getUser()), l);
if (domainText.Text != "")
@@ -323,7 +324,7 @@ namespace umbraco.cms.presentation
UnPublish.Visible = true;
_documentHasPublishedVersion = _document.HasPublishedVersion();
- updateLinks();
+ UpdateNiceUrls();
}
else
{
@@ -353,57 +354,36 @@ namespace umbraco.cms.presentation
}
- private void updateLinks()
- {
- if (_documentHasPublishedVersion)
- {
- // zb-00007 #29928 : refactor
- string currentLink = library.NiceUrl(_document.Id);
- l.Text = "" + currentLink + "";
+ void UpdateNiceUrls()
+ {
+ if (!_documentHasPublishedVersion)
+ {
+ l.Text = "" + ui.Text("content", "itemNotPublished", base.getUser()) + "";
+ return;
+ }
- // domains
- domainText.Text = "";
- foreach (string s in _document.Path.Split(','))
- {
- if (int.Parse(s) > -1)
- {
- cms.businesslogic.web.Document dChild = new cms.businesslogic.web.Document(int.Parse(s));
- if (dChild.Published)
- {
- cms.businesslogic.web.Domain[] domains = cms.businesslogic.web.Domain.GetDomainsById(int.Parse(s));
- if (domains.Length > 0)
- {
- for (int i = 0; i < domains.Length; i++)
- {
- string tempLink = "";
- if (library.NiceUrl(int.Parse(s)) == "")
- tempLink = "N/A";
- else if (int.Parse(s) != _document.Id)
- {
- string tempNiceUrl = library.NiceUrl(int.Parse(s));
+ var niceUrlProvider = Umbraco.Web.UmbracoContext.Current.RoutingContext.NiceUrlProvider;
+ var url = niceUrlProvider.GetNiceUrl(_document.Id);
- string niceUrl = tempNiceUrl != "/" ? currentLink.Replace(tempNiceUrl.Replace(".aspx", ""), "") : currentLink;
- if (!niceUrl.StartsWith("/"))
- niceUrl = "/" + niceUrl;
+ if (url == "#")
+ {
+ var parent = _document;
+ while (parent.Published && parent.ParentId > 0)
+ parent = new Document(_document.ParentId);
+ if (parent.Published)
+ l.Text = "" + ui.Text("content", "parentNotPublished", "???", base.getUser()) + "";
+ else
+ l.Text = "" + ui.Text("content", "parentNotPublished", parent.Text, base.getUser()) + "";
+ return;
+ }
- tempLink = "http://" + domains[i].Name + niceUrl;
- }
- else
- tempLink = "http://" + domains[i].Name;
+ l.Text = string.Format("{0}", url);
- domainText.Text += "" + tempLink + "
";
- }
- }
- }
- else
- l.Text = "" + ui.Text("content", "parentNotPublished", dChild.Text, base.getUser()) + "";
- }
- }
-
- }
- else
- l.Text = "" + ui.Text("content", "itemNotPublished", base.getUser()) + "";
- }
+ var lb = new System.Text.StringBuilder();
+ foreach (var altUrl in niceUrlProvider.GetAllAbsoluteNiceUrls(_document.Id).Where(u => u != url))
+ lb.AppendFormat("{0}
", altUrl);
+ domainText.Text = lb.ToString();
+ }
///
/// Clears the page of all controls and shows a simple message. Used if users don't have visible access to the page.