diff --git a/src/Umbraco.Tests/Integration/GetCultureTests.cs b/src/Umbraco.Tests/Integration/GetCultureTests.cs new file mode 100644 index 0000000000..977e0f313e --- /dev/null +++ b/src/Umbraco.Tests/Integration/GetCultureTests.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq; +using NUnit.Framework; +using umbraco.cms.businesslogic.web; +using Umbraco.Core.Models; +using Umbraco.Tests.Services; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Web.Routing; +using Language = umbraco.cms.businesslogic.language.Language; + +namespace Umbraco.Tests.Integration +{ + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] + [TestFixture, RequiresSTA] + public class GetCultureTests : BaseServiceTest + { + protected override void FreezeResolution() + { + SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper()); + + base.FreezeResolution(); + } + + [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.CreateContentWithIdentity("content", -1, "umbBlah"); + var c2 = contentService.CreateContentWithIdentity("content", c1, "umbBlah"); + var c3 = contentService.CreateContentWithIdentity("content", c1, "umbBlah"); + var c4 = contentService.CreateContentWithIdentity("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", RootContent = c1, Language = l0}); + ServiceContext.DomainService.Save(new UmbracoDomain("domain1.fr") { DomainName = "domain1.fr", RootContent = c1, Language = l1 }); + ServiceContext.DomainService.Save(new UmbracoDomain("*100112") { DomainName = "*100112", RootContent = c3, Language = l2 }); + + var content = c2; + var culture = Web.Models.ContentExtensions.GetCulture(null, + ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService, + content.Id, content.Path, new Uri("http://domain1.com/")); + Assert.AreEqual("en-US", culture.Name); + + content = c2; + culture = Web.Models.ContentExtensions.GetCulture(null, + ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService, + content.Id, content.Path, new Uri("http://domain1.fr/")); + Assert.AreEqual("fr-FR", culture.Name); + + content = c4; + culture = Web.Models.ContentExtensions.GetCulture(null, + ServiceContext.DomainService, ServiceContext.LocalizationService, ServiceContext.ContentService, + content.Id, content.Path, new Uri("http://domain1.fr/")); + Assert.AreEqual("de-DE", culture.Name); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index 0cfd4a8b24..b6dfbd3584 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -13,31 +13,98 @@ using System.Configuration; namespace Umbraco.Tests.Routing { [TestFixture] - class DomainsAndCulturesTests : UrlRoutingTestBase + internal class DomainsAndCulturesTests : UrlRoutingTestBase { - void SetDomains1() + protected override void FreezeResolution() + { + SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper()); + + base.FreezeResolution(); + } + + private void SetDomains1() { SetupDomainServiceMock(new[] { - new UmbracoDomain("domain1.com/") {Id = 1, Language = new Language("de-DE"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001}}, - new UmbracoDomain("domain1.com/en") {Id = 1, Language = new Language("en-US"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10011}}, - new UmbracoDomain("domain1.com/fr") {Id = 1, Language = new Language("fr-FR"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10012}} + new UmbracoDomain("domain1.com/") + { + Id = 1, + Language = new Language("de-DE"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001} + }, + new UmbracoDomain("domain1.com/en") + { + Id = 1, + Language = new Language("en-US"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10011} + }, + new UmbracoDomain("domain1.com/fr") + { + Id = 1, + Language = new Language("fr-FR"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10012} + } }); } - void SetDomains2() + private void SetDomains2() { SetupDomainServiceMock(new[] { - new UmbracoDomain("domain1.com/") {Id = 1, Language = new Language("de-DE"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001}}, - new UmbracoDomain("domain1.com/en") {Id = 1, Language = new Language("en-US"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10011}}, - new UmbracoDomain("domain1.com/fr") {Id = 1, Language = new Language("fr-FR"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10012}}, - new UmbracoDomain("*1001") {Id = 1, Language = new Language("de-DE"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001}}, - new UmbracoDomain("*10011") {Id = 1, Language = new Language("cs-CZ"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10011}}, - new UmbracoDomain("*100112") {Id = 1, Language = new Language("nl-NL"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 100112}}, - new UmbracoDomain("*1001122") {Id = 1, Language = new Language("da-DK"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001122}}, - new UmbracoDomain("*10012") {Id = 1, Language = new Language("nl-NL"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10012}}, - new UmbracoDomain("*10031") {Id = 1, Language = new Language("nl-NL"), RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10031}} + new UmbracoDomain("domain1.com/") + { + Id = 1, + Language = new Language("de-DE"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001} + }, + new UmbracoDomain("domain1.com/en") + { + Id = 1, + Language = new Language("en-US"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10011} + }, + new UmbracoDomain("domain1.com/fr") + { + Id = 1, + Language = new Language("fr-FR"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10012} + }, + new UmbracoDomain("*1001") + { + Id = 1, + Language = new Language("de-DE"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001} + }, + new UmbracoDomain("*10011") + { + Id = 1, + Language = new Language("cs-CZ"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10011} + }, + new UmbracoDomain("*100112") + { + Id = 1, + Language = new Language("nl-NL"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 100112} + }, + new UmbracoDomain("*1001122") + { + Id = 1, + Language = new Language("da-DK"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001122} + }, + new UmbracoDomain("*10012") + { + Id = 1, + Language = new Language("nl-NL"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10012} + }, + new UmbracoDomain("*10031") + { + Id = 1, + Language = new Language("nl-NL"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 10031} + } }); } @@ -49,82 +116,129 @@ namespace Umbraco.Tests.Routing ]> - + - + This is some content]]> - + - + - + - + - + This is some content]]> - + - + - + - + - + - + - + - + This is some content]]> - + - + - + - + - + This is some content]]> - + - + - + - + - + "; @@ -144,7 +258,8 @@ namespace Umbraco.Tests.Routing SetDomains1(); var routingContext = GetRoutingContext(inputUrl); - var url = routingContext.UmbracoContext.CleanedUmbracoUrl; //very important to use the cleaned up umbraco url + var url = routingContext.UmbracoContext.CleanedUmbracoUrl; + //very important to use the cleaned up umbraco url var pcr = new PublishedContentRequest(url, routingContext); // lookup domain @@ -152,7 +267,7 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(expectedCulture, pcr.Culture.Name); - SettingsForTests.HideTopLevelNodeFromPath = false; + SettingsForTests.HideTopLevelNodeFromPath = false; var finder = new ContentFinderByNiceUrl(); var result = finder.TryFindContent(pcr); @@ -191,7 +306,8 @@ namespace Umbraco.Tests.Routing expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; var routingContext = GetRoutingContext(inputUrl); - var url = routingContext.UmbracoContext.CleanedUmbracoUrl; //very important to use the cleaned up umbraco url + var url = routingContext.UmbracoContext.CleanedUmbracoUrl; + //very important to use the cleaned up umbraco url var pcr = new PublishedContentRequest(url, routingContext); // lookup domain @@ -209,5 +325,46 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(expectedCulture, pcr.Culture.Name); Assert.AreEqual(pcr.PublishedContent.Id, expectedNode); } + + #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, + Language = new Language("en-US"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001} + }, + new UmbracoDomain("domain1.fr/") + { + Id = 1, + Language = new Language("fr-FR"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 1001} + }, + new UmbracoDomain("*100112") + { + Id = 1, + Language = new Language("de-DE"), + RootContent = new Content("test1", -1, new ContentType(-1)) {Id = 100112} + } + }); + + var routingContext = GetRoutingContext("http://anything/"); + var umbracoContext = routingContext.UmbracoContext; + + var content = umbracoContext.ContentCache.GetById(nodeId); + Assert.IsNotNull(content); + + var culture = Web.Models.ContentExtensions.GetCulture(umbracoContext, domainService, null, null, content.Id, content.Path, new Uri(currentUrl)); + Assert.AreEqual(expectedCulture, culture.Name); + } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs index 295bb695e5..5802e023f0 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Routing /// Sets up the mock domain service /// /// - protected void SetupDomainServiceMock(IEnumerable allDomains) + protected IDomainService SetupDomainServiceMock(IEnumerable allDomains) { var domainService = Mock.Get(ServiceContext.DomainService); //setup mock domain service @@ -29,6 +29,7 @@ namespace Umbraco.Tests.Routing .Returns((bool incWildcards) => incWildcards ? allDomains : allDomains.Where(d => d.IsWildcard == false)); domainService.Setup(service => service.GetAssignedDomains(It.IsAny(), It.IsAny())) .Returns((int id, bool incWildcards) => allDomains.Where(d => d.RootContent.Id == id && (incWildcards || d.IsWildcard == false))); + return domainService.Object; } protected ServiceContext GetServiceContext(IUmbracoSettingsSection umbracoSettings, ILogger logger) diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 43a81fb76a..0dce9281ef 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -174,6 +174,7 @@ + diff --git a/src/Umbraco.Web/Models/ContentExtensions.cs b/src/Umbraco.Web/Models/ContentExtensions.cs index 97aff5e2d3..977f8eaf0b 100644 --- a/src/Umbraco.Web/Models/ContentExtensions.cs +++ b/src/Umbraco.Web/Models/ContentExtensions.cs @@ -20,7 +20,9 @@ namespace Umbraco.Web.Models public static CultureInfo GetCulture(this IContent content, Uri current = null) { return GetCulture(UmbracoContext.Current, - ApplicationContext.Current.Services.DomainService, ApplicationContext.Current.Services.LocalizationService, + ApplicationContext.Current.Services.DomainService, + ApplicationContext.Current.Services.LocalizationService, + ApplicationContext.Current.Services.ContentService, content.Id, content.Path, current); } @@ -32,32 +34,64 @@ namespace Umbraco.Web.Models /// An instance. /// An implementation. /// An implementation. + /// An implementation. /// The content identifier. /// The content path. /// The request Uri. /// The culture that would be selected to render the content. - internal static CultureInfo GetCulture(UmbracoContext umbracoContext, IDomainService domainService, ILocalizationService localizationService, + internal static CultureInfo GetCulture(UmbracoContext umbracoContext, + IDomainService domainService, ILocalizationService localizationService, IContentService contentService, int contentId, string contentPath, Uri current) { - var route = umbracoContext.ContentCache.GetRouteById(contentId); // cached - var pos = route.IndexOf('/'); + var route = umbracoContext == null + ? null // for tests only + : umbracoContext.ContentCache.GetRouteById(contentId); // cached var domainHelper = new DomainHelper(domainService); + IDomain domain; - var domain = pos == 0 - ? null - : domainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current).UmbracoDomain; + 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?) + + 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(); + hasDomain = content != null && domainHelper.NodeHasDomains(content.Id); + } + + domain = hasDomain ? domainHelper.DomainForNode(content.Id, current).UmbracoDomain : null; + } + else + { + // if content is published then we have a (cached) 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).UmbracoDomain; + } if (domain == null) - { - var defaultLanguage = localizationService.GetAllLanguages().FirstOrDefault(); - return defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); - } + return GetDefaultCulture(localizationService); var wcDomain = DomainHelper.FindWildcardDomainInPath(domainService.GetAll(true), contentPath, domain.RootContent.Id); return wcDomain == null ? new CultureInfo(domain.Language.IsoCode) : new CultureInfo(wcDomain.Language.IsoCode); } + + private static CultureInfo GetDefaultCulture(ILocalizationService localizationService) + { + var defaultLanguage = localizationService.GetAllLanguages().FirstOrDefault(); + return defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); + } } } diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 7302913d34..a735df88f9 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -1898,7 +1898,9 @@ namespace Umbraco.Web public static CultureInfo GetCulture(this IPublishedContent content, Uri current = null) { return Models.ContentExtensions.GetCulture(UmbracoContext.Current, - ApplicationContext.Current.Services.DomainService, ApplicationContext.Current.Services.LocalizationService, + ApplicationContext.Current.Services.DomainService, + ApplicationContext.Current.Services.LocalizationService, + ApplicationContext.Current.Services.ContentService, content.Id, content.Path, current); }