From 65f15125e1de62c420de4f951e480330df1a2482 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 16 Feb 2016 11:48:09 +0100 Subject: [PATCH 1/5] U4-7939 - fix routes cache --- src/Umbraco.Tests/Routing/RoutesCacheTests.cs | 42 +++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + .../PublishedContentCache.cs | 18 ++++---- 3 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 src/Umbraco.Tests/Routing/RoutesCacheTests.cs diff --git a/src/Umbraco.Tests/Routing/RoutesCacheTests.cs b/src/Umbraco.Tests/Routing/RoutesCacheTests.cs new file mode 100644 index 0000000000..80bdcb3b7f --- /dev/null +++ b/src/Umbraco.Tests/Routing/RoutesCacheTests.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using Umbraco.Tests.TestHelpers; +using Umbraco.Web.PublishedCache.XmlPublishedCache; + +namespace Umbraco.Tests.Routing +{ + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerFixture)] + [TestFixture] + public class RoutesCacheTests : BaseRoutingTest + { + [Test] + public void U4_7939() + { + //var routingContext = GetRoutingContext("/test", 1111); + var umbracoContext = GetUmbracoContext("/test", 0); + var cache = umbracoContext.ContentCache.InnerCache as PublishedContentCache; + if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + + PublishedContentCache.UnitTesting = false; // else does not write to routes cache + Assert.IsFalse(PublishedContentCache.UnitTesting); + + var z = cache.GetByRoute(umbracoContext, false, "/home/sub1"); + Assert.IsNotNull(z); + Assert.AreEqual(1173, z.Id); + + var routes = cache.RoutesCache.GetCachedRoutes(); + Assert.AreEqual(1, routes.Count); + + // before the fix, the following assert would fail because the route would + // have been stored as { 0, "/home/sub1" } - essentially meaning we were NOT + // storing anything in the route cache! + + Assert.AreEqual(1173, routes.Keys.First()); + Assert.AreEqual("/home/sub1", routes.Values.First()); + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index dc466c11f2..223ea33faa 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -192,6 +192,7 @@ + diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index 71c27f2bee..d16133f170 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -57,12 +57,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache if (content != null && preview == false) { var domainRootNodeId = route.StartsWith("/") ? -1 : int.Parse(route.Substring(0, route.IndexOf('/'))); - var iscanon = - UnitTesting == false + var iscanon = + UnitTesting == false && DomainHelper.ExistsDomainInPath(umbracoContext.Application.Services.DomainService.GetAll(false), content.Path, domainRootNodeId) == false; // and only if this is the canonical url (the one GetUrl would return) if (iscanon) - _routesCache.Store(contentId, route); + _routesCache.Store(content.Id, route); } return content; @@ -159,7 +159,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // we add this check - we look for the document matching "/" and if it's not us, then // we do not hide the top level path // it has to be taken care of in GetByRoute too so if - // "/foo" fails (looking for "/*/foo") we try also "/foo". + // "/foo" fails (looking for "/*/foo") we try also "/foo". // this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but // that's the way it works pre-4.10 and we try to be backward compat for the time being if (node.Parent == null) @@ -244,8 +244,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private static IPublishedContent ConvertToDocument(XmlNode xmlNode, bool isPreviewing) { - return xmlNode == null - ? null + return xmlNode == null + ? null : (new XmlPublishedContent(xmlNode, isPreviewing)).CreateModel(); } @@ -398,7 +398,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache if (startNodeId > 0) { // if in a domain then use the root node of the domain - xpath = string.Format(XPathStringsDefinition.Root + XPathStrings.DescendantDocumentById, startNodeId); + xpath = string.Format(XPathStringsDefinition.Root + XPathStrings.DescendantDocumentById, startNodeId); } else { @@ -409,7 +409,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // umbraco does not consistently guarantee that sortOrder starts with 0 // so the one that we want is the one with the smallest sortOrder // read http://stackoverflow.com/questions/1128745/how-can-i-use-xpath-to-find-the-minimum-value-of-an-attribute-in-a-set-of-elemen - + // so that one does not work, because min(@sortOrder) maybe 1 // xpath = "/root/*[@isDoc and @sortOrder='0']"; @@ -453,7 +453,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache else { xpathBuilder.AppendFormat(XPathStrings.ChildDocumentByUrlName, part); - + } } From 180099b71864297b7634b801fa189420f6b1172b Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 16 Feb 2016 11:52:16 +0100 Subject: [PATCH 2/5] U4-7890 XSLT Macro's not working - "Cannot use this obsoleted overload when the current provider" --- .../Cache/DeepCloneRuntimeCacheProvider.cs | 12 ++++++++-- src/Umbraco.Core/CacheHelper.cs | 24 +++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs index 861c6b803e..0ae721943d 100644 --- a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs @@ -7,14 +7,22 @@ using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Cache { + /// + /// Interface describing this cache provider as a wrapper for another + /// + internal interface IRuntimeCacheProviderWrapper + { + IRuntimeCacheProvider InnerProvider { get; } + } + /// /// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns /// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are /// reset if the object is TracksChangesEntityBase /// - internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider + internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper { - internal IRuntimeCacheProvider InnerProvider { get; private set; } + public IRuntimeCacheProvider InnerProvider { get; private set; } public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider) { diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs index 4b009e5f86..0dc5f5b00f 100644 --- a/src/Umbraco.Core/CacheHelper.cs +++ b/src/Umbraco.Core/CacheHelper.cs @@ -290,7 +290,7 @@ namespace Umbraco.Core TimeSpan timeout, Func getCacheItem) { - var cache = RuntimeCache as HttpRuntimeCacheProvider; + var cache = GetHttpRuntimeCacheProvider(RuntimeCache); if (cache != null) { var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); @@ -314,7 +314,7 @@ namespace Umbraco.Core CacheDependency cacheDependency, Func getCacheItem) { - var cache = RuntimeCache as HttpRuntimeCacheProvider; + var cache = GetHttpRuntimeCacheProvider(RuntimeCache); if (cache != null) { var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); @@ -374,7 +374,7 @@ namespace Umbraco.Core TimeSpan timeout, Func getCacheItem) { - var cache = RuntimeCache as HttpRuntimeCacheProvider; + var cache = GetHttpRuntimeCacheProvider(RuntimeCache); if (cache != null) { cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); @@ -400,7 +400,7 @@ namespace Umbraco.Core TimeSpan? timeout, Func getCacheItem) { - var cache = RuntimeCache as HttpRuntimeCacheProvider; + var cache = GetHttpRuntimeCacheProvider(RuntimeCache); if (cache != null) { cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); @@ -409,6 +409,20 @@ namespace Umbraco.Core } #endregion - } + private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache) + { + HttpRuntimeCacheProvider cache; + var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper; + if (wrapper != null) + { + cache = wrapper.InnerProvider as HttpRuntimeCacheProvider; + } + else + { + cache = RuntimeCache as HttpRuntimeCacheProvider; + } + return cache; + } + } } From 6373add38320000b7fe3d7305946da95b6003bfa Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 16 Feb 2016 11:53:54 +0100 Subject: [PATCH 3/5] U4-7922 Preview is not working --- src/Umbraco.Web/UmbracoContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index fca5ff2371..50788c4b2e 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -133,7 +133,7 @@ namespace Umbraco.Web UmbracoContext.Current._replacing = true; } - var umbracoContext = CreateContext(httpContext, applicationContext, webSecurity, umbracoSettings, urlProviders, preview ?? false); + var umbracoContext = CreateContext(httpContext, applicationContext, webSecurity, umbracoSettings, urlProviders, preview); //assign the singleton UmbracoContext.Current = umbracoContext; @@ -158,7 +158,7 @@ namespace Umbraco.Web WebSecurity webSecurity, IUmbracoSettingsSection umbracoSettings, IEnumerable urlProviders, - bool preview) + bool? preview) { if (httpContext == null) throw new ArgumentNullException("httpContext"); if (applicationContext == null) throw new ArgumentNullException("applicationContext"); From cc5ac1a84ca34f30685826bb2dcc431365b6f06d Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 16 Feb 2016 11:57:10 +0100 Subject: [PATCH 4/5] bumps version --- build/UmbracoVersion.txt | 2 +- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Core/Configuration/UmbracoVersion.cs | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/UmbracoVersion.txt b/build/UmbracoVersion.txt index 98c72aa6f5..78441cfcd1 100644 --- a/build/UmbracoVersion.txt +++ b/build/UmbracoVersion.txt @@ -1,2 +1,2 @@ # Usage: on line 2 put the release version, on line 3 put the version comment (example: beta) -7.3.7 \ No newline at end of file +7.3.8 \ No newline at end of file diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 8b9c5bf06a..48307e172a 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -11,5 +11,5 @@ using System.Resources; [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("7.3.7")] -[assembly: AssemblyInformationalVersion("7.3.7")] \ No newline at end of file +[assembly: AssemblyFileVersion("7.3.8")] +[assembly: AssemblyInformationalVersion("7.3.8")] \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index c67619f588..f931bc9e90 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("7.3.7"); + private static readonly Version Version = new Version("7.3.8"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 720a36a554..f172fa6657 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2414,9 +2414,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" True True - 7360 + 7380 / - http://localhost:7370 + http://localhost:7380 False False From 82297a6ff11c90e22fa3687871e8022e664f6db4 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 16 Feb 2016 13:23:37 +0100 Subject: [PATCH 5/5] U4-7929 Label datatype strips leading zeros --- .../ValueConverters/LabelValueConverter.cs | 28 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + 2 files changed, 29 insertions(+) create mode 100644 src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs new file mode 100644 index 0000000000..cf034c8c29 --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -0,0 +1,28 @@ +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Core.PropertyEditors.ValueConverters +{ + /// + /// We need this property converter so that we always force the value of a label to be a string + /// + /// + /// Without a property converter defined for the label type, the value will be converted with + /// the `ConvertUsingDarkMagic` method which will try to parse the value into it's correct type, but this + /// can cause issues if the string is detected as a number and then strips leading zeros. + /// Example: http://issues.umbraco.org/issue/U4-7929 + /// + [DefaultPropertyValueConverter] + [PropertyValueType(typeof (string))] + [PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)] + public class LabelValueConverter : PropertyValueConverterBase + { + public override bool IsConverter(PublishedPropertyType propertyType) + { + return Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias); + } + public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) + { + return source == null ? string.Empty : source.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 49eaa8a629..c482466749 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -472,6 +472,7 @@ +