From bcd0c95ec190aab51f93532164f57648ace0b213 Mon Sep 17 00:00:00 2001 From: Stephan Date: Sun, 29 Apr 2018 20:02:38 +0200 Subject: [PATCH] Refactor getting urls --- ...ariationContext.cs => CurrentVariation.cs} | 13 +- .../ICurrentVariationAccessor.cs | 13 ++ .../PublishedContent/IPublishedContent.cs | 41 ++-- .../IPublishedVariationContextAccessor.cs | 13 -- .../PublishedContentWrapped.cs | 3 + .../PublishedContent/PublishedCultureInfos.cs | 13 +- ... ThreadCultureCurrentVariationAccessor.cs} | 10 +- ...> ThreadStaticCurrentVariationAccessor.cs} | 8 +- src/Umbraco.Core/StringExtensions.cs | 3 +- .../Strings/IUrlSegmentProvider.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 8 +- ...edContentOtherTests.cs => NuCacheTests.cs} | 123 ++++------- .../PublishedContentDataTableTests.cs | 7 +- .../PublishedContentExtensionTests.cs | 28 +-- .../SolidPublishedSnapshot.cs | 1 + src/Umbraco.Tests/Routing/UrlProviderTests.cs | 20 +- .../Routing/UrlsProviderWithDomainsTests.cs | 46 ++-- .../Scoping/ScopedNuCacheTests.cs | 2 +- .../TestControllerActivatorBase.cs | 2 +- .../TestHelpers/Stubs/TestPublishedContent.cs | 5 +- .../TestHelpers/TestWithDatabaseBase.cs | 2 +- .../Accessors/TestCurrentVariationAccessor.cs | 17 ++ .../TestPublishedVariationContextAccessor.cs | 17 -- .../Testing/Objects/TestDataSource.cs | 57 +++++ .../Testing/TestingTests/MockTests.cs | 11 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 5 +- .../Web/TemplateUtilitiesTests.cs | 36 ++-- src/Umbraco.Web/Editors/MacroController.cs | 8 +- .../Models/PublishedContentBase.cs | 46 ++-- .../PublishedCache/NuCache/ContentNode.cs | 16 +- .../PublishedCache/NuCache/ContentNodeKit.cs | 4 +- .../PublishedCache/NuCache/ContentStore.cs | 12 +- .../PublishedCache/NuCache/MemberCache.cs | 14 +- .../PublishedCache/NuCache/Property.cs | 2 +- .../NuCache/PublishedContent.cs | 16 +- .../PublishedCache/NuCache/PublishedMember.cs | 8 +- .../NuCache/PublishedSnapshotService.cs | 63 ++---- .../PublishedSnapshotServiceBase.cs | 6 +- .../SystemDefaultCultureAccessor.cs | 4 +- .../PublishedSnapshotService.cs | 12 +- .../XmlPublishedCache/XmlCacheComponent.cs | 2 +- src/Umbraco.Web/Routing/AliasUrlProvider.cs | 29 +-- .../Routing/CustomRouteUrlProvider.cs | 26 +-- src/Umbraco.Web/Routing/DefaultUrlProvider.cs | 29 +-- src/Umbraco.Web/Routing/IUrlProvider.cs | 13 +- src/Umbraco.Web/Routing/UrlProvider.cs | 201 +++++++++--------- .../Runtime/WebRuntimeComponent.cs | 3 +- src/Umbraco.Web/umbraco.presentation/page.cs | 14 +- 48 files changed, 512 insertions(+), 522 deletions(-) rename src/Umbraco.Core/Models/PublishedContent/{PublishedVariationContext.cs => CurrentVariation.cs} (52%) create mode 100644 src/Umbraco.Core/Models/PublishedContent/ICurrentVariationAccessor.cs delete mode 100644 src/Umbraco.Core/Models/PublishedContent/IPublishedVariationContextAccessor.cs rename src/Umbraco.Core/Models/PublishedContent/{ThreadCulturePublishedVariationContextAccessor.cs => ThreadCultureCurrentVariationAccessor.cs} (54%) rename src/Umbraco.Core/Models/PublishedContent/{ThreadStaticPublishedVariationContextAccessor.cs => ThreadStaticCurrentVariationAccessor.cs} (62%) rename src/Umbraco.Tests/PublishedContent/{PublishedContentOtherTests.cs => NuCacheTests.cs} (76%) create mode 100644 src/Umbraco.Tests/Testing/Objects/Accessors/TestCurrentVariationAccessor.cs delete mode 100644 src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedVariationContextAccessor.cs create mode 100644 src/Umbraco.Tests/Testing/Objects/TestDataSource.cs diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedVariationContext.cs b/src/Umbraco.Core/Models/PublishedContent/CurrentVariation.cs similarity index 52% rename from src/Umbraco.Core/Models/PublishedContent/PublishedVariationContext.cs rename to src/Umbraco.Core/Models/PublishedContent/CurrentVariation.cs index 2440b1dc32..f52763ecf0 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedVariationContext.cs +++ b/src/Umbraco.Core/Models/PublishedContent/CurrentVariation.cs @@ -1,17 +1,14 @@ namespace Umbraco.Core.Models.PublishedContent { /// - /// Represents the published variation context. + /// Represents the current variation. /// - /// - /// The published variation context indicates which variation is the current default variation. - /// - public class PublishedVariationContext + public class CurrentVariation { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public PublishedVariationContext(string culture = null, string segment = null) + public CurrentVariation(string culture = null, string segment = null) { Culture = culture; Segment = segment; @@ -27,4 +24,4 @@ /// public string Segment { get; set; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Models/PublishedContent/ICurrentVariationAccessor.cs b/src/Umbraco.Core/Models/PublishedContent/ICurrentVariationAccessor.cs new file mode 100644 index 0000000000..969601f080 --- /dev/null +++ b/src/Umbraco.Core/Models/PublishedContent/ICurrentVariationAccessor.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Core.Models.PublishedContent +{ + /// + /// Gives access to the current . + /// + public interface ICurrentVariationAccessor + { + /// + /// Gets or sets the current . + /// + CurrentVariation CurrentVariation { get; set; } + } +} diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs index e8de7efeda..b3358c4676 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs @@ -31,9 +31,8 @@ namespace Umbraco.Core.Models.PublishedContent /// /// /// The value of this property is contextual. When the content type is multi-lingual, - /// this is the name for the 'current' culture. + /// this is the name for the 'current' culture. Otherwise, it is the invariant name. /// - /// FIXME culture aware - returns the value for the 'current' culture whatever it is + see ?? for others string Name { get; } /// @@ -41,9 +40,8 @@ namespace Umbraco.Core.Models.PublishedContent /// /// /// The value of this property is contextual. When the content type is multi-lingual, - /// this is the name for the 'current' culture. + /// this is the name for the 'current' culture. Otherwise, it is the invariant url segment. /// - /// FIXME rename UrlSegment + culture aware string UrlSegment { get; } /// @@ -96,7 +94,8 @@ namespace Umbraco.Core.Models.PublishedContent /// /// /// For published content items, this is also the date the item was published. - /// This date is global to the content item, see FIXME for per-culture dates + /// This date is always global to the content item, see GetCulture().Date for the + /// date each culture was published. /// DateTime UpdateDate { get; } @@ -104,17 +103,35 @@ namespace Umbraco.Core.Models.PublishedContent /// Gets the url of the content item. /// /// - /// The value of this property is contextual. It depends on the 'current' - /// In addition, when the content type is multi-lingual, this is the url for the - /// 'current' culture. + /// The value of this property is contextual. It depends on the 'current' request uri, + /// if any. In addition, when the content type is multi-lingual, this is the url for the + /// 'current' culture. Otherwise, it is the invariant url. /// - /// FIXME explain what 'current' means here string Url { get; } - // fixme document - //PublishedCultureInfos Culture(string culture = "."); - //string GetName(string culture = "."); // best naming? GetName? CultureName? + /// + /// Gets the url of the content item. + /// + /// + /// The value of this property is contextual. It depends on the 'current' request uri, + /// if any. In addition, when the content type is multi-lingual, this is the url for the + /// specified culture. Otherwise, it is the invariant url. + /// + string GetUrl(string culture = "."); + + /// + /// Gets culture infos for a culture. + /// PublishedCultureInfos GetCulture(string culture = "."); + + /// + /// Gets culture infos. + /// + /// + /// Contains only those culture that are available. For a published content, these are + /// the cultures that are published. For a draft content, those that are 'available' ie + /// have a non-empty content name. + /// IReadOnlyDictionary Cultures { get; } /// diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedVariationContextAccessor.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedVariationContextAccessor.cs deleted file mode 100644 index 2af4230665..0000000000 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedVariationContextAccessor.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Umbraco.Core.Models.PublishedContent -{ - /// - /// Gives access to the current . - /// - public interface IPublishedVariationContextAccessor - { - /// - /// Gets or sets the current . - /// - PublishedVariationContext Context { get; set; } - } -} diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs index 8d4888cf25..51fe3045f7 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs @@ -96,6 +96,9 @@ namespace Umbraco.Core.Models.PublishedContent /// public virtual string Url => _content.Url; + /// + public virtual string GetUrl(string culture = ".") => _content.GetUrl(culture); + /// public PublishedCultureInfos GetCulture(string culture = ".") => _content.GetCulture(culture); diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedCultureInfos.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedCultureInfos.cs index 7a563544a4..2522f0366f 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedCultureInfos.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedCultureInfos.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core.Models.PublishedContent /// /// Initializes a new instance of the class. /// - public PublishedCultureInfos(string culture, string name, bool published, DateTime publishedDate) + public PublishedCultureInfos(string culture, string name, bool published, DateTime date) { if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentNullOrEmptyException(nameof(culture)); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); @@ -20,7 +20,7 @@ namespace Umbraco.Core.Models.PublishedContent Name = name; UrlSegment = name.ToUrlSegment(culture); Published = published; - PublishedDate = publishedDate; + Date = date; } /// @@ -48,8 +48,13 @@ namespace Umbraco.Core.Models.PublishedContent public bool Published { get; } /// - /// Gets the date when fixme? + /// Gets the date associated with the culture. /// - public DateTime PublishedDate { get; } // fixme - model? model.UpdateDate - here? + /// + /// For published culture, this is the date the culture was published. For draft + /// cultures, this is the date the culture was made available, ie the last time its + /// name changed. + /// + public DateTime Date { get; } } } diff --git a/src/Umbraco.Core/Models/PublishedContent/ThreadCulturePublishedVariationContextAccessor.cs b/src/Umbraco.Core/Models/PublishedContent/ThreadCultureCurrentVariationAccessor.cs similarity index 54% rename from src/Umbraco.Core/Models/PublishedContent/ThreadCulturePublishedVariationContextAccessor.cs rename to src/Umbraco.Core/Models/PublishedContent/ThreadCultureCurrentVariationAccessor.cs index 8bf02e3f9b..9883cf9e3f 100644 --- a/src/Umbraco.Core/Models/PublishedContent/ThreadCulturePublishedVariationContextAccessor.cs +++ b/src/Umbraco.Core/Models/PublishedContent/ThreadCultureCurrentVariationAccessor.cs @@ -5,18 +5,18 @@ using System.Threading; namespace Umbraco.Core.Models.PublishedContent { /// - /// Provides a CurrentUICulture-based implementation of . + /// Provides a CurrentUICulture-based implementation of . /// /// /// This accessor does not support segments. There is no need to set the current context. /// - public class ThreadCulturePublishedVariationContextAccessor : IPublishedVariationContextAccessor + public class ThreadCultureCurrentVariationAccessor : ICurrentVariationAccessor { - private readonly ConcurrentDictionary _contexts = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _contexts = new ConcurrentDictionary(); - public PublishedVariationContext Context + public CurrentVariation CurrentVariation { - get => _contexts.GetOrAdd(Thread.CurrentThread.CurrentUICulture.Name, culture => new PublishedVariationContext { Culture = culture }); + get => _contexts.GetOrAdd(Thread.CurrentThread.CurrentUICulture.Name, culture => new CurrentVariation { Culture = culture }); set => throw new NotSupportedException(); } } diff --git a/src/Umbraco.Core/Models/PublishedContent/ThreadStaticPublishedVariationContextAccessor.cs b/src/Umbraco.Core/Models/PublishedContent/ThreadStaticCurrentVariationAccessor.cs similarity index 62% rename from src/Umbraco.Core/Models/PublishedContent/ThreadStaticPublishedVariationContextAccessor.cs rename to src/Umbraco.Core/Models/PublishedContent/ThreadStaticCurrentVariationAccessor.cs index b7391e8b0d..19ec89ff97 100644 --- a/src/Umbraco.Core/Models/PublishedContent/ThreadStaticPublishedVariationContextAccessor.cs +++ b/src/Umbraco.Core/Models/PublishedContent/ThreadStaticCurrentVariationAccessor.cs @@ -3,18 +3,18 @@ namespace Umbraco.Core.Models.PublishedContent { /// - /// Provides a ThreadStatic-based implementation of . + /// Provides a ThreadStatic-based implementation of . /// /// /// Something must set the current context. /// - public class ThreadStaticPublishedVariationContextAccessor : IPublishedVariationContextAccessor + public class ThreadStaticCurrentVariationAccessor : ICurrentVariationAccessor { [ThreadStatic] - private static PublishedVariationContext _context; + private static CurrentVariation _context; /// - public PublishedVariationContext Context + public CurrentVariation CurrentVariation { get => _context; set => _context = value; diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 0a41b3c09e..cded44a7e9 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -1166,7 +1166,8 @@ namespace Umbraco.Core /// The text to filter. /// The culture. /// The safe url segment. - public static string ToUrlSegment(this string text, CultureInfo culture) // fixme obsolete that one, use the string one? + // todo: obsolete that one and use the string one (requires changes to IShortStringHelper) + public static string ToUrlSegment(this string text, CultureInfo culture) { return Current.ShortStringHelper.CleanStringForUrlSegment(text, culture); } diff --git a/src/Umbraco.Core/Strings/IUrlSegmentProvider.cs b/src/Umbraco.Core/Strings/IUrlSegmentProvider.cs index 824ae50aa4..4674361b95 100644 --- a/src/Umbraco.Core/Strings/IUrlSegmentProvider.cs +++ b/src/Umbraco.Core/Strings/IUrlSegmentProvider.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Strings /// /// The content. /// The url segment. - string GetUrlSegment(IContentBase content); + string GetUrlSegment(IContentBase content); // fixme do we need to have both? /// /// Gets the url segment for a specified content and culture. diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 954391c8a6..9284a12cbd 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -369,11 +369,11 @@ - + - - - + + + diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentOtherTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs similarity index 76% rename from src/Umbraco.Tests/PublishedContent/PublishedContentOtherTests.cs rename to src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 3aa1fbf41f..ffdaf71711 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentOtherTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Data; -using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -16,6 +15,7 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing.Objects; using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Cache; @@ -26,14 +26,18 @@ using Umbraco.Web.Routing; namespace Umbraco.Tests.PublishedContent { [TestFixture] - public class PublishedContentOtherTests // FIXME rename! + public class NuCacheTests { [Test] - public void Test() + public void StandaloneVariations() { + // this test implements a full standalone NuCache (based upon a test IDataSource, does not + // use any local db files, does not rely on any database) - and tests variations + SettingsForTests.ConfigureSettings(SettingsForTests.GenerateMockUmbracoSettings()); var globalSettings = UmbracoConfig.For.GlobalSettings(); + // create a content node kit var kit = new ContentNodeKit { ContentTypeId = 2, @@ -66,11 +70,20 @@ namespace Umbraco.Tests.PublishedContent } }; + // create a data source for NuCache var dataSource = new TestDataSource(kit); var runtime = Mock.Of(); Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); + // create data types, property types and content types + var dataType = new DataType(new VoidEditor("Editor", Mock.Of())) { Id = 3 }; + + var dataTypes = new[] + { + dataType + }; + var propertyType = new PropertyType("Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.InvariantNeutral | ContentVariation.CultureNeutral }; var contentType = new ContentType(-1) { Id = 2, Alias = "alias-ct", Variations = ContentVariation.InvariantNeutral | ContentVariation.CultureNeutral }; contentType.AddPropertyType(propertyType); @@ -80,13 +93,6 @@ namespace Umbraco.Tests.PublishedContent contentType }; - var dataType = new DataType(new VoidEditor("Editor", Mock.Of())) { Id = 3 }; - - var dataTypes = new[] - { - dataType - }; - var contentTypeService = Mock.Of(); Mock.Get(contentTypeService).Setup(x => x.GetAll()).Returns(contentTypes); Mock.Get(contentTypeService).Setup(x => x.GetAll(It.IsAny())).Returns(contentTypes); @@ -94,6 +100,7 @@ namespace Umbraco.Tests.PublishedContent var dataTypeService = Mock.Of(); Mock.Get(dataTypeService).Setup(x => x.GetAll()).Returns(dataTypes); + // create a service context var serviceContext = new ServiceContext( dataTypeService : dataTypeService, memberTypeService: Mock.Of(), @@ -102,17 +109,7 @@ namespace Umbraco.Tests.PublishedContent localizationService: Mock.Of() ); - var contentTypeFactory = new PublishedContentTypeFactory( - Mock.Of(), - new PropertyValueConverterCollection(Array.Empty()), - dataTypeService); - - var documentRepository = Mock.Of(); - var mediaRepository = Mock.Of(); - var memberRepository = Mock.Of(); - - var snapshotAccessor = new TestPublishedSnapshotAccessor(); - + // create a scope provider var scopeProvider = Mock.Of(); Mock.Get(scopeProvider) .Setup(x => x.CreateScope( @@ -122,10 +119,18 @@ namespace Umbraco.Tests.PublishedContent It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(() => Mock.Of()); + .Returns(Mock.Of); - var variationAccessor = new TestPublishedVariationContextAccessor(); + // create a published content type factory + var contentTypeFactory = new PublishedContentTypeFactory( + Mock.Of(), + new PropertyValueConverterCollection(Array.Empty()), + dataTypeService); + // create a variation accessor + var variationAccessor = new TestCurrentVariationAccessor(); + + // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true }; var snapshotService = new PublishedSnapshotService(options, null, @@ -133,23 +138,24 @@ namespace Umbraco.Tests.PublishedContent serviceContext, contentTypeFactory, null, - snapshotAccessor, + new TestPublishedSnapshotAccessor(), variationAccessor, Mock.Of(), scopeProvider, - documentRepository, - mediaRepository, - memberRepository, + Mock.Of(), + Mock.Of(), + Mock.Of(), new TestSystemDefaultCultureAccessor(), dataSource, globalSettings, new SiteDomainHelper()); + // get a snapshot, get a published content var snapshot = snapshotService.CreatePublishedSnapshot(previewToken: null); var publishedContent = snapshot.Content.GetById(1); // invariant is the current default - variationAccessor.Context = new PublishedVariationContext(); + variationAccessor.CurrentVariation = new CurrentVariation(); Assert.IsNotNull(publishedContent); Assert.AreEqual("It Works1!", publishedContent.Name); @@ -170,86 +176,39 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual("name-uk2", draftContent.GetCulture("en-UK").Name); // now french is default - variationAccessor.Context = new PublishedVariationContext("fr-FR"); + variationAccessor.CurrentVariation = new CurrentVariation("fr-FR"); Assert.AreEqual("val-fr1", publishedContent.Value("prop")); Assert.AreEqual("name-fr1", publishedContent.GetCulture().Name); Assert.AreEqual("name-fr1", publishedContent.Name); - Assert.AreEqual(new DateTime(2018, 01, 01, 01, 00, 00), publishedContent.GetCulture().PublishedDate); + Assert.AreEqual(new DateTime(2018, 01, 01, 01, 00, 00), publishedContent.GetCulture().Date); // now uk is default - variationAccessor.Context = new PublishedVariationContext("en-UK"); + variationAccessor.CurrentVariation = new CurrentVariation("en-UK"); Assert.AreEqual("val-uk1", publishedContent.Value("prop")); Assert.AreEqual("name-uk1", publishedContent.GetCulture().Name); Assert.AreEqual("name-uk1", publishedContent.Name); - Assert.AreEqual(new DateTime(2018, 01, 02, 01, 00, 00), publishedContent.GetCulture().PublishedDate); + Assert.AreEqual(new DateTime(2018, 01, 02, 01, 00, 00), publishedContent.GetCulture().Date); // invariant needs to be retrieved explicitely, when it's not default Assert.AreEqual("val1", publishedContent.Value("prop", culture: null)); // but, // if the content type / property type does not vary, then it's all invariant again + // modify the content type and property type, notify the snapshot service contentType.Variations = ContentVariation.InvariantNeutral; propertyType.Variations = ContentVariation.InvariantNeutral; snapshotService.Notify(new[] { new ContentTypeCacheRefresher.JsonPayload("IContentType", publishedContent.ContentType.Id, ContentTypeChangeTypes.RefreshMain) }); + // get a new snapshot (nothing changed in the old one), get the published content again var anotherSnapshot = snapshotService.CreatePublishedSnapshot(previewToken: null); var againContent = anotherSnapshot.Content.GetById(1); Assert.AreEqual(ContentVariation.InvariantNeutral, againContent.ContentType.Variations); Assert.AreEqual(ContentVariation.InvariantNeutral, againContent.ContentType.GetPropertyType("prop").Variations); + // now, "no culture" means "invariant" Assert.AreEqual("It Works1!", againContent.Name); Assert.AreEqual("val1", againContent.Value("prop")); - - // then, test fallback - } - - internal class TestDataSource : IDataSource - { - private readonly Dictionary _kits; - - public TestDataSource(params ContentNodeKit[] kits) - : this((IEnumerable) kits) - { } - - public TestDataSource(IEnumerable kits) - { - _kits = kits.ToDictionary(x => x.Node.Id, x => x); - } - - public ContentNodeKit GetContentSource(IScope scope, int id) - => _kits.TryGetValue(id, out var kit) ? kit : default; - - public IEnumerable GetAllContentSources(IScope scope) - => _kits.Values; - - public IEnumerable GetBranchContentSources(IScope scope, int id) - { - throw new NotImplementedException(); - } - - public IEnumerable GetTypeContentSources(IScope scope, IEnumerable ids) - => _kits.Values.Where(x => ids.Contains(x.ContentTypeId)); - - public ContentNodeKit GetMediaSource(IScope scope, int id) - { - throw new NotImplementedException(); - } - - public IEnumerable GetAllMediaSources(IScope scope) - { - throw new NotImplementedException(); - } - - public IEnumerable GetBranchMediaSources(IScope scope, int id) - { - throw new NotImplementedException(); - } - - public IEnumerable GetTypeMediaSources(IScope scope, IEnumerable ids) - { - throw new NotImplementedException(); - } } } } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index af63d2244b..70a349e0cb 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -134,9 +134,6 @@ namespace Umbraco.Tests.PublishedContent CreateDate = DateTime.Now, CreatorId = 1, CreatorName = "Shannon", - // fixme what're we gonna do? - //DocumentTypeAlias = contentTypeAlias, - //DocumentTypeId = 2, Id = 3, SortOrder = 4, TemplateId = 5, @@ -186,7 +183,9 @@ namespace Umbraco.Tests.PublishedContent // l8tr... private class TestPublishedContent : IPublishedContent { - public string Url { get; set; } + public string Url { get; set; } + public string GetUrl(string culture = ".") => throw new NotSupportedException(); + public PublishedItemType ItemType { get; set; } IPublishedContent IPublishedContent.Parent diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs index d6321af692..acff953503 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs @@ -12,14 +12,14 @@ namespace Umbraco.Tests.PublishedContent [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] public class PublishedContentExtensionTests : PublishedContentTestBase { - private UmbracoContext ctx; - private string xmlContent = ""; - private bool createContentTypes = true; + private UmbracoContext _ctx; + private string _xmlContent = ""; + private bool _createContentTypes = true; private Dictionary _contentTypes; protected override string GetXmlContent(int templateId) { - return xmlContent; + return _xmlContent; } [Test] @@ -27,7 +27,7 @@ namespace Umbraco.Tests.PublishedContent { InitializeInheritedContentTypes(); - var publishedContent = ctx.ContentCache.GetById(1100); + var publishedContent = _ctx.ContentCache.GetById(1100); Assert.That(publishedContent.IsDocumentType("inherited", false)); } @@ -36,7 +36,7 @@ namespace Umbraco.Tests.PublishedContent { InitializeInheritedContentTypes(); - var publishedContent = ctx.ContentCache.GetById(1100); + var publishedContent = _ctx.ContentCache.GetById(1100); Assert.That(publishedContent.IsDocumentType("base", false), Is.False); } @@ -45,7 +45,7 @@ namespace Umbraco.Tests.PublishedContent { InitializeInheritedContentTypes(); - var publishedContent = ctx.ContentCache.GetById(1100); + var publishedContent = _ctx.ContentCache.GetById(1100); Assert.That(publishedContent.IsDocumentType("inherited", true)); } @@ -53,9 +53,9 @@ namespace Umbraco.Tests.PublishedContent public void IsDocumentType_Recursive_BaseType_ReturnsTrue() { InitializeInheritedContentTypes(); - ContentTypesCache.GetPublishedContentTypeByAlias = null; // fixme this is not pretty + ContentTypesCache.GetPublishedContentTypeByAlias = null; - var publishedContent = ctx.ContentCache.GetById(1100); + var publishedContent = _ctx.ContentCache.GetById(1100); Assert.That(publishedContent.IsDocumentType("base", true)); } @@ -64,14 +64,14 @@ namespace Umbraco.Tests.PublishedContent { InitializeInheritedContentTypes(); - var publishedContent = ctx.ContentCache.GetById(1100); + var publishedContent = _ctx.ContentCache.GetById(1100); Assert.That(publishedContent.IsDocumentType("invalidbase", true), Is.False); } private void InitializeInheritedContentTypes() { - ctx = GetUmbracoContext("/", 1, null, true); - if (createContentTypes) + _ctx = GetUmbracoContext("/", 1, null, true); + if (_createContentTypes) { var contentTypeService = Current.Services.ContentTypeService; var baseType = new ContentType(-1) { Alias = "base", Name = "Base" }; @@ -85,12 +85,12 @@ namespace Umbraco.Tests.PublishedContent { inheritedType.Alias, new PublishedContentType(inheritedType, null) } }; ContentTypesCache.GetPublishedContentTypeByAlias = alias => _contentTypes[alias]; - createContentTypes = false; + _createContentTypes = false; } ContentTypesCache.GetPublishedContentTypeByAlias = alias => _contentTypes[alias]; - xmlContent = @" + _xmlContent = @" diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index 38ba7e771b..7cdea14008 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -189,6 +189,7 @@ namespace Umbraco.Tests.PublishedContent public Guid Version { get; set; } public int Level { get; set; } public string Url { get; set; } + public string GetUrl(string culture = ".") => throw new NotSupportedException(); public PublishedItemType ItemType { get { return PublishedItemType.Content; } } public bool IsDraft { get; set; } diff --git a/src/Umbraco.Tests/Routing/UrlProviderTests.cs b/src/Umbraco.Tests/Routing/UrlProviderTests.cs index 185812002d..d3cd25ae92 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderTests.cs @@ -5,6 +5,7 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; @@ -166,9 +167,15 @@ namespace Umbraco.Tests.Routing var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); + var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), + ContentVariation.CultureNeutral); + var publishedContent = new TestPublishedContent(contentType, 1234, Guid.NewGuid(), new Dictionary(), false); + var publishedContentCache = new Mock(); publishedContentCache.Setup(x => x.GetRouteById(1234, "fr-FR")) .Returns("9876/home/test-fr"); //prefix with the root id node with the domain assigned as per the umbraco standard + publishedContentCache.Setup(x => x.GetById(It.IsAny())) + .Returns(id => id == 1234 ? publishedContent : null); var domainCache = new Mock(); domainCache.Setup(x => x.GetAssigned(It.IsAny(), false)) @@ -209,9 +216,15 @@ namespace Umbraco.Tests.Routing var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); + var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), + ContentVariation.CultureNeutral); + var publishedContent = new TestPublishedContent(contentType, 1234, Guid.NewGuid(), new Dictionary(), false); + var publishedContentCache = new Mock(); publishedContentCache.Setup(x => x.GetRouteById(1234, "fr-FR")) .Returns("9876/home/test-fr"); //prefix with the root id node with the domain assigned as per the umbraco standard + publishedContentCache.Setup(x => x.GetById(It.IsAny())) + .Returns(id => id == 1234 ? publishedContent : null); var domainCache = new Mock(); domainCache.Setup(x => x.GetAssigned(It.IsAny(), false)) @@ -261,9 +274,15 @@ namespace Umbraco.Tests.Routing var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); + var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), + ContentVariation.CultureNeutral); + var publishedContent = new TestPublishedContent(contentType, 1234, Guid.NewGuid(), new Dictionary(), false); + var publishedContentCache = new Mock(); publishedContentCache.Setup(x => x.GetRouteById(1234, "fr-FR")) .Returns("9876/home/test-fr"); //prefix with the root id node with the domain assigned as per the umbraco standard + publishedContentCache.Setup(x => x.GetById(It.IsAny())) + .Returns(id => id == 1234 ? publishedContent : null); var domainCache = new Mock(); domainCache.Setup(x => x.GetAssigned(It.IsAny(), false)) @@ -306,7 +325,6 @@ namespace Umbraco.Tests.Routing globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); SettingsForTests.ConfigureSettings(globalSettings.Object); - var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); diff --git a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs index b064e9685c..627d95ea29 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -190,7 +190,7 @@ namespace Umbraco.Tests.Routing SetDomains1(); var currentUri = new Uri(currentUrl); - var result = umbracoContext.UrlProvider.GetUrl(nodeId, currentUri, absolute); + var result = umbracoContext.UrlProvider.GetUrl(nodeId, absolute, current: currentUri); Assert.AreEqual(expected, result); } @@ -226,7 +226,7 @@ namespace Umbraco.Tests.Routing SetDomains2(); var currentUri = new Uri(currentUrl); - var result = umbracoContext.UrlProvider.GetUrl(nodeId, currentUri, absolute); + var result = umbracoContext.UrlProvider.GetUrl(nodeId, absolute, current : currentUri); Assert.AreEqual(expected, result); } @@ -254,7 +254,7 @@ namespace Umbraco.Tests.Routing SetDomains3(); var currentUri = new Uri(currentUrl); - var result = umbracoContext.UrlProvider.GetUrl(nodeId, currentUri, absolute); + var result = umbracoContext.UrlProvider.GetUrl(nodeId, absolute, current : currentUri); Assert.AreEqual(expected, result); } @@ -288,7 +288,7 @@ namespace Umbraco.Tests.Routing SetDomains4(); var currentUri = new Uri(currentUrl); - var result = umbracoContext.UrlProvider.GetUrl(nodeId, currentUri, absolute); + var result = umbracoContext.UrlProvider.GetUrl(nodeId, absolute, current : currentUri); Assert.AreEqual(expected, result); } @@ -312,17 +312,17 @@ namespace Umbraco.Tests.Routing SetDomains4(); string ignore; - ignore = umbracoContext.UrlProvider.GetUrl(1001, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(10011, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(100111, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(10012, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(100121, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(10013, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(1002, new Uri("http://domain1.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(1001, new Uri("http://domain2.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(10011, new Uri("http://domain2.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(100111, new Uri("http://domain2.com"), false); - ignore = umbracoContext.UrlProvider.GetUrl(1002, new Uri("http://domain2.com"), false); + ignore = umbracoContext.UrlProvider.GetUrl(1001, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(10011, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(100111, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(10012, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(100121, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(10013, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(1002, false, current: new Uri("http://domain1.com")); + ignore = umbracoContext.UrlProvider.GetUrl(1001, false, current: new Uri("http://domain2.com")); + ignore = umbracoContext.UrlProvider.GetUrl(10011, false, current: new Uri("http://domain2.com")); + ignore = umbracoContext.UrlProvider.GetUrl(100111, false, current: new Uri("http://domain2.com")); + ignore = umbracoContext.UrlProvider.GetUrl(1002, false, current: new Uri("http://domain2.com")); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); @@ -341,15 +341,15 @@ namespace Umbraco.Tests.Routing CheckRoute(cachedRoutes, cachedIds, 1002, "/1002"); // use the cache - Assert.AreEqual("/", umbracoContext.UrlProvider.GetUrl(1001, new Uri("http://domain1.com"), false)); - Assert.AreEqual("/en/", umbracoContext.UrlProvider.GetUrl(10011, new Uri("http://domain1.com"), false)); - Assert.AreEqual("/en/1001-1-1/", umbracoContext.UrlProvider.GetUrl(100111, new Uri("http://domain1.com"), false)); - Assert.AreEqual("/fr/", umbracoContext.UrlProvider.GetUrl(10012, new Uri("http://domain1.com"), false)); - Assert.AreEqual("/fr/1001-2-1/", umbracoContext.UrlProvider.GetUrl(100121, new Uri("http://domain1.com"), false)); - Assert.AreEqual("/1001-3/", umbracoContext.UrlProvider.GetUrl(10013, new Uri("http://domain1.com"), false)); - Assert.AreEqual("/1002/", umbracoContext.UrlProvider.GetUrl(1002, new Uri("http://domain1.com"), false)); + Assert.AreEqual("/", umbracoContext.UrlProvider.GetUrl(1001, false, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/en/", umbracoContext.UrlProvider.GetUrl(10011, false, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/en/1001-1-1/", umbracoContext.UrlProvider.GetUrl(100111, false, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/fr/", umbracoContext.UrlProvider.GetUrl(10012, false, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/fr/1001-2-1/", umbracoContext.UrlProvider.GetUrl(100121, false, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/1001-3/", umbracoContext.UrlProvider.GetUrl(10013, false, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/1002/", umbracoContext.UrlProvider.GetUrl(1002, false, current: new Uri("http://domain1.com"))); - Assert.AreEqual("http://domain1.com/fr/1001-2-1/", umbracoContext.UrlProvider.GetUrl(100121, new Uri("http://domain2.com"), false)); + Assert.AreEqual("http://domain1.com/fr/1001-2-1/", umbracoContext.UrlProvider.GetUrl(100121, false, current: new Uri("http://domain2.com"))); } private static void CheckRoute(IDictionary routes, IDictionary ids, int id, string route) diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index fb9b3ee0e4..b6eff1e0ef 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -89,7 +89,7 @@ namespace Umbraco.Tests.Scoping contentTypeFactory, null, publishedSnapshotAccessor, - Mock.Of(), + Mock.Of(), Logger, ScopeProvider, documentRepository, mediaRepository, memberRepository, diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 97d88a680b..d5f10cc324 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -153,7 +153,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting true); //replace it var urlHelper = new Mock(); - urlHelper.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + urlHelper.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns("/hello/world/1234"); var membershipHelper = new MembershipHelper(umbCtx, Mock.Of(), Mock.Of()); diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs index 14a0979091..3f2a05dfda 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs @@ -18,12 +18,12 @@ namespace Umbraco.Tests.TestHelpers.Stubs public int TemplateId { get; set; } public int SortOrder { get; set; } public string Name { get; set; } - public IPublishedVariationContextAccessor VariationContextAccessor { get; set; } + public ICurrentVariationAccessor VariationAccessor { get; set; } public PublishedCultureInfos GetCulture(string culture = ".") { // handle context culture if (culture == ".") - culture = VariationContextAccessor?.Context.Culture; + culture = VariationAccessor?.CurrentVariation.Culture; // no invariant culture infos if (culture == null || Cultures == null) return null; @@ -45,6 +45,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs public Guid Version { get; set; } public int Level { get; set; } public string Url { get; set; } + public string GetUrl(string culture = ".") => throw new NotSupportedException(); public PublishedItemType ItemType => ContentType.ItemType; public bool IsDraft { get; set; } public IPublishedContent Parent { get; set; } diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 75b9d6b0fd..2c2b275e7f 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -264,7 +264,7 @@ namespace Umbraco.Tests.TestHelpers // testing=true so XmlStore will not use the file nor the database var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); - var variationContextAccessor = new TestPublishedVariationContextAccessor(); + var variationContextAccessor = new TestCurrentVariationAccessor(); var service = new PublishedSnapshotService( ServiceContext, Container.GetInstance(), diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestCurrentVariationAccessor.cs b/src/Umbraco.Tests/Testing/Objects/Accessors/TestCurrentVariationAccessor.cs new file mode 100644 index 0000000000..3b2ad36f00 --- /dev/null +++ b/src/Umbraco.Tests/Testing/Objects/Accessors/TestCurrentVariationAccessor.cs @@ -0,0 +1,17 @@ +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Tests.Testing.Objects.Accessors +{ + /// + /// Provides an implementation of for tests. + /// + public class TestCurrentVariationAccessor : ICurrentVariationAccessor + { + /// + public CurrentVariation CurrentVariation + { + get; + set; + } + } +} diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedVariationContextAccessor.cs b/src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedVariationContextAccessor.cs deleted file mode 100644 index 455e5795a9..0000000000 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedVariationContextAccessor.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Umbraco.Core.Models.PublishedContent; - -namespace Umbraco.Tests.Testing.Objects.Accessors -{ - /// - /// Provides an implementation of for tests. - /// - public class TestPublishedVariationContextAccessor : IPublishedVariationContextAccessor - { - /// - public PublishedVariationContext Context - { - get; - set; - } - } -} diff --git a/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs b/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs new file mode 100644 index 0000000000..26bfff0e1a --- /dev/null +++ b/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Scoping; +using Umbraco.Web.PublishedCache.NuCache; +using Umbraco.Web.PublishedCache.NuCache.DataSource; + +namespace Umbraco.Tests.Testing.Objects +{ + internal class TestDataSource : IDataSource + { + private readonly Dictionary _kits; + + public TestDataSource(params ContentNodeKit[] kits) + : this((IEnumerable) kits) + { } + + public TestDataSource(IEnumerable kits) + { + _kits = kits.ToDictionary(x => x.Node.Id, x => x); + } + + public ContentNodeKit GetContentSource(IScope scope, int id) + => _kits.TryGetValue(id, out var kit) ? kit : default; + + public IEnumerable GetAllContentSources(IScope scope) + => _kits.Values; + + public IEnumerable GetBranchContentSources(IScope scope, int id) + { + throw new NotImplementedException(); + } + + public IEnumerable GetTypeContentSources(IScope scope, IEnumerable ids) + => _kits.Values.Where(x => ids.Contains(x.ContentTypeId)); + + public ContentNodeKit GetMediaSource(IScope scope, int id) + { + throw new NotImplementedException(); + } + + public IEnumerable GetAllMediaSources(IScope scope) + { + throw new NotImplementedException(); + } + + public IEnumerable GetBranchMediaSources(IScope scope, int id) + { + throw new NotImplementedException(); + } + + public IEnumerable GetTypeMediaSources(IScope scope, IEnumerable ids) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 9f06d0de17..f44cba624f 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -1,11 +1,13 @@ using System; using System.Globalization; +using System.Linq; using System.Web.Security; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Dictionary; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; @@ -75,13 +77,18 @@ namespace Umbraco.Tests.Testing.TestingTests var umbracoContext = TestObjects.GetUmbracoContextMock(); var urlProviderMock = new Mock(); - urlProviderMock.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + urlProviderMock.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns("/hello/world/1234"); var urlProvider = urlProviderMock.Object; var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }); - Assert.AreEqual("/hello/world/1234", theUrlProvider.GetUrl(1234)); + var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), + ContentVariation.InvariantNeutral); + var publishedContent = Mock.Of(); + Mock.Get(publishedContent).Setup(x => x.ContentType).Returns(contentType); + + Assert.AreEqual("/hello/world/1234", theUrlProvider.GetUrl(publishedContent)); } } } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index c1d1da0b54..bf8dc2285a 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -129,7 +129,8 @@ - + + @@ -180,7 +181,7 @@ - + diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs index 165f103d43..27a4541733 100644 --- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs +++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using System.Web; using LightInject; using Moq; @@ -10,6 +11,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; @@ -44,7 +46,7 @@ namespace Umbraco.Tests.Web Current.Container = container.Object; Umbraco.Web.Composing.Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - + Udi.ResetUdiTypes(); } @@ -66,26 +68,36 @@ namespace Umbraco.Tests.Web //setup a mock entity service from the service context to return an integer for a GUID var entityService = Mock.Get(serviceCtxMock.EntityService); - entityService.Setup(x => x.GetId(It.IsAny(), It.IsAny())) - .Returns((Guid id, UmbracoObjectTypes objType) => - { - return Attempt.Succeed(1234); - }); + //entityService.Setup(x => x.GetId(It.IsAny(), It.IsAny())) + // .Returns((Guid id, UmbracoObjectTypes objType) => + // { + // return Attempt.Succeed(1234); + // }); //setup a mock url provider which we'll use fo rtesting var testUrlProvider = new Mock(); - testUrlProvider.Setup(x => x.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Returns((UmbracoContext umbCtx, int id, Uri url, UrlProviderMode mode, string culture) => - { - return "/my-test-url"; - }); + testUrlProvider + .Setup(x => x.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns((UmbracoContext umbCtx, IPublishedContent content, UrlProviderMode mode, string culture, Uri url) => "/my-test-url"); var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + var contentType = new PublishedContentType(666, "alia", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.InvariantNeutral); + var publishedContent = Mock.Of(); + Mock.Get(publishedContent).Setup(x => x.Id).Returns(1234); + Mock.Get(publishedContent).Setup(x => x.ContentType).Returns(contentType); + var contentCache = Mock.Of(); + Mock.Get(contentCache).Setup(x => x.GetById(It.IsAny())).Returns(publishedContent); + Mock.Get(contentCache).Setup(x => x.GetById(It.IsAny())).Returns(publishedContent); + var snapshot = Mock.Of(); + Mock.Get(snapshot).Setup(x => x.Content).Returns(contentCache); + var snapshotService = Mock.Of(); + Mock.Get(snapshotService).Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(snapshot); + using (var umbCtx = UmbracoContext.EnsureContext( Umbraco.Web.Composing.Current.UmbracoContextAccessor, Mock.Of(), - Mock.Of(), + snapshotService, new Mock(null, null, globalSettings).Object, //setup a quick mock of the WebRouting section Mock.Of(section => section.WebRouting == Mock.Of(routingSection => routingSection.UrlProviderMode == "AutoLegacy")), diff --git a/src/Umbraco.Web/Editors/MacroController.cs b/src/Umbraco.Web/Editors/MacroController.cs index ba23d4c8dd..bc0d1f4a0c 100644 --- a/src/Umbraco.Web/Editors/MacroController.cs +++ b/src/Umbraco.Web/Editors/MacroController.cs @@ -27,11 +27,11 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class MacroController : UmbracoAuthorizedJsonController, IRequiresSessionState { - private readonly IPublishedVariationContextAccessor _variationContextAccessor; + private readonly ICurrentVariationAccessor _variationAccessor; - public MacroController(IPublishedVariationContextAccessor variationContextAccessor) + public MacroController(ICurrentVariationAccessor variationAccessor) { - _variationContextAccessor = variationContextAccessor; + _variationAccessor = variationAccessor; } /// @@ -121,7 +121,7 @@ namespace Umbraco.Web.Editors //the 'easiest' way might be to create an IPublishedContent manually and populate the legacy 'page' object with that //and then set the legacy parameters. - var legacyPage = new global::umbraco.page(doc, _variationContextAccessor); + var legacyPage = new global::umbraco.page(doc, _variationAccessor); UmbracoContext.HttpContext.Items["pageID"] = doc.Id; UmbracoContext.HttpContext.Items["pageElements"] = legacyPage.Elements; UmbracoContext.HttpContext.Items[global::Umbraco.Core.Constants.Conventions.Url.AltTemplate] = null; diff --git a/src/Umbraco.Web/Models/PublishedContentBase.cs b/src/Umbraco.Web/Models/PublishedContentBase.cs index 0fe7bc0fc7..1c91b41bff 100644 --- a/src/Umbraco.Web/Models/PublishedContentBase.cs +++ b/src/Umbraco.Web/Models/PublishedContentBase.cs @@ -1,11 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Umbraco.Core; -using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -19,7 +15,7 @@ namespace Umbraco.Web.Models [DebuggerDisplay("Content Id: {Id}, Name: {Name}")] public abstract class PublishedContentBase : IPublishedContent { - private string _url; + private string _url; // fixme meaning? #region ContentType @@ -75,34 +71,31 @@ namespace Umbraco.Web.Models /// public abstract DateTime UpdateDate { get; } + /// + public virtual string Url => GetUrl(); + /// /// /// The url of documents are computed by the document url providers. The url of medias are, at the moment, /// computed here from the 'umbracoFile' property -- but we should move to media url providers at some point. /// - public virtual string Url + public virtual string GetUrl(string culture = ".") // fixme - consider .GetCulture("fr-FR").Url { - // fixme contextual! - get - { - // should be thread-safe although it won't prevent url from being resolved more than once - if (_url != null) - return _url; // fixme very bad idea with nucache? or? - switch (ItemType) { - case PublishedItemType.Content: + case PublishedItemType.Content: + // fixme inject an umbraco context accessor! if (UmbracoContext.Current == null) - throw new InvalidOperationException( - "Cannot resolve a Url for a content item when UmbracoContext.Current is null."); + throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.Current is null."); if (UmbracoContext.Current.UrlProvider == null) - throw new InvalidOperationException( - "Cannot resolve a Url for a content item when UmbracoContext.Current.UrlProvider is null."); - _url = UmbracoContext.Current.UrlProvider.GetUrl(Id); - break; + throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.Current.UrlProvider is null."); + return UmbracoContext.Current.UrlProvider.GetUrl(this); + case PublishedItemType.Media: + if (_url != null) return _url; // assume it will not depend on current uri/culture + var prop = GetProperty(Constants.Conventions.Media.File); - if (prop == null || prop.GetValue() == null) + if (prop?.GetValue() == null) { _url = string.Empty; return _url; @@ -110,7 +103,7 @@ namespace Umbraco.Web.Models var propType = ContentType.GetPropertyType(Constants.Conventions.Media.File); - // fixme this is horrible we need url providers for media too + // fixme this is horrible we need url providers for media too + this does NOT support variations //This is a hack - since we now have 2 properties that support a URL: upload and cropper, we need to detect this since we always // want to return the normal URL and the cropper stores data as json switch (propType.EditorAlias) @@ -130,13 +123,12 @@ namespace Umbraco.Web.Models _url = prop.GetValue()?.ToString(); break; } - break; + + return _url; + default: throw new NotSupportedException(); } - - return _url; - } } /// @@ -174,7 +166,7 @@ namespace Umbraco.Web.Models /// public virtual IPublishedProperty GetProperty(string alias, bool recurse) { - // fixme - but can this work with variants? + // fixme - but can recurse work with variants? var property = GetProperty(alias); if (recurse == false) return property; diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs index de658daeec..1a562dad79 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs @@ -34,10 +34,10 @@ namespace Umbraco.Web.PublishedCache.NuCache DateTime createDate, int creatorId, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, - IPublishedVariationContextAccessor variationContextAccessor) + ICurrentVariationAccessor variationAccessor) : this(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId) { - SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor); + SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationAccessor); } // 2-phases ctor, phase 1 @@ -59,7 +59,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } // two-phase ctor, phase 2 - public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { ContentType = contentType; @@ -67,9 +67,9 @@ namespace Umbraco.Web.PublishedCache.NuCache throw new ArgumentException("Both draftData and publishedData cannot be null at the same time."); if (draftData != null) - Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationAccessor).CreateModel(); if (publishedData != null) - Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationAccessor).CreateModel(); } // clone parent @@ -98,7 +98,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } // clone with new content type - public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { Id = origin.Id; Uid = origin.Uid; @@ -113,8 +113,8 @@ namespace Umbraco.Web.PublishedCache.NuCache var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft); var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published); - Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); - Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationAccessor).CreateModel(); + Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationAccessor).CreateModel(); ChildContentIds = origin.ChildContentIds; // can be the *same* list FIXME oh really? } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs index 19163d5e8d..d4d4221bf0 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs @@ -17,9 +17,9 @@ namespace Umbraco.Web.PublishedCache.NuCache public static ContentNodeKit Null { get; } = new ContentNodeKit { ContentTypeId = -1 }; - public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { - Node.SetContentTypeAndData(contentType, DraftData, PublishedData, publishedSnapshotAccessor, variationContextAccessor); + Node.SetContentTypeAndData(contentType, DraftData, PublishedData, publishedSnapshotAccessor, variationAccessor); } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs index 95482bb6b1..b19e9f5ddf 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // SnapDictionary has unit tests to ensure it all works correctly private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly IPublishedVariationContextAccessor _variationContextAccessor; + private readonly ICurrentVariationAccessor _variationAccessor; private readonly ConcurrentDictionary> _contentNodes; private readonly ConcurrentDictionary> _contentRootNodes; private readonly ConcurrentDictionary> _contentTypesById; @@ -44,10 +44,10 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Ctor - public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor, ILogger logger, BPlusTree localDb = null) + public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor, ILogger logger, BPlusTree localDb = null) { _publishedSnapshotAccessor = publishedSnapshotAccessor; - _variationContextAccessor = variationContextAccessor; + _variationAccessor = variationAccessor; _logger = logger; _localDb = localDb; @@ -279,7 +279,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (node == null) continue; var contentTypeId = node.ContentType.Id; if (index.TryGetValue(contentTypeId, out PublishedContentType contentType) == false) continue; - SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor)); + SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationAccessor)); } } finally @@ -393,7 +393,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _contentNodes.TryGetValue(id, out LinkedNode link); if (link?.Value == null) continue; - var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor); + var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationAccessor); SetValueLocked(_contentNodes, id, node); if (_localDb != null) RegisterChange(id, node.ToKit()); } @@ -416,7 +416,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return false; // and use - kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor); + kit.Build(link.Value, _publishedSnapshotAccessor, _variationAccessor); return true; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs index 899fbd6eed..61f3d9862d 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.PublishedCache.NuCache class MemberCache : IPublishedMemberCache, INavigableData { private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - public readonly IPublishedVariationContextAccessor _variationContextAccessor; + public readonly ICurrentVariationAccessor VariationAccessor; private readonly ICacheProvider _snapshotCache; private readonly IMemberService _memberService; private readonly IDataTypeService _dataTypeService; @@ -24,11 +24,11 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly PublishedContentTypeCache _contentTypeCache; private readonly bool _previewDefault; - public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, IDataTypeService dataTypeService, ILocalizationService localizationService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, IDataTypeService dataTypeService, ILocalizationService localizationService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { _snapshotCache = snapshotCache; _publishedSnapshotAccessor = publishedSnapshotAccessor; - _variationContextAccessor = variationContextAccessor; + VariationAccessor = variationAccessor; _memberService = memberService; _dataTypeService = dataTypeService; _localizationService = localizationService; @@ -65,14 +65,14 @@ namespace Umbraco.Web.PublishedCache.NuCache var member = _memberService.GetById(memberId); return member == null ? null - : PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, _variationContextAccessor); + : PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationAccessor); }); } private IPublishedContent /*IPublishedMember*/ GetById(IMember member, bool previewing) { return GetCacheItem(CacheKeys.MemberCacheMember("ById", _previewDefault, member.Id), () => - PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, _variationContextAccessor)); + PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationAccessor)); } public IPublishedContent /*IPublishedMember*/ GetByProviderKey(object key) @@ -107,7 +107,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public IPublishedContent /*IPublishedMember*/ GetByMember(IMember member) { - return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, _variationContextAccessor); + return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationAccessor); } public IEnumerable GetAtRoot(bool preview) @@ -115,7 +115,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // because members are flat (not a tree) everything is at root // because we're loading everything... let's just not cache? var members = _memberService.GetAllMembers(); - return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, _variationContextAccessor)); + return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationAccessor)); } public XPathNavigator CreateNavigator() diff --git a/src/Umbraco.Web/PublishedCache/NuCache/Property.cs b/src/Umbraco.Web/PublishedCache/NuCache/Property.cs index 02dfc4e934..6231425e50 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/Property.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/Property.cs @@ -191,7 +191,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // use context values // fixme CultureSegment? - var publishedVariationContext = _content.VariationContextAccessor?.Context; + var publishedVariationContext = _content.VariationAccessor?.CurrentVariation; if (culture == ".") culture = _variations.Has(ContentVariation.CultureNeutral) ? publishedVariationContext?.Culture : null; if (segment == ".") segment = _variations.Has(ContentVariation.CultureNeutral) ? publishedVariationContext?.Segment : null; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index 0ca20fd625..ea2480ec7a 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -22,12 +22,12 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Constructors - public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { _contentNode = contentNode; _contentData = contentData; _publishedSnapshotAccessor = publishedSnapshotAccessor; - VariationContextAccessor = variationContextAccessor; // fixme why is this a property? should be be on the base class? + VariationAccessor = variationAccessor; // fixme why is this a property? should be be on the base class? _urlSegment = _contentData.Name.ToUrlSegment(); IsPreviewing = _contentData.Published == false; @@ -70,7 +70,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { _contentNode = contentNode; _publishedSnapshotAccessor = origin._publishedSnapshotAccessor; - VariationContextAccessor = origin.VariationContextAccessor; + VariationAccessor = origin.VariationAccessor; _contentData = origin._contentData; _urlSegment = origin._urlSegment; @@ -86,7 +86,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private PublishedContent(PublishedContent origin) { _publishedSnapshotAccessor = origin._publishedSnapshotAccessor; - VariationContextAccessor = origin.VariationContextAccessor; + VariationAccessor = origin.VariationAccessor; _contentNode = origin._contentNode; _contentData = origin._contentData; @@ -181,7 +181,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment? return _contentData.Name; - var culture = VariationContextAccessor.Context.Culture; + var culture = VariationAccessor.CurrentVariation.Culture; if (culture == null) return _contentData.Name; @@ -197,7 +197,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment? return _urlSegment; - var culture = VariationContextAccessor.Context.Culture; + var culture = VariationAccessor.CurrentVariation.Culture; if (culture == null) return _urlSegment; @@ -244,7 +244,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { // handle context culture if (culture == ".") - culture = VariationContextAccessor.Context.Culture; + culture = VariationAccessor.CurrentVariation.Culture; // no invariant culture infos if (culture == null) return null; @@ -397,7 +397,7 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Internal - internal IPublishedVariationContextAccessor VariationContextAccessor { get; } + internal ICurrentVariationAccessor VariationAccessor { get; } // used by navigable content internal IPublishedProperty[] PropertiesArray { get; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs index 63ef1ae5aa..4e01df0cd9 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs @@ -15,13 +15,13 @@ namespace Umbraco.Web.PublishedCache.NuCache { private readonly IMember _member; - private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) - : base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor) + private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) + : base(contentNode, contentData, publishedSnapshotAccessor, variationAccessor) { _member = member; } - public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { var d = new ContentData { @@ -37,7 +37,7 @@ namespace Umbraco.Web.PublishedCache.NuCache member.Level, member.Path, member.SortOrder, member.ParentId, member.CreateDate, member.CreatorId); - return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationAccessor).CreateModel(); } private static Dictionary GetPropertyValues(PublishedContentType contentType, IMember member) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index b2cb8bbcf8..3108f24090 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -81,12 +81,12 @@ namespace Umbraco.Web.PublishedCache.NuCache public PublishedSnapshotService(Options options, MainDom mainDom, IRuntimeState runtime, ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IdkMap idkMap, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor, + IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor, ILogger logger, IScopeProvider scopeProvider, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, ISystemDefaultCultureAccessor systemDefaultCultureAccessor, IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper) - : base(publishedSnapshotAccessor, variationContextAccessor) + : base(publishedSnapshotAccessor, variationAccessor) { //if (Interlocked.Increment(ref _singletonCheck) > 1) // throw new Exception("Singleton must be instancianted only once!"); @@ -145,13 +145,13 @@ namespace Umbraco.Web.PublishedCache.NuCache // stores are created with a db so they can write to it, but they do not read from it, // stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to // figure out whether it can read the dbs or it should populate them from sql - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localContentDb); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localMediaDb); + _contentStore = new ContentStore(publishedSnapshotAccessor, variationAccessor, logger, _localContentDb); + _mediaStore = new ContentStore(publishedSnapshotAccessor, variationAccessor, logger, _localMediaDb); } else { - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger); + _contentStore = new ContentStore(publishedSnapshotAccessor, variationAccessor, logger); + _mediaStore = new ContentStore(publishedSnapshotAccessor, variationAccessor, logger); } _domainStore = new SnapDictionary(); @@ -173,7 +173,7 @@ namespace Umbraco.Web.PublishedCache.NuCache try { - if (_localDbExists) // fixme? + if (_localDbExists) { LockAndLoadContent(LoadContentFromLocalDbLocked); LockAndLoadMedia(LoadMediaFromLocalDbLocked); @@ -333,7 +333,6 @@ namespace Umbraco.Web.PublishedCache.NuCache //private void LoadContent(IContent content) //{ // var contentService = _serviceContext.ContentService as ContentService; - // if (contentService == null) throw new Exception("oops"); // var newest = content; // var published = newest.Published // ? newest @@ -536,7 +535,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } if (draftChanged || publishedChanged) - ((PublishedSnapshot)CurrentPublishedSnapshot).Resync(); + ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); } private void NotifyLocked(IEnumerable payloads, out bool draftChanged, out bool publishedChanged) @@ -544,9 +543,6 @@ namespace Umbraco.Web.PublishedCache.NuCache publishedChanged = false; draftChanged = false; - if (!(_serviceContext.ContentService is ContentService)) - throw new Exception("oops"); - // locks: // content (and content types) are read-locked while reading content // contentStore is wlocked (so readable, only no new views) @@ -633,16 +629,13 @@ namespace Umbraco.Web.PublishedCache.NuCache } if (anythingChanged) - ((PublishedSnapshot)CurrentPublishedSnapshot).Resync(); + ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); } private void NotifyLocked(IEnumerable payloads, out bool anythingChanged) { anythingChanged = false; - if (!(_serviceContext.MediaService is MediaService)) - throw new Exception("oops"); - // locks: // see notes for content cache refresher @@ -722,7 +715,7 @@ namespace Umbraco.Web.PublishedCache.NuCache Notify(_contentStore, payloads, RefreshContentTypesLocked); Notify(_mediaStore, payloads, RefreshMediaTypesLocked); - ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); // fixme all + ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); } private void Notify(ContentStore store, ContentTypeCacheRefresher.JsonPayload[] payloads, Action, IEnumerable, IEnumerable, IEnumerable> action) @@ -778,9 +771,6 @@ namespace Umbraco.Web.PublishedCache.NuCache // some locking on datatypes _publishedContentTypeFactory.NotifyDataTypeChanges(idsA); - if (!(_serviceContext.ContentService is ContentService)) - throw new Exception("oops"); - using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.ContentTree); @@ -788,9 +778,6 @@ namespace Umbraco.Web.PublishedCache.NuCache scope.Complete(); } - if (!(_serviceContext.MediaService is MediaService)) - throw new Exception("oops"); - using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.MediaTree); @@ -799,7 +786,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } } - ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); // fixme elsewhere! + ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); } public override void Notify(DomainCacheRefresher.JsonPayload[] payloads) @@ -815,8 +802,6 @@ namespace Umbraco.Web.PublishedCache.NuCache switch (payload.ChangeType) { case DomainChangeTypes.RefreshAll: - if (!(_serviceContext.DomainService is DomainService)) - throw new Exception("oops"); using (var scope = _scopeProvider.CreateScope()) { @@ -900,10 +885,6 @@ namespace Umbraco.Web.PublishedCache.NuCache // contentStore is wlocked (so readable, only no new views) // and it can be wlocked by 1 thread only at a time - // fixme wtf? - //if (!(_serviceContext.ContentService is ContentService)) - // throw new Exception("oops"); - var refreshedIdsA = refreshedIds.ToArray(); using (var scope = _scopeProvider.CreateScope()) @@ -925,9 +906,6 @@ namespace Umbraco.Web.PublishedCache.NuCache // mediaStore is wlocked (so readable, only no new views) // and it can be wlocked by 1 thread only at a time - if (!(_serviceContext.MediaService is MediaService)) - throw new Exception("oops"); - var refreshedIdsA = refreshedIds.ToArray(); using (var scope = _scopeProvider.CreateScope()) @@ -1000,7 +978,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // a MaxValue to make sure this one runs last, and it should be ok scopeContext.Enlist("Umbraco.Web.PublishedCache.NuCache.PublishedSnapshotService.Resync", () => this, (completed, svc) => { - ((PublishedSnapshot)svc.CurrentPublishedSnapshot).Resync(); + ((PublishedSnapshot)svc.CurrentPublishedSnapshot)?.Resync(); }, int.MaxValue); } @@ -1026,7 +1004,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService), MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache), - MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, _serviceContext.DataTypeService, _serviceContext.LocalizationService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor), + MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, _serviceContext.DataTypeService, _serviceContext.LocalizationService, memberTypeCache, PublishedSnapshotAccessor, VariationAccessor), DomainCache = domainCache, SnapshotCache = snapshotCache, ElementsCache = elementsCache @@ -1084,21 +1062,6 @@ namespace Umbraco.Web.PublishedCache.NuCache db.Execute("DELETE FROM cmsContentNu WHERE nodeId=@id", new { id = item.Id }); } - private static readonly string[] PropertiesImpactingAllVersions = { "SortOrder", "ParentId", "Level", "Path", "Trashed" }; - - private static bool HasChangesImpactingAllVersions(IContent icontent) - { - var content = (Content)icontent; - - // UpdateDate will be dirty - // Published may be dirty if saving a Published entity - // so cannot do this (would always be true): - //return content.IsEntityDirty(); - - // have to be more precise & specify properties - return PropertiesImpactingAllVersions.Any(content.IsPropertyDirty); - } - private void OnContentRefreshedEntity(DocumentRepository sender, DocumentRepository.ScopedEntityEventArgs args) { var db = args.Scope.Database; diff --git a/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs b/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs index 64dda9f20b..b5d721e03c 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs @@ -7,14 +7,14 @@ namespace Umbraco.Web.PublishedCache { abstract class PublishedSnapshotServiceBase : IPublishedSnapshotService { - protected PublishedSnapshotServiceBase(IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor) + protected PublishedSnapshotServiceBase(IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor) { PublishedSnapshotAccessor = publishedSnapshotAccessor; - VariationContextAccessor = variationContextAccessor; + VariationAccessor = variationAccessor; } public IPublishedSnapshotAccessor PublishedSnapshotAccessor { get; } - public IPublishedVariationContextAccessor VariationContextAccessor { get; } + public ICurrentVariationAccessor VariationAccessor { get; } // note: NOT setting _publishedSnapshotAccessor.PublishedSnapshot here because it is the // responsibility of the caller to manage what the 'current' facade is diff --git a/src/Umbraco.Web/PublishedCache/SystemDefaultCultureAccessor.cs b/src/Umbraco.Web/PublishedCache/SystemDefaultCultureAccessor.cs index 34910bfe1b..42e1c4dbca 100644 --- a/src/Umbraco.Web/PublishedCache/SystemDefaultCultureAccessor.cs +++ b/src/Umbraco.Web/PublishedCache/SystemDefaultCultureAccessor.cs @@ -19,6 +19,6 @@ namespace Umbraco.Web.PublishedCache } /// - public string DefaultCulture => _localizationService.GetDefaultLanguageIsoCode(); // capture - fast + public string DefaultCulture => _localizationService.GetDefaultLanguageIsoCode(); // fast } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs index 259229a600..ab59fc6aca 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs @@ -43,7 +43,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IScopeProvider scopeProvider, ICacheProvider requestCache, IEnumerable segmentProviders, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor, + IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, ISystemDefaultCultureAccessor systemDefaultCultureAccessor, ILogger logger, @@ -52,7 +52,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache MainDom mainDom, bool testing = false, bool enableRepositoryEvents = true) : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, segmentProviders, - publishedSnapshotAccessor, variationContextAccessor, + publishedSnapshotAccessor, variationAccessor, documentRepository, mediaRepository, memberRepository, systemDefaultCultureAccessor, logger, globalSettings, siteDomainHelper, null, mainDom, testing, enableRepositoryEvents) @@ -63,7 +63,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IPublishedContentTypeFactory publishedContentTypeFactory, IScopeProvider scopeProvider, ICacheProvider requestCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor, + IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, ISystemDefaultCultureAccessor systemDefaultCultureAccessor, ILogger logger, @@ -73,7 +73,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache MainDom mainDom, bool testing, bool enableRepositoryEvents) : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, Enumerable.Empty(), - publishedSnapshotAccessor, variationContextAccessor, + publishedSnapshotAccessor, variationAccessor, documentRepository, mediaRepository, memberRepository, systemDefaultCultureAccessor, logger, globalSettings, siteDomainHelper, contentTypeCache, mainDom, testing, enableRepositoryEvents) @@ -84,7 +84,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IScopeProvider scopeProvider, ICacheProvider requestCache, IEnumerable segmentProviders, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedVariationContextAccessor variationContextAccessor, + IPublishedSnapshotAccessor publishedSnapshotAccessor, ICurrentVariationAccessor variationAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, ISystemDefaultCultureAccessor systemDefaultCultureAccessor, ILogger logger, @@ -93,7 +93,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache PublishedContentTypeCache contentTypeCache, MainDom mainDom, bool testing, bool enableRepositoryEvents) - : base(publishedSnapshotAccessor, variationContextAccessor) + : base(publishedSnapshotAccessor, variationAccessor) { _routesCache = new RoutesCache(); _publishedContentTypeFactory = publishedContentTypeFactory; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheComponent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheComponent.cs index a574575cbd..76af7102f5 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheComponent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheComponent.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache factory.GetInstance().RequestCache, factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), + factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), diff --git a/src/Umbraco.Web/Routing/AliasUrlProvider.cs b/src/Umbraco.Web/Routing/AliasUrlProvider.cs index 4b7cb48add..7b7a70cc2a 100644 --- a/src/Umbraco.Web/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Web/Routing/AliasUrlProvider.cs @@ -1,13 +1,10 @@ using System; 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.Services; -using Umbraco.Web.Composing; -using Umbraco.Web.PublishedCache; +using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Routing { @@ -17,15 +14,13 @@ namespace Umbraco.Web.Routing public class AliasUrlProvider : IUrlProvider { private readonly IGlobalSettings _globalSettings; - private readonly IRequestHandlerSection _requestConfig; - private readonly ILocalizationService _localizationService; + private readonly IRequestHandlerSection _requestConfig; private readonly ISiteDomainHelper _siteDomainHelper; - public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSection requestConfig, ILocalizationService localizationService, ISiteDomainHelper siteDomainHelper) + public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSection requestConfig, ISiteDomainHelper siteDomainHelper) { _globalSettings = globalSettings; - _requestConfig = requestConfig; - _localizationService = localizationService; + _requestConfig = requestConfig; _siteDomainHelper = siteDomainHelper; } @@ -35,20 +30,8 @@ namespace Umbraco.Web.Routing #region GetUrl - /// - /// Gets the nice url of a published content. - /// - /// The Umbraco context. - /// The published content id. - /// The current absolute url. - /// The url mode. - /// The url for the published content. - /// - /// The url is absolute or relative depending on url indicated by current and settings, unless - /// absolute is true, in which case the url is always absolute. - /// If the provider is unable to provide a url, it should return null. - /// - public string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode, string culture = null) + /// + public string GetUrl(UmbracoContext umbracoContext, IPublishedContent content, UrlProviderMode mode, string culture, Uri current) { return null; // we have nothing to say } diff --git a/src/Umbraco.Web/Routing/CustomRouteUrlProvider.cs b/src/Umbraco.Web/Routing/CustomRouteUrlProvider.cs index 926db253c8..893445add6 100644 --- a/src/Umbraco.Web/Routing/CustomRouteUrlProvider.cs +++ b/src/Umbraco.Web/Routing/CustomRouteUrlProvider.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Globalization; +using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Routing { @@ -14,25 +14,15 @@ namespace Umbraco.Web.Routing /// /// This will simply return the URL that is returned by the assigned IPublishedContent if this is a custom route /// - /// - /// - /// - /// - /// - public string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode, string culture = null) + public string GetUrl(UmbracoContext umbracoContext, IPublishedContent content, UrlProviderMode mode, string culture, Uri current) { - if (umbracoContext == null) return null; - if (umbracoContext.PublishedRequest == null) return null; - if (umbracoContext.PublishedRequest.PublishedContent == null) return null; - if (umbracoContext.HttpContext == null) return null; - if (umbracoContext.HttpContext.Request == null) return null; - if (umbracoContext.HttpContext.Request.RequestContext == null) return null; - if (umbracoContext.HttpContext.Request.RequestContext.RouteData == null) return null; - if (umbracoContext.HttpContext.Request.RequestContext.RouteData.DataTokens == null) return null; - if (umbracoContext.HttpContext.Request.RequestContext.RouteData.DataTokens.ContainsKey(Umbraco.Core.Constants.Web.CustomRouteDataToken) == false) return null; + if (umbracoContext?.PublishedRequest?.PublishedContent == null) return null; + if (umbracoContext.HttpContext?.Request?.RequestContext?.RouteData?.DataTokens == null) return null; + if (umbracoContext.HttpContext.Request.RequestContext.RouteData.DataTokens.ContainsKey(Core.Constants.Web.CustomRouteDataToken) == false) return null; + //ok so it's a custom route with published content assigned, check if the id being requested for is the same id as the assigned published content - return id == umbracoContext.PublishedRequest.PublishedContent.Id - ? umbracoContext.PublishedRequest.PublishedContent.Url + return content.Id == umbracoContext.PublishedRequest.PublishedContent.Id + ? umbracoContext.PublishedRequest.PublishedContent.GetUrl(culture) // fixme ∞ loop. : null; } diff --git a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs index 37d38d521e..366bcd865f 100644 --- a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs @@ -1,14 +1,11 @@ using System; 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; -using Umbraco.Core.Models.PublishedContent; - +using Umbraco.Core.Models.PublishedContent; + namespace Umbraco.Web.Routing { /// @@ -31,27 +28,15 @@ namespace Umbraco.Web.Routing #region GetUrl - /// - /// Gets the url of a published content. - /// - /// The Umbraco context. - /// The published content id. - /// The current absolute url. - /// The url mode. - /// The culture. - /// The url for the published content. - /// - /// The url is absolute or relative depending on mode and on current. - /// If the provider is unable to provide a url, it should return null. - /// - public virtual string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode, string culture = null) + /// + public virtual string GetUrl(UmbracoContext umbracoContext, IPublishedContent content, UrlProviderMode mode, string culture, Uri current) { if (!current.IsAbsoluteUri) throw new ArgumentException("Current url must be absolute.", nameof(current)); - + // will not use cache if previewing - var route = umbracoContext.ContentCache.GetRouteById(id, culture); + var route = umbracoContext.ContentCache.GetRouteById(content.Id, culture); - return GetUrlFromRoute(route, umbracoContext, id, current, mode, culture); + return GetUrlFromRoute(route, umbracoContext, content.Id, current, mode, culture); } internal string GetUrlFromRoute(string route, UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode, string culture) diff --git a/src/Umbraco.Web/Routing/IUrlProvider.cs b/src/Umbraco.Web/Routing/IUrlProvider.cs index 031f4670b2..53a7e9886c 100644 --- a/src/Umbraco.Web/Routing/IUrlProvider.cs +++ b/src/Umbraco.Web/Routing/IUrlProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Globalization; -using Umbraco.Web.PublishedCache; +using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Routing { @@ -14,16 +13,18 @@ namespace Umbraco.Web.Routing /// Gets the nice url of a published content. /// /// The Umbraco context. - /// The published content id. - /// The current absolute url. + /// The published content. /// The url mode. + /// A culture. + /// The current absolute url. /// The url for the published content. /// /// The url is absolute or relative depending on mode and on current. + /// If the published content is multi-lingual, gets the url for the specified culture or, + /// when no culture is specified, the current culture. /// If the provider is unable to provide a url, it should return null. /// - string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode, string culture = null); - // FIXME WE HAVE TO DOCUMENT CULTURE FFS + string GetUrl(UmbracoContext umbracoContext, IPublishedContent content, UrlProviderMode mode, string culture, Uri current); /// /// Gets the other urls of a published content. diff --git a/src/Umbraco.Web/Routing/UrlProvider.cs b/src/Umbraco.Web/Routing/UrlProvider.cs index c23ff5fb86..b8c28814b5 100644 --- a/src/Umbraco.Web/Routing/UrlProvider.cs +++ b/src/Umbraco.Web/Routing/UrlProvider.cs @@ -1,15 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Web.PublishedCache; using Umbraco.Core; using Umbraco.Core.Models; -using Umbraco.Web.Composing; -using Umbraco.Core.Services; -using System.Globalization; - +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Services; + namespace Umbraco.Web.Routing { /// @@ -57,7 +54,8 @@ namespace Umbraco.Web.Routing private readonly UmbracoContext _umbracoContext; private readonly IEnumerable _urlProviders; - private readonly IEntityService _entityService; + private readonly IEntityService _entityService; + private readonly ICurrentVariationAccessor _variationAccessor; // fixme set! /// /// Gets or sets the provider url mode. @@ -68,150 +66,149 @@ namespace Umbraco.Web.Routing #region GetUrl + private UrlProviderMode GetMode(bool absolute) => absolute ? UrlProviderMode.Absolute : Mode; + private IPublishedContent GetDocument(int id) => _umbracoContext.ContentCache.GetById(id); + private IPublishedContent GetDocument(Guid id) => _umbracoContext.ContentCache.GetById(id); + /// /// Gets the url of a published content. /// - /// The published content identifier. - /// The url for the published content. - /// - /// The url is absolute or relative depending on Mode and on the current url. - /// If the provider is unable to provide a url, it returns "#". - /// - public string GetUrl(Guid id, string culture = null) - { - var intId = _entityService.GetId(id, UmbracoObjectTypes.Document); - return GetUrl(intId.Success ? intId.Result : -1, culture); - } - - /// - /// Gets the nice url of a published content. - /// - /// The published content identifier. - /// A value indicating whether the url should be absolute in any case. - /// The url for the published content. - /// - /// The url is absolute or relative depending on Mode and on current, unless - /// absolute is true, in which case the url is always absolute. - /// If the provider is unable to provide a url, it returns "#". - /// - public string GetUrl(Guid id, bool absolute, string culture = null) - { - var intId = _entityService.GetId(id, UmbracoObjectTypes.Document); - return GetUrl(intId.Success ? intId.Result : -1, absolute, culture); - } - - /// - /// Gets the nice url of a published content. - /// - /// The published content id. + /// The published content. + /// A culture. /// The current absolute url. - /// A value indicating whether the url should be absolute in any case. /// The url for the published content. - /// - /// The url is absolute or relative depending on Mode and on current, unless - /// absolute is true, in which case the url is always absolute. - /// If the provider is unable to provide a url, it returns "#". - /// - public string GetUrl(Guid id, Uri current, bool absolute, string culture = null) - { - var intId = _entityService.GetId(id, UmbracoObjectTypes.Document); - return GetUrl(intId.Success ? intId.Result : -1, current, absolute, culture); - } + public string GetUrl(IPublishedContent content, string culture = ".", Uri current = null) + => GetUrl(content, Mode, culture, current); /// /// Gets the nice url of a published content. /// - /// The published content identifier. - /// The url mode. + /// The published content. + /// A value indicating whether the url should be absolute in any case. + /// A culture. + /// The current absolute url. /// The url for the published content. /// - /// The url is absolute or relative depending on mode and on the current url. - /// If the provider is unable to provide a url, it returns "#". + /// The url is absolute or relative depending on Mode and on current, unless + /// absolute is true, in which case the url is always absolute. /// - public string GetUrl(Guid id, UrlProviderMode mode, string culture = null) - { - var intId = _entityService.GetId(id, UmbracoObjectTypes.Document); - return GetUrl(intId.Success ? intId.Result : -1, mode, culture); - } + public string GetUrl(IPublishedContent content, bool absolute, Uri current = null, string culture = ".") + => GetUrl(content, GetMode(absolute), culture, current); + + /// + /// Gets the nice url of a published content. + /// + /// The published content. + /// The url mode. + /// A culture. + /// The current absolute url. + /// The url for the published content. + public string GetUrl(IPublishedContent content, UrlProviderMode mode, Uri current = null, string culture = ".") + => GetUrl(content, mode, culture, current); /// /// Gets the url of a published content. /// /// The published content identifier. + /// A culture. + /// The current absolute url. /// The url for the published content. - /// - /// The url is absolute or relative depending on Mode and on the current url. - /// If the provider is unable to provide a url, it returns "#". - /// - public string GetUrl(int id, string culture = null) - { - return GetUrl(id, _umbracoContext.CleanedUmbracoUrl, Mode, culture); - } + public string GetUrl(Guid id, string culture = ".", Uri current = null) + => GetUrl(GetDocument(id), Mode, culture, current); /// /// Gets the nice url of a published content. /// /// The published content identifier. /// A value indicating whether the url should be absolute in any case. - /// The url for the published content. - /// - /// The url is absolute or relative depending on Mode and on current, unless - /// absolute is true, in which case the url is always absolute. - /// If the provider is unable to provide a url, it returns "#". - /// - public string GetUrl(int id, bool absolute, string culture = null) - { - var mode = absolute ? UrlProviderMode.Absolute : Mode; - return GetUrl(id, _umbracoContext.CleanedUmbracoUrl, mode, culture); - } - - /// - /// Gets the nice url of a published content. - /// - /// The published content id. + /// A culture. /// The current absolute url. - /// A value indicating whether the url should be absolute in any case. /// The url for the published content. /// /// The url is absolute or relative depending on Mode and on current, unless /// absolute is true, in which case the url is always absolute. - /// If the provider is unable to provide a url, it returns "#". /// - public string GetUrl(int id, Uri current, bool absolute, string culture = null) - { - var mode = absolute ? UrlProviderMode.Absolute : Mode; - return GetUrl(id, current, mode, culture); - } + public string GetUrl(Guid id, bool absolute, string culture = ".", Uri current = null) + => GetUrl(GetDocument(id), GetMode(absolute), culture, current); /// /// Gets the nice url of a published content. /// /// The published content identifier. /// The url mode. + /// A culture. + /// The current absolute url. /// The url for the published content. - /// - /// The url is absolute or relative depending on mode and on the current url. - /// If the provider is unable to provide a url, it returns "#". - /// - public string GetUrl(int id, UrlProviderMode mode, string culture = null) - { - return GetUrl(id, _umbracoContext.CleanedUmbracoUrl, mode, culture); - } + public string GetUrl(Guid id, UrlProviderMode mode, string culture = ".", Uri current = null) + => GetUrl(GetDocument(id), mode, culture, current); + + /// + /// Gets the url of a published content. + /// + /// The published content identifier. + /// A culture. + /// The current absolute url. + /// The url for the published content. + public string GetUrl(int id, string culture = ".", Uri current = null) + => GetUrl(GetDocument(id), Mode, culture, current); /// /// Gets the nice url of a published content. /// - /// The published content id. + /// The published content identifier. + /// A value indicating whether the url should be absolute in any case. + /// A culture. /// The current absolute url. + /// The url for the published content. + /// + /// The url is absolute or relative depending on Mode and on current, unless + /// absolute is true, in which case the url is always absolute. + /// + public string GetUrl(int id, bool absolute, string culture = ".", Uri current = null) + => GetUrl(GetDocument(id), GetMode(absolute), culture, current); + + /// + /// Gets the nice url of a published content. + /// + /// The published content identifier. /// The url mode. + /// A culture. + /// The current absolute url. + /// The url for the published content. + public string GetUrl(int id, UrlProviderMode mode, string culture = ".", Uri current = null) + => GetUrl(GetDocument(id), mode, culture, current); + + /// + /// Gets the nice url of a published content. + /// + /// The published content. + /// The url mode. + /// A culture. + /// The current absolute url. /// The url for the published content. /// /// The url is absolute or relative depending on mode and on current. + /// If the published content is multi-lingual, gets the url for the specified culture or, + /// when no culture is specified, the current culture. /// If the provider is unable to provide a url, it returns "#". /// - public string GetUrl(int id, Uri current, UrlProviderMode mode, string culture = null) // FIXME DOCUMENT + public string GetUrl(IPublishedContent content, UrlProviderMode mode, string culture = ".", Uri current = null) { - var url = _urlProviders.Select(provider => provider.GetUrl(_umbracoContext, id, current, mode, culture)) + if (content == null) + return "#"; + + // this the ONLY place where we deal with default culture - IUrlProvider always receive a culture + if (culture == ".") + { + culture = content.ContentType.Variations.Has(ContentVariation.CultureNeutral) // fixme CultureSegment + ? _variationAccessor.CurrentVariation.Culture + : null; + } + + if (current == null) + current = _umbracoContext.CleanedUmbracoUrl; + + var url = _urlProviders.Select(provider => provider.GetUrl(_umbracoContext, content, mode, culture, current)) .FirstOrDefault(u => u != null); return url ?? "#"; // legacy wants this } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 41d4d4883c..bd5acab5de 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -71,9 +71,8 @@ namespace Umbraco.Web.Runtime composition.Container.RegisterFrom(); // register accessors for cultures - // fixme merge the two accessors? composition.Container.RegisterSingleton(); - composition.Container.RegisterSingleton(); + composition.Container.RegisterSingleton(); var typeLoader = composition.Container.GetInstance(); var logger = composition.Container.GetInstance(); diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index f65f04fb76..f7660987ea 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -108,8 +108,8 @@ namespace umbraco /// /// The content. /// This is for usage only. - internal page(IContent content, IPublishedVariationContextAccessor variationContextAccessor) - : this(new PagePublishedContent(content, variationContextAccessor)) + internal page(IContent content, ICurrentVariationAccessor variationAccessor) + : this(new PagePublishedContent(content, variationAccessor)) { } #endregion @@ -409,7 +409,7 @@ namespace umbraco private readonly IPublishedProperty[] _properties; private readonly IPublishedContent _parent; private IReadOnlyDictionary _cultureInfos; - private readonly IPublishedVariationContextAccessor _variationContextAccessor; + private readonly ICurrentVariationAccessor _variationAccessor; private static readonly IReadOnlyDictionary NoCultureInfos = new Dictionary(); @@ -418,13 +418,13 @@ namespace umbraco _id = id; } - public PagePublishedContent(IContent inner, IPublishedVariationContextAccessor variationContextAccessor) + public PagePublishedContent(IContent inner, ICurrentVariationAccessor variationAccessor) { if (inner == null) throw new NullReferenceException("content"); _inner = inner; - _variationContextAccessor = variationContextAccessor; + _variationAccessor = variationAccessor; _id = _inner.Id; _key = _inner.Key; @@ -480,7 +480,7 @@ namespace umbraco { // handle context culture if (culture == ".") - culture = _variationContextAccessor.Context.Culture; + culture = _variationAccessor.CurrentVariation.Culture; // no invariant culture infos if (culture == null) return null; @@ -564,6 +564,8 @@ namespace umbraco get { throw new NotImplementedException(); } } + public string GetUrl(string culture = ".") => throw new NotSupportedException(); + public PublishedItemType ItemType { get { return PublishedItemType.Content; }