From 5c7bf075e66e154a038c78d5cfd3f07c27cfc4a5 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Thu, 12 Aug 2021 19:28:48 +0100 Subject: [PATCH 01/24] Backport fix for #10774 to v8 Call EnsureCaches on all notify handlers in PublishedSnapshotService. No need to delete NuCache database files. --- .../NuCache/PublishedSnapshotService.cs | 50 ++----------------- 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 73d06db12b..0e98112fc1 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -347,28 +347,6 @@ namespace Umbraco.Web.PublishedCache.NuCache return path; } - private void DeleteLocalFilesForContent() - { - if (_isReady && _localContentDb != null) - throw new InvalidOperationException("Cannot delete local files while the cache uses them."); - - var path = GetLocalFilesPath(); - var localContentDbPath = Path.Combine(path, "NuCache.Content.db"); - if (File.Exists(localContentDbPath)) - File.Delete(localContentDbPath); - } - - private void DeleteLocalFilesForMedia() - { - if (_isReady && _localMediaDb != null) - throw new InvalidOperationException("Cannot delete local files while the cache uses them."); - - var path = GetLocalFilesPath(); - var localMediaDbPath = Path.Combine(path, "NuCache.Media.db"); - if (File.Exists(localMediaDbPath)) - File.Delete(localMediaDbPath); - } - #endregion #region Environment @@ -685,13 +663,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) { - // no cache, trash everything - if (_isReady == false) - { - DeleteLocalFilesForContent(); - draftChanged = publishedChanged = true; - return; - } + EnsureCaches(); using (_contentStore.GetScopedWriteLock(_scopeProvider)) { @@ -785,13 +757,7 @@ namespace Umbraco.Web.PublishedCache.NuCache /// public override void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) { - // no cache, trash everything - if (_isReady == false) - { - DeleteLocalFilesForMedia(); - anythingChanged = true; - return; - } + EnsureCaches(); using (_mediaStore.GetScopedWriteLock(_scopeProvider)) { @@ -878,9 +844,7 @@ namespace Umbraco.Web.PublishedCache.NuCache /// public override void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) { - // no cache, nothing we can do - if (_isReady == false) - return; + EnsureCaches(); foreach (var payload in payloads) _logger.Debug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id); @@ -960,9 +924,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) { - // no cache, nothing we can do - if (_isReady == false) - return; + EnsureCaches(); var idsA = payloads.Select(x => x.Id).ToArray(); @@ -1000,9 +962,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(DomainCacheRefresher.JsonPayload[] payloads) { - // no cache, nothing we can do - if (_isReady == false) - return; + EnsureCaches(); // see note in LockAndLoadContent using (_domainStore.GetScopedWriteLock(_scopeProvider)) From 42c59a91cafb4acb0bd12a7a4efae7314ac310dd Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 Aug 2021 11:14:27 +0200 Subject: [PATCH 02/24] Bump version to 8.16.0 --- src/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 56e0376196..156b91187f 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("8.16.0")] -[assembly: AssemblyInformationalVersion("8.16.0-rc")] +[assembly: AssemblyInformationalVersion("8.16.0")] From a2dab5b6caaf55e221fbbdea5b021c6d343c0000 Mon Sep 17 00:00:00 2001 From: Chad Date: Tue, 24 Aug 2021 00:44:48 +1200 Subject: [PATCH 03/24] DIspose Process (#10918) --- src/Umbraco.Core/Diagnostics/MiniDump.cs | 28 ++++++++++--------- src/Umbraco.Core/Persistence/LocalDb.cs | 17 ++++++----- .../Sync/DatabaseServerMessenger.cs | 10 ++++++- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Core/Diagnostics/MiniDump.cs b/src/Umbraco.Core/Diagnostics/MiniDump.cs index e8c2e82f94..ca9596b4ae 100644 --- a/src/Umbraco.Core/Diagnostics/MiniDump.cs +++ b/src/Umbraco.Core/Diagnostics/MiniDump.cs @@ -79,24 +79,26 @@ namespace Umbraco.Core.Diagnostics private static bool Write(SafeHandle fileHandle, Option options, bool withException = false) { - var currentProcess = Process.GetCurrentProcess(); - var currentProcessHandle = currentProcess.Handle; - var currentProcessId = (uint)currentProcess.Id; + using (var currentProcess = Process.GetCurrentProcess()) + { + var currentProcessHandle = currentProcess.Handle; + var currentProcessId = (uint)currentProcess.Id; - MiniDumpExceptionInformation exp; + MiniDumpExceptionInformation exp; - exp.ThreadId = GetCurrentThreadId(); - exp.ClientPointers = false; - exp.ExceptionPointers = IntPtr.Zero; + exp.ThreadId = GetCurrentThreadId(); + exp.ClientPointers = false; + exp.ExceptionPointers = IntPtr.Zero; - if (withException) - exp.ExceptionPointers = Marshal.GetExceptionPointers(); + if (withException) + exp.ExceptionPointers = Marshal.GetExceptionPointers(); - var bRet = exp.ExceptionPointers == IntPtr.Zero - ? MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) - : MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, ref exp, IntPtr.Zero, IntPtr.Zero); + var bRet = exp.ExceptionPointers == IntPtr.Zero + ? MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint)options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) + : MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint)options, ref exp, IntPtr.Zero, IntPtr.Zero); - return bRet; + return bRet; + } } public static bool Dump(Option options = Option.WithFullMemory, bool withException = false) diff --git a/src/Umbraco.Core/Persistence/LocalDb.cs b/src/Umbraco.Core/Persistence/LocalDb.cs index 55d6565344..0e1da4c0d1 100644 --- a/src/Umbraco.Core/Persistence/LocalDb.cs +++ b/src/Umbraco.Core/Persistence/LocalDb.cs @@ -901,7 +901,7 @@ namespace Umbraco.Core.Persistence return -1; } - var p = new Process + using (var p = new Process { StartInfo = { @@ -913,13 +913,16 @@ namespace Umbraco.Core.Persistence CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden } - }; - p.Start(); - output = p.StandardOutput.ReadToEnd(); - error = p.StandardError.ReadToEnd(); - p.WaitForExit(); + }) + { + p.Start(); + output = p.StandardOutput.ReadToEnd(); + error = p.StandardError.ReadToEnd(); + p.WaitForExit(); - return p.ExitCode; + return p.ExitCode; + } + } /// diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs index 75ccf5e4f9..1cfca49160 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs @@ -535,10 +535,18 @@ namespace Umbraco.Core.Sync /// protected static readonly string LocalIdentity = NetworkHelper.MachineName // eg DOMAIN\SERVER + "/" + HttpRuntime.AppDomainAppId // eg /LM/S3SVC/11/ROOT - + " [P" + Process.GetCurrentProcess().Id // eg 1234 + + " [P" + GetProcessId() // eg 1234 + "/D" + AppDomain.CurrentDomain.Id // eg 22 + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique + private static int GetProcessId() + { + using(var p = Process.GetCurrentProcess()) + { + return p.Id; + } + } + private string GetDistCacheFilePath(IGlobalSettings globalSettings) { var fileName = HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt"; From dcc533fd8dba44bb4cd7feebd609bed40fe7d271 Mon Sep 17 00:00:00 2001 From: Chad Currie Date: Sun, 22 Aug 2021 15:40:44 +1200 Subject: [PATCH 04/24] Update Serilog.Enrichers.Process to 2.0.2 as it fixes a leak --- build/NuSpecs/UmbracoCms.Core.nuspec | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index c94def143b..a55eff33a9 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -33,7 +33,7 @@ - + diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 146197c4f8..7a65d75578 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -97,7 +97,7 @@ 2.10.0 - 2.0.1 + 2.0.2 3.1.0 From cd6cb3737e54118d83fd3d76fe750e2689620a8a Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 Aug 2021 14:48:49 +0200 Subject: [PATCH 05/24] Cannot copy page with Block List block with property that 'looks like' JSON #10879 (#10925) --- .../Compose/BlockEditorComponent.cs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Compose/BlockEditorComponent.cs b/src/Umbraco.Web/Compose/BlockEditorComponent.cs index a8b4cfb8ca..ac92aa6918 100644 --- a/src/Umbraco.Web/Compose/BlockEditorComponent.cs +++ b/src/Umbraco.Web/Compose/BlockEditorComponent.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Logging; using Umbraco.Core.Models.Blocks; using Umbraco.Core.PropertyEditors; @@ -17,6 +18,17 @@ namespace Umbraco.Web.Compose { private ComplexPropertyEditorContentEventHandler _handler; private readonly BlockListEditorDataConverter _converter = new BlockListEditorDataConverter(); + private readonly ILogger _logger; + + [Obsolete("Use the ctor injecting dependencies.")] + public BlockEditorComponent() : this(Current.Logger) + { + } + + public BlockEditorComponent(ILogger logger) + { + _logger = logger; + } public void Initialize() { @@ -116,8 +128,23 @@ namespace Umbraco.Web.Compose // this gets a little ugly because there could be some other complex editor that contains another block editor // and since we would have no idea how to parse that, all we can do is try JSON Path to find another block editor // of our type - var json = JToken.Parse(asString); - if (ProcessJToken(json, createGuid, out var result)) + JToken json = null; + try + { + json = JToken.Parse(asString); + } + catch (Exception e) + { + // See issue https://github.com/umbraco/Umbraco-CMS/issues/10879 + // We are detecting JSON data by seeing if a string is surrounded by [] or {} + // If people enter text like [PLACEHOLDER] JToken parsing fails, it's safe to ignore though + // Logging this just in case in the future we find values that are not safe to ignore + _logger.Warn( + "The property {PropertyAlias} on content type {ContentTypeKey} has a value of: {BlockItemValue} - this was recognized as JSON but could not be parsed", + data.Key, propertyAliasToBlockItemData.Key, asString); + } + + if (json != null && ProcessJToken(json, createGuid, out var result)) { // need to re-save this back to the RawPropertyValues data.RawPropertyValues[propertyAliasToBlockItemData.Key] = result; From 82fc05ac5125add0ae5f02ccdbfef2ddc073ff37 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 Aug 2021 14:48:49 +0200 Subject: [PATCH 06/24] Cannot copy page with Block List block with property that 'looks like' JSON #10879 (#10925) (cherry picked from commit cd6cb3737e54118d83fd3d76fe750e2689620a8a) --- .../Compose/BlockEditorComponent.cs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Compose/BlockEditorComponent.cs b/src/Umbraco.Web/Compose/BlockEditorComponent.cs index a8b4cfb8ca..ac92aa6918 100644 --- a/src/Umbraco.Web/Compose/BlockEditorComponent.cs +++ b/src/Umbraco.Web/Compose/BlockEditorComponent.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Logging; using Umbraco.Core.Models.Blocks; using Umbraco.Core.PropertyEditors; @@ -17,6 +18,17 @@ namespace Umbraco.Web.Compose { private ComplexPropertyEditorContentEventHandler _handler; private readonly BlockListEditorDataConverter _converter = new BlockListEditorDataConverter(); + private readonly ILogger _logger; + + [Obsolete("Use the ctor injecting dependencies.")] + public BlockEditorComponent() : this(Current.Logger) + { + } + + public BlockEditorComponent(ILogger logger) + { + _logger = logger; + } public void Initialize() { @@ -116,8 +128,23 @@ namespace Umbraco.Web.Compose // this gets a little ugly because there could be some other complex editor that contains another block editor // and since we would have no idea how to parse that, all we can do is try JSON Path to find another block editor // of our type - var json = JToken.Parse(asString); - if (ProcessJToken(json, createGuid, out var result)) + JToken json = null; + try + { + json = JToken.Parse(asString); + } + catch (Exception e) + { + // See issue https://github.com/umbraco/Umbraco-CMS/issues/10879 + // We are detecting JSON data by seeing if a string is surrounded by [] or {} + // If people enter text like [PLACEHOLDER] JToken parsing fails, it's safe to ignore though + // Logging this just in case in the future we find values that are not safe to ignore + _logger.Warn( + "The property {PropertyAlias} on content type {ContentTypeKey} has a value of: {BlockItemValue} - this was recognized as JSON but could not be parsed", + data.Key, propertyAliasToBlockItemData.Key, asString); + } + + if (json != null && ProcessJToken(json, createGuid, out var result)) { // need to re-save this back to the RawPropertyValues data.RawPropertyValues[propertyAliasToBlockItemData.Key] = result; From d085b117524033d4293cb449ebd1667a7c2319d4 Mon Sep 17 00:00:00 2001 From: Chad Date: Tue, 24 Aug 2021 00:44:48 +1200 Subject: [PATCH 07/24] DIspose Process (#10918) (cherry picked from commit a2dab5b6caaf55e221fbbdea5b021c6d343c0000) --- src/Umbraco.Core/Diagnostics/MiniDump.cs | 28 ++++++++++--------- src/Umbraco.Core/Persistence/LocalDb.cs | 17 ++++++----- .../Sync/DatabaseServerMessenger.cs | 10 ++++++- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Core/Diagnostics/MiniDump.cs b/src/Umbraco.Core/Diagnostics/MiniDump.cs index e8c2e82f94..ca9596b4ae 100644 --- a/src/Umbraco.Core/Diagnostics/MiniDump.cs +++ b/src/Umbraco.Core/Diagnostics/MiniDump.cs @@ -79,24 +79,26 @@ namespace Umbraco.Core.Diagnostics private static bool Write(SafeHandle fileHandle, Option options, bool withException = false) { - var currentProcess = Process.GetCurrentProcess(); - var currentProcessHandle = currentProcess.Handle; - var currentProcessId = (uint)currentProcess.Id; + using (var currentProcess = Process.GetCurrentProcess()) + { + var currentProcessHandle = currentProcess.Handle; + var currentProcessId = (uint)currentProcess.Id; - MiniDumpExceptionInformation exp; + MiniDumpExceptionInformation exp; - exp.ThreadId = GetCurrentThreadId(); - exp.ClientPointers = false; - exp.ExceptionPointers = IntPtr.Zero; + exp.ThreadId = GetCurrentThreadId(); + exp.ClientPointers = false; + exp.ExceptionPointers = IntPtr.Zero; - if (withException) - exp.ExceptionPointers = Marshal.GetExceptionPointers(); + if (withException) + exp.ExceptionPointers = Marshal.GetExceptionPointers(); - var bRet = exp.ExceptionPointers == IntPtr.Zero - ? MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) - : MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, ref exp, IntPtr.Zero, IntPtr.Zero); + var bRet = exp.ExceptionPointers == IntPtr.Zero + ? MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint)options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) + : MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint)options, ref exp, IntPtr.Zero, IntPtr.Zero); - return bRet; + return bRet; + } } public static bool Dump(Option options = Option.WithFullMemory, bool withException = false) diff --git a/src/Umbraco.Core/Persistence/LocalDb.cs b/src/Umbraco.Core/Persistence/LocalDb.cs index 55d6565344..0e1da4c0d1 100644 --- a/src/Umbraco.Core/Persistence/LocalDb.cs +++ b/src/Umbraco.Core/Persistence/LocalDb.cs @@ -901,7 +901,7 @@ namespace Umbraco.Core.Persistence return -1; } - var p = new Process + using (var p = new Process { StartInfo = { @@ -913,13 +913,16 @@ namespace Umbraco.Core.Persistence CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden } - }; - p.Start(); - output = p.StandardOutput.ReadToEnd(); - error = p.StandardError.ReadToEnd(); - p.WaitForExit(); + }) + { + p.Start(); + output = p.StandardOutput.ReadToEnd(); + error = p.StandardError.ReadToEnd(); + p.WaitForExit(); - return p.ExitCode; + return p.ExitCode; + } + } /// diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs index 75ccf5e4f9..1cfca49160 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs @@ -535,10 +535,18 @@ namespace Umbraco.Core.Sync /// protected static readonly string LocalIdentity = NetworkHelper.MachineName // eg DOMAIN\SERVER + "/" + HttpRuntime.AppDomainAppId // eg /LM/S3SVC/11/ROOT - + " [P" + Process.GetCurrentProcess().Id // eg 1234 + + " [P" + GetProcessId() // eg 1234 + "/D" + AppDomain.CurrentDomain.Id // eg 22 + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique + private static int GetProcessId() + { + using(var p = Process.GetCurrentProcess()) + { + return p.Id; + } + } + private string GetDistCacheFilePath(IGlobalSettings globalSettings) { var fileName = HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt"; From 8b685a0a2c626c422f67616b73ea8d0e55a5d06f Mon Sep 17 00:00:00 2001 From: Chad Currie Date: Sun, 22 Aug 2021 15:40:44 +1200 Subject: [PATCH 08/24] Update Serilog.Enrichers.Process to 2.0.2 as it fixes a leak (cherry picked from commit dcc533fd8dba44bb4cd7feebd609bed40fe7d271) --- build/NuSpecs/UmbracoCms.Core.nuspec | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index c94def143b..a55eff33a9 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -33,7 +33,7 @@ - + diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 146197c4f8..7a65d75578 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -97,7 +97,7 @@ 2.10.0 - 2.0.1 + 2.0.2 3.1.0 From e869ba7e9bc8f4a4e2c384128618a278a7126cab Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 23 Aug 2021 14:41:26 -0600 Subject: [PATCH 09/24] removes comment --- .../NuCache/PublishedSnapshotService.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 0e98112fc1..7a07dcf051 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -638,25 +638,6 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Handle Notifications - // note: if the service is not ready, ie _isReady is false, then notifications are ignored - - // SetUmbracoVersionStep issues a DistributedCache.Instance.RefreshAll...() call which should cause - // the entire content, media etc caches to reload from database -- and then the app restarts -- however, - // at the time SetUmbracoVersionStep runs, Umbraco is not fully initialized and therefore some property - // value converters, etc are not registered, and rebuilding the NuCache may not work properly. - // - // More details: ApplicationContext.IsConfigured being false, ApplicationEventHandler.ExecuteWhen... is - // called and in most cases events are skipped, so property value converters are not registered or - // removed, so PublishedPropertyType either initializes with the wrong converter, or throws because it - // detects more than one converter for a property type. - // - // It's not an issue for XmlStore - the app restart takes place *after* the install has refreshed the - // cache, and XmlStore just writes a new umbraco.config file upon RefreshAll, so that's OK. - // - // But for NuCache... we cannot rebuild the cache now. So it will NOT work and we are not fixing it, - // because now we should ALWAYS run with the database server messenger, and then the RefreshAll will - // be processed as soon as we are configured and the messenger processes instructions. - // note: notifications for content type and data type changes should be invoked with the // pure live model factory, if any, locked and refreshed - see ContentTypeCacheRefresher and // DataTypeCacheRefresher From 14a94f0ba59c7c8131bfc5c3e9eb00b8bc0c4c3e Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 24 Aug 2021 06:41:57 +1000 Subject: [PATCH 10/24] Merge pull request #10847 from umbraco/v8/bugfix/backport-fix-for-10774-into-v8 Backport fix for #10774 to v8 (cherry picked from commit 88f17b7cbfdc9073ef20d15ca503ec76a2ebf6b0) --- .../NuCache/PublishedSnapshotService.cs | 69 ++----------------- 1 file changed, 5 insertions(+), 64 deletions(-) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index f3373dab6c..7678563a53 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -347,28 +347,6 @@ namespace Umbraco.Web.PublishedCache.NuCache return path; } - private void DeleteLocalFilesForContent() - { - if (_isReady && _localContentDb != null) - throw new InvalidOperationException("Cannot delete local files while the cache uses them."); - - var path = GetLocalFilesPath(); - var localContentDbPath = Path.Combine(path, "NuCache.Content.db"); - if (File.Exists(localContentDbPath)) - File.Delete(localContentDbPath); - } - - private void DeleteLocalFilesForMedia() - { - if (_isReady && _localMediaDb != null) - throw new InvalidOperationException("Cannot delete local files while the cache uses them."); - - var path = GetLocalFilesPath(); - var localMediaDbPath = Path.Combine(path, "NuCache.Media.db"); - if (File.Exists(localMediaDbPath)) - File.Delete(localMediaDbPath); - } - #endregion #region Environment @@ -660,38 +638,13 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Handle Notifications - // note: if the service is not ready, ie _isReady is false, then notifications are ignored - - // SetUmbracoVersionStep issues a DistributedCache.Instance.RefreshAll...() call which should cause - // the entire content, media etc caches to reload from database -- and then the app restarts -- however, - // at the time SetUmbracoVersionStep runs, Umbraco is not fully initialized and therefore some property - // value converters, etc are not registered, and rebuilding the NuCache may not work properly. - // - // More details: ApplicationContext.IsConfigured being false, ApplicationEventHandler.ExecuteWhen... is - // called and in most cases events are skipped, so property value converters are not registered or - // removed, so PublishedPropertyType either initializes with the wrong converter, or throws because it - // detects more than one converter for a property type. - // - // It's not an issue for XmlStore - the app restart takes place *after* the install has refreshed the - // cache, and XmlStore just writes a new umbraco.config file upon RefreshAll, so that's OK. - // - // But for NuCache... we cannot rebuild the cache now. So it will NOT work and we are not fixing it, - // because now we should ALWAYS run with the database server messenger, and then the RefreshAll will - // be processed as soon as we are configured and the messenger processes instructions. - // note: notifications for content type and data type changes should be invoked with the // pure live model factory, if any, locked and refreshed - see ContentTypeCacheRefresher and // DataTypeCacheRefresher public override void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) { - // no cache, trash everything - if (_isReady == false) - { - DeleteLocalFilesForContent(); - draftChanged = publishedChanged = true; - return; - } + EnsureCaches(); using (_contentStore.GetScopedWriteLock(_scopeProvider)) { @@ -785,13 +738,7 @@ namespace Umbraco.Web.PublishedCache.NuCache /// public override void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) { - // no cache, trash everything - if (_isReady == false) - { - DeleteLocalFilesForMedia(); - anythingChanged = true; - return; - } + EnsureCaches(); using (_mediaStore.GetScopedWriteLock(_scopeProvider)) { @@ -878,9 +825,7 @@ namespace Umbraco.Web.PublishedCache.NuCache /// public override void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) { - // no cache, nothing we can do - if (_isReady == false) - return; + EnsureCaches(); foreach (var payload in payloads) _logger.Debug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id); @@ -960,9 +905,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) { - // no cache, nothing we can do - if (_isReady == false) - return; + EnsureCaches(); var idsA = payloads.Select(x => x.Id).ToArray(); @@ -1000,9 +943,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(DomainCacheRefresher.JsonPayload[] payloads) { - // no cache, nothing we can do - if (_isReady == false) - return; + EnsureCaches(); // see note in LockAndLoadContent using (_domainStore.GetScopedWriteLock(_scopeProvider)) From 94b0b252ece607c9ea6fff4e417635623ee1803e Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Tue, 24 Aug 2021 14:42:08 +0100 Subject: [PATCH 11/24] Revert "Optimization by returning the same instance" This reverts commit 990fc118cbd6df423be2107a75970a834ade1f76. When using the _reusableEditor field to create a BlockEditorPropertyEditor it doesn't matter that content type cache has been invalidated (memory cache) as the content types are also cached in a private field in the BlockEditorValues class. Closes #10910 --- src/Umbraco.Core/PropertyEditors/DataEditor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/DataEditor.cs b/src/Umbraco.Core/PropertyEditors/DataEditor.cs index d927d10052..add523ecf6 100644 --- a/src/Umbraco.Core/PropertyEditors/DataEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataEditor.cs @@ -19,7 +19,6 @@ namespace Umbraco.Core.PropertyEditors public class DataEditor : IDataEditor { private IDictionary _defaultConfiguration; - private IDataValueEditor _reusableEditor; /// /// Initializes a new instance of the class. @@ -91,8 +90,7 @@ namespace Umbraco.Core.PropertyEditors /// simple enough for now. /// // TODO: point of that one? shouldn't we always configure? - public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? (_reusableEditor ?? (_reusableEditor = CreateValueEditor())); - + public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? CreateValueEditor(); /// /// From e558d11fa9758041b2ad9ffbe28722c57c21bd57 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Tue, 24 Aug 2021 14:42:08 +0100 Subject: [PATCH 12/24] Revert "Optimization by returning the same instance" This reverts commit 990fc118cbd6df423be2107a75970a834ade1f76. When using the _reusableEditor field to create a BlockEditorPropertyEditor it doesn't matter that content type cache has been invalidated (memory cache) as the content types are also cached in a private field in the BlockEditorValues class. Closes #10910 (cherry picked from commit 94b0b252ece607c9ea6fff4e417635623ee1803e) --- src/Umbraco.Core/PropertyEditors/DataEditor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/DataEditor.cs b/src/Umbraco.Core/PropertyEditors/DataEditor.cs index d927d10052..add523ecf6 100644 --- a/src/Umbraco.Core/PropertyEditors/DataEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataEditor.cs @@ -19,7 +19,6 @@ namespace Umbraco.Core.PropertyEditors public class DataEditor : IDataEditor { private IDictionary _defaultConfiguration; - private IDataValueEditor _reusableEditor; /// /// Initializes a new instance of the class. @@ -91,8 +90,7 @@ namespace Umbraco.Core.PropertyEditors /// simple enough for now. /// // TODO: point of that one? shouldn't we always configure? - public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? (_reusableEditor ?? (_reusableEditor = CreateValueEditor())); - + public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? CreateValueEditor(); /// /// From cac4124dea2637177824734148636a1ebcfc9688 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 30 Aug 2021 11:12:45 +0200 Subject: [PATCH 13/24] Bump version to 8.14.4 --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index b9bbd54c8e..c3b38dd2d8 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.14.3")] -[assembly: AssemblyInformationalVersion("8.14.3")] +[assembly: AssemblyFileVersion("8.14.4")] +[assembly: AssemblyInformationalVersion("8.14.4")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 95ba9de0ca..c2e3daf779 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -348,9 +348,9 @@ False True - 8143 + 8144 / - http://localhost:8143 + http://localhost:8144 8131 / http://localhost:8131 From ee1faa4da2f0077c8f7fa6caf783b31771313f5e Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 30 Aug 2021 11:15:11 +0200 Subject: [PATCH 14/24] Bump version to 8.15.3 --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index ff286570c3..9e6adabf97 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.15.2")] -[assembly: AssemblyInformationalVersion("8.15.2")] +[assembly: AssemblyFileVersion("8.15.3")] +[assembly: AssemblyInformationalVersion("8.15.3")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 56ed9483fe..5faecbe755 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -348,9 +348,9 @@ False True - 8152 + 8153 / - http://localhost:8152 + http://localhost:8153 False False From b04fe360d8985802d5500fe5cf41d422b0d52e07 Mon Sep 17 00:00:00 2001 From: nzdev <834725+nzdev@users.noreply.github.com> Date: Mon, 30 Aug 2021 12:19:21 +1200 Subject: [PATCH 15/24] Dispose certficate handle --- .../HealthCheck/Checks/Security/HttpsCheck.cs | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs b/src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs index 18d27ba028..15906af96a 100644 --- a/src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs +++ b/src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs @@ -92,24 +92,26 @@ namespace Umbraco.Web.HealthCheck.Checks.Security // Hat-tip: https://stackoverflow.com/a/15343898/489433 const int NumberOfDaysForExpiryWarning = 14; var cert = request.ServicePoint.Certificate; - var cert2 = new X509Certificate2(cert); - var expirationDate = cert2.NotAfter; + using (var cert2 = new X509Certificate2(cert)) + { + var expirationDate = cert2.NotAfter; - var daysToExpiry = (int)Math.Floor((cert2.NotAfter - DateTime.Now).TotalDays); - if (daysToExpiry <= 0) - { - result = StatusResultType.Error; - message = _textService.Localize("healthcheck", "httpsCheckExpiredCertificate"); - } - else if (daysToExpiry < NumberOfDaysForExpiryWarning) - { - result = StatusResultType.Warning; - message = _textService.Localize("healthcheck", "httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); - } - else - { - result = StatusResultType.Success; - message = _textService.Localize("healthcheck", "httpsCheckValidCertificate"); + var daysToExpiry = (int)Math.Floor((cert2.NotAfter - DateTime.Now).TotalDays); + if (daysToExpiry <= 0) + { + result = StatusResultType.Error; + message = _textService.Localize("healthcheck", "httpsCheckExpiredCertificate"); + } + else if (daysToExpiry < NumberOfDaysForExpiryWarning) + { + result = StatusResultType.Warning; + message = _textService.Localize("healthcheck", "httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); + } + else + { + result = StatusResultType.Success; + message = _textService.Localize("healthcheck", "httpsCheckValidCertificate"); + } } } else From 50dfb1fd92c47f45acfcad5c3fbf967ffe49fb0d Mon Sep 17 00:00:00 2001 From: Chad Date: Tue, 31 Aug 2021 00:17:05 +1200 Subject: [PATCH 16/24] Avoid allocating an array every call to IsClientSideRequest() (#10936) --- src/Umbraco.Core/UriExtensions.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 96e24e89db..3ba004a939 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Umbraco.Core.Composing; @@ -137,6 +138,14 @@ namespace Umbraco.Core return false; } + /// + /// Non Client Side request Extensions + /// + internal readonly static HashSet NonClientSideRequestExtensions = new (5, StringComparer.InvariantCultureIgnoreCase) + { + ".aspx", ".ashx", ".asmx", ".axd", ".svc" + }; + /// /// This is a performance tweak to check if this not an ASP.Net server file /// .Net will pass these requests through to the module when in integrated mode. @@ -150,8 +159,7 @@ namespace Umbraco.Core { var ext = Path.GetExtension(url.LocalPath); if (ext.IsNullOrWhiteSpace()) return false; - var toInclude = new[] {".aspx", ".ashx", ".asmx", ".axd", ".svc"}; - return toInclude.Any(ext.InvariantEquals) == false; + return !NonClientSideRequestExtensions.Contains(ext); } catch (ArgumentException) { From b1d1a2fcf2e8cb0d0d5726227592e312f0925b26 Mon Sep 17 00:00:00 2001 From: Chad Date: Tue, 31 Aug 2021 00:22:07 +1200 Subject: [PATCH 17/24] Avoid creating a new string for the log level every log message (#10934) --- .../Enrichers/Log4NetLevelMapperEnricher.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs b/src/Umbraco.Core/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs index 0c255fa8b4..327dc13526 100644 --- a/src/Umbraco.Core/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs +++ b/src/Umbraco.Core/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core.Logging.Serilog.Enrichers { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { - var log4NetLevel = string.Empty; + string log4NetLevel; switch (logEvent.Level) { @@ -28,21 +28,21 @@ namespace Umbraco.Core.Logging.Serilog.Enrichers break; case LogEventLevel.Information: - log4NetLevel = "INFO"; + log4NetLevel = "INFO "; //Padded string so that all log levels are 5 chars long (needed to keep the txt log file lined up nicely) break; case LogEventLevel.Verbose: - log4NetLevel = "ALL"; + log4NetLevel = "ALL "; //Padded string so that all log levels are 5 chars long (needed to keep the txt log file lined up nicely) break; case LogEventLevel.Warning: - log4NetLevel = "WARN"; + log4NetLevel = "WARN "; //Padded string so that all log levels are 5 chars long (needed to keep the txt log file lined up nicely) + break; + default: + log4NetLevel = string.Empty; break; } - //Pad string so that all log levels are 5 chars long (needed to keep the txt log file lined up nicely) - log4NetLevel = log4NetLevel.PadRight(5); - logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Log4NetLevel", log4NetLevel)); } } From 20eda449e7f5e0d4b37ddbfc1a671c40f3d0f8a6 Mon Sep 17 00:00:00 2001 From: Chad Currie Date: Tue, 24 Aug 2021 22:31:30 +1200 Subject: [PATCH 18/24] Avoid generating the maindom hash twice to get the Id. --- src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs b/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs index 2dcc37e25f..1f49f494cc 100644 --- a/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs +++ b/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs @@ -20,10 +20,11 @@ namespace Umbraco.Core.Runtime public MainDomSemaphoreLock(ILogger logger) { - var lockName = "UMBRACO-" + MainDom.GetMainDomId() + "-MAINDOM-LCK"; + var mainDomId = MainDom.GetMainDomId(); + var lockName = "UMBRACO-" + mainDomId + "-MAINDOM-LCK"; _systemLock = new SystemLock(lockName); - var eventName = "UMBRACO-" + MainDom.GetMainDomId() + "-MAINDOM-EVT"; + var eventName = "UMBRACO-" + mainDomId + "-MAINDOM-EVT"; _signal = new EventWaitHandle(false, EventResetMode.AutoReset, eventName); _logger = logger; } From 7757c4d76317a97e7464fed533c8d2a0a258a665 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Mon, 30 Aug 2021 15:57:58 +0200 Subject: [PATCH 19/24] Allow to pass in boolean to noDirtyCheck directive (#8638) * Adjust noDirtyCheck directive to accept a parameter to enable/disable dirty check * Update dirty property * Use Utilities.noop and add description * Set default value from controller * Check for truthly value * Use Object.toBoolean * Revert setting $pristine and $dirty for now * Handle default values in dirty check attributes * Add check on presence of disableDirtyCheck atribute * Check for truthy value otherwise it should be default return false and work as no-dirty-check without value * update test conditions for vamue of no-dirty-check and disable-dirty-check * Remove whitespace * update check Co-authored-by: Kenn Jacobsen Co-authored-by: Michael --- .../components/forms/umbcheckbox.directive.js | 9 +++-- .../forms/umbradiobutton.directive.js | 9 +++-- .../validation/nodirtycheck.directive.js | 13 ++++--- .../views/components/forms/umb-checkbox.html | 34 ++++++------------- .../components/forms/umb-radiobutton.html | 34 ++++++------------- 5 files changed, 45 insertions(+), 54 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js index 717cefbb0a..a4508c8879 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js @@ -41,7 +41,7 @@ (function () { 'use strict'; - function UmbCheckboxController($timeout, localizationService) { + function UmbCheckboxController($timeout, $attrs, localizationService) { var vm = this; @@ -50,7 +50,12 @@ function onInit() { vm.inputId = vm.inputId || "umb-check_" + String.CreateGuid(); - + vm.disableDirtyCheck = + $attrs.hasOwnProperty("disableDirtyCheck") && + vm.disableDirtyCheck !== '0' && + vm.disableDirtyCheck !== 0 && + vm.disableDirtyCheck !== 'false' && + vm.disableDirtyCheck !== false; vm.icon = vm.icon || vm.iconClass || null; // If a labelKey is passed let's update the returned text if it's does not contain an opening square bracket [ diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js index 8c7157c414..dd0d2fc31b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js @@ -40,7 +40,7 @@ (function () { 'use strict'; - function UmbRadiobuttonController($timeout, localizationService) { + function UmbRadiobuttonController($timeout, $attrs, localizationService) { var vm = this; @@ -49,7 +49,12 @@ function onInit() { vm.inputId = vm.inputId || "umb-radio_" + String.CreateGuid(); - + vm.disableDirtyCheck = + $attrs.hasOwnProperty("disableDirtyCheck") && + vm.disableDirtyCheck !== '0' && + vm.disableDirtyCheck !== 0 && + vm.disableDirtyCheck !== 'false' && + vm.disableDirtyCheck !== false; vm.icon = vm.icon || vm.iconClass || null; // If a labelKey is passed let's update the returned text if it's does not contain an opening square bracket [ diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js index 800ac87480..31ef125511 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js @@ -10,13 +10,18 @@ function noDirtyCheck() { require: 'ngModel', link: function (scope, elm, attrs, ctrl) { + // if "no-dirty-check" attribute is explicitly falsy, then skip and use default behaviour. In all other cases we consider it truthy + var skipNoDirtyCheck = attrs.noDirtyCheck === '0' || attrs.noDirtyCheck === 0 || attrs.noDirtyCheck.toString().toLowerCase() === 'false'; + if (skipNoDirtyCheck) + return; + var alwaysFalse = { - get: function () { return false; }, - set: function () { } - }; + get: function () { return false; }, + set: function () { } + }; + Object.defineProperty(ctrl, '$pristine', alwaysFalse); Object.defineProperty(ctrl, '$dirty', alwaysFalse); - } }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html index 9056963c9d..a093e66b61 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html @@ -1,29 +1,17 @@