Fixes more bugs and outbound routing for additional urls
This commit is contained in:
@@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Integration
|
||||
{
|
||||
[TestFixture]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class GetCultureTests : TestWithSomeContentBase
|
||||
{
|
||||
protected override void Compose()
|
||||
{
|
||||
base.Compose();
|
||||
Container.Register<ISiteDomainHelper, SiteDomainHelper>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCulture()
|
||||
{
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type");
|
||||
contentTypeService.Save(contentType);
|
||||
var contentService = ServiceContext.ContentService;
|
||||
|
||||
var c1 = contentService.CreateAndSave("content", -1, "umbBlah");
|
||||
var c2 = contentService.CreateAndSave("content", c1, "umbBlah");
|
||||
var c3 = contentService.CreateAndSave("content", c1, "umbBlah");
|
||||
var c4 = contentService.CreateAndSave("content", c3, "umbBlah");
|
||||
|
||||
foreach (var l in ServiceContext.LocalizationService.GetAllLanguages().Where(x => x.CultureName != "en-US").ToArray())
|
||||
ServiceContext.LocalizationService.Delete(l);
|
||||
|
||||
var l0 = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-US");
|
||||
var l1 = new Core.Models.Language("fr-FR");
|
||||
var l2 = new Core.Models.Language("de-DE");
|
||||
ServiceContext.LocalizationService.Save(l1);
|
||||
ServiceContext.LocalizationService.Save(l2);
|
||||
|
||||
foreach (var d in ServiceContext.DomainService.GetAll(true).ToArray())
|
||||
ServiceContext.DomainService.Delete(d);
|
||||
|
||||
ServiceContext.DomainService.Save(new UmbracoDomain("domain1.com") {DomainName="domain1.com", RootContentId = c1.Id, LanguageId = l0.Id});
|
||||
ServiceContext.DomainService.Save(new UmbracoDomain("domain1.fr") { DomainName = "domain1.fr", RootContentId = c1.Id, LanguageId = l1.Id });
|
||||
ServiceContext.DomainService.Save(new UmbracoDomain("*100112") { DomainName = "*100112", RootContentId = c3.Id, LanguageId = l2.Id });
|
||||
|
||||
var content = c2;
|
||||
var culture = global::Umbraco.Web.Models.ContentExtensions.GetCulture(null,
|
||||
ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService,
|
||||
new SiteDomainHelper(),
|
||||
content.Id, content.Path, new Uri("http://domain1.com/"));
|
||||
Assert.AreEqual("en-US", culture.Name);
|
||||
|
||||
content = c2;
|
||||
culture = global::Umbraco.Web.Models.ContentExtensions.GetCulture(null,
|
||||
ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService,
|
||||
new SiteDomainHelper(),
|
||||
content.Id, content.Path, new Uri("http://domain1.fr/"));
|
||||
Assert.AreEqual("fr-FR", culture.Name);
|
||||
|
||||
content = c4;
|
||||
culture = global::Umbraco.Web.Models.ContentExtensions.GetCulture(null,
|
||||
ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService,
|
||||
new SiteDomainHelper(),
|
||||
content.Id, content.Path, new Uri("http://domain1.fr/"));
|
||||
Assert.AreEqual("de-DE", culture.Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCultureWithWildcard()
|
||||
{
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type");
|
||||
contentTypeService.Save(contentType);
|
||||
var contentService = ServiceContext.ContentService;
|
||||
|
||||
var c1 = contentService.CreateAndSave("content", -1, "umbBlah");
|
||||
var c2 = contentService.CreateAndSave("content", c1, "umbBlah");
|
||||
var c3 = contentService.CreateAndSave("content", c1, "umbBlah");
|
||||
var c4 = contentService.CreateAndSave("content", c3, "umbBlah");
|
||||
|
||||
foreach (var l in ServiceContext.LocalizationService.GetAllLanguages().Where(x => x.CultureName != "en-US").ToArray())
|
||||
ServiceContext.LocalizationService.Delete(l);
|
||||
|
||||
var l0 = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-US");
|
||||
var l1 = new Core.Models.Language("fr-FR");
|
||||
var l2 = new Core.Models.Language("de-DE");
|
||||
ServiceContext.LocalizationService.Save(l1);
|
||||
ServiceContext.LocalizationService.Save(l2);
|
||||
|
||||
foreach (var d in ServiceContext.DomainService.GetAll(true).ToArray())
|
||||
ServiceContext.DomainService.Delete(d);
|
||||
|
||||
ServiceContext.DomainService.Save(new UmbracoDomain("*0000") { DomainName = "*0000", RootContentId = c1.Id, LanguageId = l2.Id });
|
||||
ServiceContext.DomainService.Save(new UmbracoDomain("*0001") { DomainName = "*0001", RootContentId = c3.Id, LanguageId = l1.Id });
|
||||
//ServiceContext.DomainService.Save(new UmbracoDomain("*100112") { DomainName = "*100112", RootContentId = c3.Id, LanguageId = l2.Id });
|
||||
|
||||
var content = c2;
|
||||
var culture = Umbraco.Web.Models.ContentExtensions.GetCulture(null,
|
||||
ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService,
|
||||
new SiteDomainHelper(),
|
||||
content.Id, content.Path, new Uri("http://domain1.com/"));
|
||||
Assert.AreEqual("de-DE", culture.Name);
|
||||
|
||||
content = c4;
|
||||
culture = Umbraco.Web.Models.ContentExtensions.GetCulture(null,
|
||||
ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService,
|
||||
new SiteDomainHelper(),
|
||||
content.Id, content.Path, new Uri("http://domain1.fr/"));
|
||||
Assert.AreEqual("fr-FR", culture.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,48 +338,6 @@ namespace Umbraco.Tests.Routing
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region Cases
|
||||
[TestCase(10011, "http://domain1.com/", "en-US")]
|
||||
[TestCase(100111, "http://domain1.com/", "en-US")]
|
||||
[TestCase(10011, "http://domain1.fr/", "fr-FR")]
|
||||
[TestCase(100111, "http://domain1.fr/", "fr-FR")]
|
||||
[TestCase(1001121, "http://domain1.fr/", "de-DE")]
|
||||
#endregion
|
||||
public void GetCulture(int nodeId, string currentUrl, string expectedCulture)
|
||||
{
|
||||
var domainService = SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("domain1.com/")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangEngId,
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "en-US"
|
||||
},
|
||||
new UmbracoDomain("domain1.fr/")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangFrId,
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "fr-FR"
|
||||
},
|
||||
new UmbracoDomain("*100112")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangDeId,
|
||||
RootContentId = 100112,
|
||||
LanguageIsoCode = "de-DE"
|
||||
}
|
||||
});
|
||||
|
||||
var umbracoContext = GetUmbracoContext("http://anything/");
|
||||
|
||||
var content = umbracoContext.ContentCache.GetById(nodeId);
|
||||
Assert.IsNotNull(content);
|
||||
|
||||
var culture = global::Umbraco.Web.Models.ContentExtensions.GetCulture(umbracoContext, domainService, ServiceContext.LocalizationService, null, new SiteDomainHelper(), content.Id, content.Path, new Uri(currentUrl));
|
||||
Assert.AreEqual(expectedCulture, culture.Name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,6 @@
|
||||
<Compile Include="Strings\StylesheetHelperTests.cs" />
|
||||
<Compile Include="Strings\StringValidationTests.cs" />
|
||||
<Compile Include="FrontEnd\UmbracoHelperTests.cs" />
|
||||
<Compile Include="Integration\GetCultureTests.cs" />
|
||||
<Compile Include="Membership\MembershipProviderBaseTests.cs" />
|
||||
<Compile Include="Membership\UmbracoServiceMembershipProviderTests.cs" />
|
||||
<Compile Include="Migrations\Stubs\FiveZeroMigration.cs" />
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Routing;
|
||||
using Domain = Umbraco.Web.Routing.Domain;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public static class ContentExtensions
|
||||
{
|
||||
//TODO: Not used
|
||||
///// <summary>
|
||||
///// Gets the culture that would be selected to render a specified content,
|
||||
///// within the context of a specified current request.
|
||||
///// </summary>
|
||||
///// <param name="content">The content.</param>
|
||||
///// <param name="current">The request Uri.</param>
|
||||
///// <returns>The culture that would be selected to render the content.</returns>
|
||||
//public static CultureInfo GetCulture(this IContent content, Uri current = null)
|
||||
//{
|
||||
// return GetCulture(UmbracoContext.Current,
|
||||
// Current.Services.DomainService,
|
||||
// Current.Services.LocalizationService,
|
||||
// Current.Services.ContentService,
|
||||
// content.Id, content.Path,
|
||||
// current);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//TODO: Not used - only in tests
|
||||
/// <summary>
|
||||
/// Gets the culture that would be selected to render a specified content,
|
||||
/// within the context of a specified current request.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">An <see cref="UmbracoContext"/> instance.</param>
|
||||
/// <param name="domainService">An <see cref="IDomainService"/> implementation.</param>
|
||||
/// <param name="localizationService">An <see cref="ILocalizationService"/> implementation.</param>
|
||||
/// <param name="contentService">An <see cref="IContentService"/> implementation.</param>
|
||||
/// <param name="contentId">The content identifier.</param>
|
||||
/// <param name="contentPath">The content path.</param>
|
||||
/// <param name="current">The request Uri.</param>
|
||||
/// <returns>The culture that would be selected to render the content.</returns>
|
||||
internal static CultureInfo GetCulture(UmbracoContext umbracoContext,
|
||||
IDomainService domainService, ILocalizationService localizationService, IContentService contentService,
|
||||
ISiteDomainHelper siteDomainHelper,
|
||||
int contentId, string contentPath, Uri current)
|
||||
{
|
||||
var route = umbracoContext == null
|
||||
? null // for tests only
|
||||
: umbracoContext.ContentCache.GetRouteById(contentId); // may be cached
|
||||
|
||||
var domainCache = umbracoContext == null
|
||||
? new PublishedCache.XmlPublishedCache.DomainCache(domainService, localizationService) // for tests only
|
||||
: umbracoContext.PublishedShapshot.Domains; // default
|
||||
var domainHelper = umbracoContext.GetDomainHelper(siteDomainHelper);
|
||||
Domain domain;
|
||||
|
||||
if (route == null)
|
||||
{
|
||||
// if content is not published then route is null and we have to work
|
||||
// on non-published content (note: could optimize by checking routes?)
|
||||
|
||||
// fixme - even non-published content is stored in the cache or in the cmsContentNu table which would be faster to lookup
|
||||
|
||||
var content = contentService.GetById(contentId);
|
||||
if (content == null)
|
||||
return GetDefaultCulture(localizationService);
|
||||
|
||||
var hasDomain = domainHelper.NodeHasDomains(content.Id);
|
||||
while (hasDomain == false && content != null)
|
||||
{
|
||||
content = content.Parent(contentService);
|
||||
hasDomain = content != null && domainHelper.NodeHasDomains(content.Id);
|
||||
}
|
||||
|
||||
domain = hasDomain ? domainHelper.DomainForNode(content.Id, current) : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if content is published then we have a route
|
||||
// from which we can figure out the domain
|
||||
|
||||
var pos = route.IndexOf('/');
|
||||
domain = pos == 0
|
||||
? null
|
||||
: domainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
}
|
||||
|
||||
var rootContentId = domain == null ? -1 : domain.ContentId;
|
||||
var wcDomain = DomainHelper.FindWildcardDomainInPath(domainCache.GetAll(true), contentPath, rootContentId);
|
||||
|
||||
if (wcDomain != null) return wcDomain.Culture;
|
||||
if (domain != null) return domain.Culture;
|
||||
return GetDefaultCulture(localizationService);
|
||||
}
|
||||
|
||||
private static CultureInfo GetDefaultCulture(ILocalizationService localizationService)
|
||||
{
|
||||
var defaultLanguage = localizationService.GetDefaultVariantLanguage();
|
||||
return defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
if (_cultureNames == null)
|
||||
{
|
||||
var d = new Dictionary<string, PublishedCultureName>();
|
||||
var d = new Dictionary<string, PublishedCultureName>(StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach(var c in _contentData.CultureInfos)
|
||||
{
|
||||
d[c.Key] = new PublishedCultureName(c.Value.Name, c.Value.Name.ToUrlSegment());
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
@@ -90,32 +92,79 @@ namespace Umbraco.Web.Routing
|
||||
/// urls for the node in other contexts (different domain for current request, umbracoUrlAlias...).</para>
|
||||
/// </remarks>
|
||||
public virtual IEnumerable<string> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
|
||||
{
|
||||
// will not use cache if previewing
|
||||
var route = umbracoContext.ContentCache.GetRouteById(id);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(route))
|
||||
{
|
||||
_logger.Debug<DefaultUrlProvider>(() =>
|
||||
$"Couldn't find any page with nodeId={id}. This is most likely caused by the page not being published.");
|
||||
return null;
|
||||
{
|
||||
var node = umbracoContext.ContentCache.GetById(id);
|
||||
var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper);
|
||||
|
||||
//if this is invariant, continue as we used to
|
||||
if (!node.ContentType.Variations.Has(ContentVariation.CultureNeutral))
|
||||
{
|
||||
// will not use cache if previewing
|
||||
var route = umbracoContext.ContentCache.GetRouteById(id);
|
||||
|
||||
return GetOtherUrlsForSinglePath(route, id, domainHelper, current);
|
||||
}
|
||||
else
|
||||
{
|
||||
//this is variant, so we need to find the domains and use the cultures assigned to get the route/paths
|
||||
|
||||
var n = node;
|
||||
var domainUris = domainHelper.DomainsForNode(n.Id, current, false);
|
||||
while (domainUris == null && n != null) // n is null at root
|
||||
{
|
||||
// move to parent node
|
||||
n = n.Parent;
|
||||
domainUris = n == null ? null : domainHelper.DomainsForNode(n.Id, current);
|
||||
}
|
||||
|
||||
if (domainUris == null)
|
||||
{
|
||||
//we can't continue, there are no domains assigned but this is a culture variant node
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
var result = new List<string>();
|
||||
foreach(var d in domainUris)
|
||||
{
|
||||
var route = umbracoContext.ContentCache.GetRouteById(id, d.Culture);
|
||||
if (route == null) continue;
|
||||
|
||||
//need to strip off the leading ID for the route
|
||||
//TODO: Is there a nicer way to deal with this?
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
|
||||
var uri = new Uri(CombinePaths(d.Uri.GetLeftPart(UriPartial.Path), path));
|
||||
uri = UriUtility.UriFromUmbraco(uri, _globalSettings, _requestSettings);
|
||||
result.Add(uri.ToString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper);
|
||||
|
||||
// extract domainUri and path
|
||||
// route is /<path> or <domainRootId>/<path>
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
var domainUris = pos == 0 ? null : domainHelper.DomainsForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
|
||||
// assemble the alternate urls from domainUris (maybe empty) and path
|
||||
return AssembleUrls(domainUris, path).Select(uri => uri.ToString());
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utilities
|
||||
|
||||
private IEnumerable<string> GetOtherUrlsForSinglePath(string route, int id, DomainHelper domainHelper, Uri current)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(route))
|
||||
{
|
||||
_logger.Debug<DefaultUrlProvider>(() =>
|
||||
$"Couldn't find any page with nodeId={id}. This is most likely caused by the page not being published.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// extract domainUri and path
|
||||
// route is /<path> or <domainRootId>/<path>
|
||||
var pos = route.IndexOf('/');
|
||||
var path = pos == 0 ? route : route.Substring(pos);
|
||||
var domainUris = pos == 0 ? null : domainHelper.DomainsForNode(int.Parse(route.Substring(0, pos)), current);
|
||||
|
||||
// assemble the alternate urls from domainUris (maybe empty) and path
|
||||
return AssembleUrls(domainUris, path).Select(uri => uri.ToString());
|
||||
}
|
||||
|
||||
Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlProviderMode mode)
|
||||
{
|
||||
|
||||
@@ -128,7 +128,8 @@ namespace Umbraco.Web.Routing
|
||||
{
|
||||
//get the default domain (there should be one)
|
||||
domainAndUri = domainsAndUris.FirstOrDefault(x => x.IsDefault);
|
||||
if (domainAndUri == null) domainsAndUris.First(); // take the first one by default (what else can we do?)
|
||||
if (domainAndUri == null)
|
||||
domainAndUri = domainsAndUris.First(); // take the first one by default (what else can we do?)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -567,7 +567,6 @@
|
||||
<Compile Include="Models\ContentEditing\Relation.cs" />
|
||||
<Compile Include="HtmlStringUtilities.cs" />
|
||||
<Compile Include="Models\ContentEditing\RelationType.cs" />
|
||||
<Compile Include="Models\ContentExtensions.cs" />
|
||||
<Compile Include="ITagQuery.cs" />
|
||||
<Compile Include="IUmbracoComponentRenderer.cs" />
|
||||
<Compile Include="Models\Mapping\RelationMapperProfile.cs" />
|
||||
|
||||
@@ -481,7 +481,7 @@ namespace umbraco
|
||||
|
||||
if (_cultureNames == null)
|
||||
{
|
||||
var d = new Dictionary<string, PublishedCultureName>();
|
||||
var d = new Dictionary<string, PublishedCultureName>(StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var c in _inner.Names)
|
||||
{
|
||||
d[c.Key] = new PublishedCultureName(c.Value, c.Value.ToUrlSegment());
|
||||
|
||||
Reference in New Issue
Block a user