From 4eb4cd896272132781e6d95d0c9252fbb3c5a312 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Sun, 28 Oct 2018 16:35:37 +0100 Subject: [PATCH 001/555] Refactor checkboxlist to show a prettier checkbox than the default browser one --- .../less/components/umb-checkbox-list.less | 77 +++++++++++++++++++ .../checkboxlist/checkboxlist.html | 11 ++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less index 02f30f6f35..bd914ab65c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less @@ -65,3 +65,80 @@ font-size: 16px; line-height: 1.8em; } + + +/* Styling for the .umb-checkboxlist class - Styling added 28-10-2018 using BEM syntax */ +.umb-checkboxlist{ + &__label{ + position: relative; + padding: 0; + + &-text{ + margin: 0 0 0 32px; + position: relative; + top: 2px; + } + } + + &__input{ + position: absolute; + top: 0; + left: 0; + opacity: 0; + + &:focus ~ .umb-checkboxlist__state{ + box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%); + } + + &:checked ~ .umb-checkboxlist__state{ + &:before{ + width: 100%; + height: 100%; + } + } + + &:checked ~ .umb-checkboxlist__state .umb-checkboxlist__icon{ + opacity: 1; + } + } + + &__state{ + display: flex; + flex-wrap: wrap; + border: 1px solid @gray-8; + width: 20px; + height: 20px; + position: relative; + + &:before{ + content: ""; + background: @green; + width: 0; + height: 0; + transition: .1s ease-out; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + } + } + + &__icon{ + color: @white; + text-align: center; + font-size: 13px; + opacity: 0; + transition: .3s ease-out; + + &:before{ + position: absolute; + top: 1px; + right: 0; + left: 0; + bottom: 0; + margin: auto; + } + } +} diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html index ae691215e7..52c3c11b70 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html @@ -2,11 +2,16 @@ From 397b3ca69f862a1fee524abc6aa2de8b94e18dcd Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Mon, 29 Oct 2018 11:02:53 +0100 Subject: [PATCH 002/555] #3434 use toggle for varying by culture on property settings dialog in content type designer --- .../propertysettings.controller.js | 13 +++++++++- .../propertysettings/propertysettings.html | 25 +++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js index 7239fd22e7..fec24a3a31 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js @@ -29,6 +29,8 @@ vm.submit = submit; vm.close = close; + vm.toggleAllowCultureVariants = toggleAllowCultureVariants; + function onInit() { userService.getCurrentUser().then(function(user) { @@ -232,10 +234,19 @@ } + function toggleAllowCultureVariants() { + if ($scope.model.property.allowCultureVariant) { + $scope.model.property.allowCultureVariant = false; + return; + } + + $scope.model.property.allowCultureVariant = true; + } + onInit(); } angular.module("umbraco").controller("Umbraco.Editors.PropertySettingsController", PropertySettingsEditor); -})(); \ No newline at end of file +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index 610af28cb8..6862a313d1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -106,14 +106,23 @@
- -
Property Type Variation
- - - +
+ +
+
+ +
+ +
+ + +
+ +
+
From 87340d6c2c998f8f38ed629068cc80bc80974547 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Wed, 31 Oct 2018 21:24:35 +0100 Subject: [PATCH 003/555] Fix width issue on the checkbox label --- .../src/less/components/umb-checkbox-list.less | 18 ++++++++++++------ .../checkboxlist/checkboxlist.html | 4 +++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less index bd914ab65c..a05c376ccc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less @@ -72,9 +72,10 @@ &__label{ position: relative; padding: 0; + margin: 0 0 15px 0; &-text{ - margin: 0 0 0 32px; + margin: 0 0 0 10px; position: relative; top: 2px; } @@ -86,14 +87,14 @@ left: 0; opacity: 0; - &:focus ~ .umb-checkboxlist__state{ + &:focus ~ .umb-checkboxlist__state .umb-checkboxlist__check{ box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%); } - &:checked ~ .umb-checkboxlist__state{ + &:checked ~ .umb-checkboxlist__state .umb-checkboxlist__check{ &:before{ - width: 100%; - height: 100%; + width: 20px; + height: 20px; } } @@ -105,10 +106,15 @@ &__state{ display: flex; flex-wrap: wrap; + height: 20px; + position: relative; + } + + &__check{ + position: relative; border: 1px solid @gray-8; width: 20px; height: 20px; - position: relative; &:before{ content: ""; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html index 52c3c11b70..8ddbfd5801 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html @@ -9,7 +9,9 @@ class="umb-checkboxlist__input" />
- +
+ +
{{item.val}}
From 5716353518bb6c793b2ad7d2d6264c1d30f1cd4e Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Wed, 31 Oct 2018 21:46:00 +0100 Subject: [PATCH 004/555] Offset the state 1 px to align it with the radio button list if they ever occur as properties beneath each other --- .../src/less/components/umb-checkbox-list.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less index a05c376ccc..f7ac90c31e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkbox-list.less @@ -108,6 +108,7 @@ flex-wrap: wrap; height: 20px; position: relative; + left: 1px; } &__check{ From 007cdeb9ab1521b723c73d8093a836671a1c55d3 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Wed, 31 Oct 2018 21:48:47 +0100 Subject: [PATCH 005/555] Fix long label issue on RADIO button list --- .../components/umb-radiobuttons-list.less | 20 ++++++++++++------- .../radiobuttons/radiobuttons.html | 4 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-radiobuttons-list.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-radiobuttons-list.less index 2fe3487a8f..91856dc0a6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-radiobuttons-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-radiobuttons-list.less @@ -2,11 +2,12 @@ &__label{ position: relative; padding: 0; + margin: 0 0 15px 0; &-text{ - margin: 0 0 0 32px; + margin: 0 0 0 10px; position: relative; - top: 1px; + top: 3px; } } @@ -16,18 +17,18 @@ left: 0; opacity: 0; - &:focus ~ .umb-radiobuttons__state{ + &:focus ~ .umb-radiobuttons__state .umb-radiobuttons__check{ box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%); } - &:focus:checked ~ .umb-radiobuttons__state{ + &:focus:checked ~ .umb-radiobuttons__state .umb-radiobuttons__check{ box-shadow: none; } - &:checked ~ .umb-radiobuttons__state{ + &:checked ~ .umb-radiobuttons__state .umb-radiobuttons__check{ &:before{ - width: 100%; - height: 100%; + width: 22px; + height: 22px; } } @@ -39,6 +40,11 @@ &__state{ display: flex; flex-wrap: wrap; + height: 22px; + position: relative; + } + + &__check{ border: 1px solid @gray-8; border-radius: 100%; width: 22px; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html index 7af6491641..b690feb2ba 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html @@ -8,7 +8,9 @@ class="umb-radiobuttons__input" />
- +
+ +
{{item.value}}
From d0908895ddd8de472b8ed64bb1fe8f1f7e1b66e1 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 7 Nov 2018 09:48:31 +0100 Subject: [PATCH 006/555] #3434 removed usage of subview-classes --- .../propertysettings/propertysettings.html | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index 6862a313d1..dae9c2c838 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -106,23 +106,15 @@
-
- -
+
- -
- -
+ -
- -
- +
From 110ecc5fda4864348d0f3c7a7316ae19a4dad377 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 7 Nov 2018 10:09:04 +0100 Subject: [PATCH 007/555] #3434 use toggle for mandatory validation on property type settings and made a better distinction between mandatory and custom validation --- .../propertysettings/propertysettings.controller.js | 10 ++++++++++ .../propertysettings/propertysettings.html | 13 +++++++++++-- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js index fec24a3a31..198f352bf1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js @@ -30,6 +30,7 @@ vm.close = close; vm.toggleAllowCultureVariants = toggleAllowCultureVariants; + vm.toggleValidation = toggleValidation; function onInit() { @@ -243,6 +244,15 @@ $scope.model.property.allowCultureVariant = true; } + function toggleValidation() { + if ($scope.model.property.validation.mandatory) { + $scope.model.property.validation.mandatory = false; + return; + } + + $scope.model.property.validation.mandatory = true; + } + onInit(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index dae9c2c838..ecdd5b203d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -84,10 +84,19 @@
-
From 880faeebd3485bae962f02dffd8c1fddec44950b Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 30 Jan 2019 16:50:08 +0000 Subject: [PATCH 032/555] Adds a few more providers to the collection --- .../Media/IEmbedSettingProvider.cs | 9 ------ src/Umbraco.Core/Umbraco.Core.csproj | 1 - .../config/EmbeddedMedia.config | 28 ------------------- .../Media/EmbedProviders/SoundCloud.cs | 24 ++++++++++++++++ src/Umbraco.Web/Media/EmbedProviders/Ted.cs | 24 ++++++++++++++++ src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs | 24 ++++++++++++++++ src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 6 +++- src/Umbraco.Web/Umbraco.Web.csproj | 3 ++ 8 files changed, 80 insertions(+), 39 deletions(-) delete mode 100644 src/Umbraco.Core/Media/IEmbedSettingProvider.cs create mode 100644 src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs create mode 100644 src/Umbraco.Web/Media/EmbedProviders/Ted.cs create mode 100644 src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs diff --git a/src/Umbraco.Core/Media/IEmbedSettingProvider.cs b/src/Umbraco.Core/Media/IEmbedSettingProvider.cs deleted file mode 100644 index b9ba611100..0000000000 --- a/src/Umbraco.Core/Media/IEmbedSettingProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Xml; - -namespace Umbraco.Core.Media -{ - public interface IEmbedSettingProvider - { - object GetSetting(XmlNode settingNode); - } -} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f44db01738..2edb39fc86 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -647,7 +647,6 @@ - diff --git a/src/Umbraco.Web.UI/config/EmbeddedMedia.config b/src/Umbraco.Web.UI/config/EmbeddedMedia.config index 262dc2993f..0e2c5aa988 100644 --- a/src/Umbraco.Web.UI/config/EmbeddedMedia.config +++ b/src/Umbraco.Web.UI/config/EmbeddedMedia.config @@ -12,20 +12,6 @@ - - - - - - - - - - - - - - @@ -35,20 +21,6 @@ - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs b/src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs new file mode 100644 index 0000000000..080437a246 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Soundcloud : EmbedProviderBase + { + public override string ApiEndpoint => "https://soundcloud.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"soundcloud.com\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Ted.cs b/src/Umbraco.Web/Media/EmbedProviders/Ted.cs new file mode 100644 index 0000000000..aa14423349 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Ted.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Ted : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.ted.com/talks/oembed.xml"; + + public override string[] UrlSchemeRegex => new string[] + { + @"ted.com\/talks\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs b/src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs new file mode 100644 index 0000000000..806f40a10c --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Vimeo : EmbedProviderBase + { + public override string ApiEndpoint => "https://vimeo.com/api/oembed.xml"; + + public override string[] UrlSchemeRegex => new string[] + { + @"vimeo\.com/" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 444a4e6098..5696589647 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -222,7 +222,11 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append() - .Append(); + .Append() + .Append() + .Append() + .Append(); } } } + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 4f20e30b68..3e767f97a8 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -148,6 +148,9 @@ + + + From fe9700b3f79eeeee12cafd5e82aa91b9592a01ed Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 30 Jan 2019 21:52:12 +0000 Subject: [PATCH 033/555] A handful more providers moved across & removed any that no longer supported --- .../config/EmbeddedMedia.config | 25 ----------------- src/Umbraco.Web/Media/EmbedProviders/Hulu.cs | 24 ++++++++++++++++ src/Umbraco.Web/Media/EmbedProviders/Issuu.cs | 28 +++++++++++++++++++ src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 9 +++++- src/Umbraco.Web/Umbraco.Web.csproj | 2 ++ 5 files changed, 62 insertions(+), 26 deletions(-) create mode 100644 src/Umbraco.Web/Media/EmbedProviders/Hulu.cs create mode 100644 src/Umbraco.Web/Media/EmbedProviders/Issuu.cs diff --git a/src/Umbraco.Web.UI/config/EmbeddedMedia.config b/src/Umbraco.Web.UI/config/EmbeddedMedia.config index 0e2c5aa988..a5edaf3834 100644 --- a/src/Umbraco.Web.UI/config/EmbeddedMedia.config +++ b/src/Umbraco.Web.UI/config/EmbeddedMedia.config @@ -11,15 +11,6 @@ https - - - - - - - json - - @@ -29,21 +20,5 @@ xml - - - - - - - xml - - - - - - - - - diff --git a/src/Umbraco.Web/Media/EmbedProviders/Hulu.cs b/src/Umbraco.Web/Media/EmbedProviders/Hulu.cs new file mode 100644 index 0000000000..150439832a --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Hulu.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Hulu : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.hulu.com/api/oembed.json"; + + public override string[] UrlSchemeRegex => new string[] + { + @"hulu.com/watch/.*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Issuu.cs b/src/Umbraco.Web/Media/EmbedProviders/Issuu.cs new file mode 100644 index 0000000000..2b33473453 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Issuu.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Issuu : EmbedProviderBase + { + public override string ApiEndpoint => "https://issuu.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"issuu.com/.*/docs/.*" + }; + + public override Dictionary RequestParams => new Dictionary() + { + //ApiUrl/?format=xml + {"format", "xml"} + }; + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 5696589647..5974288daf 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -225,7 +225,14 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append() - .Append(); + .Append() + .Append() + .Append(); + + + //Giphy + //Meetup + //Spotify } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3e767f97a8..e418cf8872 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -149,7 +149,9 @@ + + From 7b55d2f1b2fce1a3bb8eadbd32028598785658e3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 31 Jan 2019 15:09:31 +1100 Subject: [PATCH 034/555] New IMacroRenderer and ITemplateRenderer and hides underlying logic for these in internal classes. Massively cleans up the macro rendering logic (almost makes sense now), removes unused macro code, injects UmbracoHelper wherever it's needed (not creating manually), fixes UmbracoHelper to have it's services injected, no more empty services, allows setting the AssignedContentItem on the UmbracoHelper and ensures it's lifespan is Transient, updates all corresponding ctors. Fixes macro rendering, ensures the correct culture variation is assigned, and that we can render macros for any given IPublishedContent, not just the one assigned in the request. --- .../Routing/RenderRouteHandlerTests.cs | 3 +- .../TestControllerActivatorBase.cs | 9 +- .../Testing/TestingTests/MockTests.cs | 7 +- .../Controllers/PluginControllerAreaTests.cs | 8 +- .../Web/Mvc/SurfaceControllerTests.cs | 13 +- src/Umbraco.Web/Composing/Current.cs | 3 + src/Umbraco.Web/Controllers/TagsController.cs | 15 +- .../Controllers/UmbLoginController.cs | 9 +- .../Controllers/UmbLoginStatusController.cs | 9 +- .../Controllers/UmbProfileController.cs | 4 +- .../Controllers/UmbRegisterController.cs | 9 +- .../Editors/AuthenticationController.cs | 15 +- .../Editors/BackOfficeController.cs | 4 +- .../Editors/ContentTypeController.cs | 4 +- .../Editors/ContentTypeControllerBase.cs | 4 +- .../Editors/DashboardController.cs | 12 +- src/Umbraco.Web/Editors/EntityController.cs | 4 +- .../Editors/MacroRenderingController.cs | 19 +- .../Editors/MediaTypeController.cs | 3 +- .../Editors/MemberTypeController.cs | 3 +- .../Editors/PackageInstallController.cs | 4 +- src/Umbraco.Web/Editors/SectionController.cs | 6 +- .../UmbracoAuthorizedJsonController.cs | 15 +- src/Umbraco.Web/HtmlHelperRenderExtensions.cs | 4 +- src/Umbraco.Web/IUmbracoComponentRenderer.cs | 13 +- src/Umbraco.Web/Macros/IMacroRenderer.cs | 13 + src/Umbraco.Web/Macros/MacroModel.cs | 15 +- src/Umbraco.Web/Macros/MacroRenderer.cs | 355 ++++-------------- .../PublishedContentHashtableConverter.cs | 10 +- .../Mapping/RedirectUrlMapperProfile.cs | 6 +- .../EnsurePublishedContentRequestAttribute.cs | 3 +- src/Umbraco.Web/Mvc/PluginController.cs | 21 +- src/Umbraco.Web/Mvc/RenderMvcController.cs | 6 +- src/Umbraco.Web/Mvc/SurfaceController.cs | 4 +- .../Mvc/UmbracoAuthorizedController.cs | 9 +- src/Umbraco.Web/Mvc/UmbracoController.cs | 13 +- .../Mvc/UmbracoViewPageOfTModel.cs | 12 +- .../MacroContainerValueConverter.cs | 10 +- .../RteMacroRenderingValueConverter.cs | 10 +- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 17 +- .../Templates/ITemplateRenderer.cs | 12 + src/Umbraco.Web/Templates/TemplateRenderer.cs | 93 +++-- .../Trees/ApplicationTreeController.cs | 4 +- src/Umbraco.Web/Trees/TreeController.cs | 4 +- src/Umbraco.Web/Trees/TreeControllerBase.cs | 9 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 + .../UmbracoAuthorizedHttpHandler.cs | 7 +- src/Umbraco.Web/UmbracoComponentRenderer.cs | 161 ++++---- src/Umbraco.Web/UmbracoContext.cs | 26 +- src/Umbraco.Web/UmbracoHelper.cs | 136 +++---- src/Umbraco.Web/UmbracoHttpHandler.cs | 15 +- src/Umbraco.Web/UmbracoWebService.cs | 18 +- .../WebApi/UmbracoApiController.cs | 16 +- .../WebApi/UmbracoApiControllerBase.cs | 13 +- .../WebApi/UmbracoAuthorizedApiController.cs | 16 +- 55 files changed, 457 insertions(+), 778 deletions(-) create mode 100644 src/Umbraco.Web/Macros/IMacroRenderer.cs create mode 100644 src/Umbraco.Web/Templates/ITemplateRenderer.cs diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 71e3836b3d..3f44c6764e 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -172,8 +172,7 @@ namespace Umbraco.Tests.Routing /// public class CustomDocumentController : RenderMvcController { - public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger) + public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) { } diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 602b5907d8..4363996a46 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -152,13 +152,12 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbCtx), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()); - var umbHelper = new UmbracoHelper(umbCtx, - Mock.Of(), + var umbHelper = new UmbracoHelper(umbCtx, Mock.Of(), - Mock.Of(), + Mock.Of(), Mock.Of(), - membershipHelper, - serviceContext); + Mock.Of(), + membershipHelper); return CreateController(controllerType, request, umbHelper); } diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 575f14e818..b65e503f34 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -61,12 +61,11 @@ namespace Umbraco.Tests.Testing.TestingTests // ReSharper disable once UnusedVariable var helper = new UmbracoHelper(umbracoContext, - Mock.Of(), Mock.Of(), - Mock.Of(), + Mock.Of(), Mock.Of(), - new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()), - ServiceContext.CreatePartial()); + Mock.Of(), + new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of())); Assert.Pass(); } diff --git a/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs b/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs index 01525f12da..4c738df003 100644 --- a/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs @@ -54,7 +54,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin1Controller : PluginController { public Plugin1Controller(UmbracoContext umbracoContext) - : base(umbracoContext, null, null, null, null, null) + : base(umbracoContext, null, null, null, null, null, null) { } } @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin2Controller : PluginController { public Plugin2Controller(UmbracoContext umbracoContext) - : base(umbracoContext, null, null, null, null, null) + : base(umbracoContext, null, null, null, null, null, null) { } } @@ -72,7 +72,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin3Controller : PluginController { public Plugin3Controller(UmbracoContext umbracoContext) - : base(umbracoContext, null, null, null, null, null) + : base(umbracoContext, null, null, null, null, null, null) { } } @@ -80,7 +80,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin4Controller : PluginController { public Plugin4Controller(UmbracoContext umbracoContext) - : base(umbracoContext, null, null, null, null, null) + : base(umbracoContext, null, null, null, null, null, null) { } } diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 69f6c5d13e..e80385b533 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -128,12 +128,11 @@ namespace Umbraco.Tests.Web.Mvc var helper = new UmbracoHelper( umbracoContext, - Mock.Of(), Mock.Of(), - Mock.Of(), + Mock.Of(), Mock.Of(), - new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()), - ServiceContext.CreatePartial()); + Mock.Of(), + new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of())); var ctrl = new TestSurfaceController(umbracoContext, helper); var result = ctrl.GetContent(2) as PublishedContentResult; @@ -185,12 +184,8 @@ namespace Umbraco.Tests.Web.Mvc public class TestSurfaceController : SurfaceController { public TestSurfaceController(UmbracoContext ctx, UmbracoHelper helper = null) - : base(ctx, null, ServiceContext.CreatePartial(), Mock.Of(), null, null) + : base(ctx, null, ServiceContext.CreatePartial(), Mock.Of(), null, null, helper) { - if (helper != null) - { - Umbraco = helper; - } } public ActionResult Index() diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index b394684f56..d4fe51b3f1 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -94,6 +94,9 @@ namespace Umbraco.Web.Composing public static UmbracoContext UmbracoContext => UmbracoContextAccessor.UmbracoContext; + public static UmbracoHelper UmbracoHelper + => Factory.GetInstance(); + public static DistributedCache DistributedCache => Factory.GetInstance(); diff --git a/src/Umbraco.Web/Controllers/TagsController.cs b/src/Umbraco.Web/Controllers/TagsController.cs index 29518a594d..5dca84eee1 100644 --- a/src/Umbraco.Web/Controllers/TagsController.cs +++ b/src/Umbraco.Web/Controllers/TagsController.cs @@ -20,18 +20,13 @@ namespace Umbraco.Web.Controllers // TODO: This controller should be moved to a more suitable place. public class TagsController : UmbracoApiController { - /// - /// Initializes a new instance of the with auto dependencies. - /// public TagsController() - { } + { + } - /// - /// Initializes a new instance of the with all its dependencies. - /// - public TagsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) - { } + public TagsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } /// /// Get every tag stored in the database (with optional group) diff --git a/src/Umbraco.Web/Controllers/UmbLoginController.cs b/src/Umbraco.Web/Controllers/UmbLoginController.cs index 97444dbc6a..ea526f47a9 100644 --- a/src/Umbraco.Web/Controllers/UmbLoginController.cs +++ b/src/Umbraco.Web/Controllers/UmbLoginController.cs @@ -12,11 +12,12 @@ namespace Umbraco.Web.Controllers public class UmbLoginController : SurfaceController { public UmbLoginController() - { } + { + } - public UmbLoginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger) - { } + public UmbLoginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper) + { + } [HttpPost] [ValidateAntiForgeryToken] diff --git a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs b/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs index fddefbe4a9..e63f15b9c9 100644 --- a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs +++ b/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs @@ -14,11 +14,12 @@ namespace Umbraco.Web.Controllers public class UmbLoginStatusController : SurfaceController { public UmbLoginStatusController() - { } + { + } - public UmbLoginStatusController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger) - { } + public UmbLoginStatusController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper) + { + } [HttpPost] [ValidateAntiForgeryToken] diff --git a/src/Umbraco.Web/Controllers/UmbProfileController.cs b/src/Umbraco.Web/Controllers/UmbProfileController.cs index f22192a1cc..d30f08040e 100644 --- a/src/Umbraco.Web/Controllers/UmbProfileController.cs +++ b/src/Umbraco.Web/Controllers/UmbProfileController.cs @@ -17,8 +17,8 @@ namespace Umbraco.Web.Controllers public UmbProfileController() { } - public UmbProfileController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger) + public UmbProfileController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper) { } [HttpPost] diff --git a/src/Umbraco.Web/Controllers/UmbRegisterController.cs b/src/Umbraco.Web/Controllers/UmbRegisterController.cs index 726797c26a..a60b5cffdb 100644 --- a/src/Umbraco.Web/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web/Controllers/UmbRegisterController.cs @@ -14,11 +14,12 @@ namespace Umbraco.Web.Controllers public class UmbRegisterController : SurfaceController { public UmbRegisterController() - { } + { + } - public UmbRegisterController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger) - { } + public UmbRegisterController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper) + { + } [HttpPost] [ValidateAntiForgeryToken] diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 5804a00a79..f5652cc5fb 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -43,18 +43,9 @@ namespace Umbraco.Web.Editors private BackOfficeUserManager _userManager; private BackOfficeSignInManager _signInManager; - /// - /// Initializes a new instance of the new class with auto dependencies. - /// - public AuthenticationController() - { } - - /// - /// Initializes a new instance of the class with all its dependencies. - /// - public AuthenticationController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) - { } + public AuthenticationController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } protected BackOfficeUserManager UserManager => _userManager ?? (_userManager = TryGetOwinContext().Result.GetBackOfficeUserManager()); diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 462b5bbc9c..abe7930693 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -49,8 +49,8 @@ namespace Umbraco.Web.Editors private const string TokenPasswordResetCode = "PasswordResetCode"; private static readonly string[] TempDataTokenNames = { TokenExternalSignInError, TokenPasswordResetCode }; - public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger) + public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) { _manifestParser = manifestParser; _features = features; diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index e2d268450c..faaf14319f 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -54,8 +54,8 @@ namespace Umbraco.Web.Editors UmbracoContext umbracoContext, ISqlContext sqlContext, PropertyEditorCollection propertyEditors, ServiceContext services, AppCaches appCaches, - IProfilingLogger logger, IRuntimeState runtimeState) - : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _serializer = serializer; _propertyEditors = propertyEditors; diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs index fe91f9fff6..b3baaf3e03 100644 --- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs @@ -33,8 +33,8 @@ namespace Umbraco.Web.Editors private readonly ICultureDictionaryFactory _cultureDictionaryFactory; private ICultureDictionary _cultureDictionary; - protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _cultureDictionaryFactory = cultureDictionaryFactory; } diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web/Editors/DashboardController.cs index 8ae59b974c..9a9ab72845 100644 --- a/src/Umbraco.Web/Editors/DashboardController.cs +++ b/src/Umbraco.Web/Editors/DashboardController.cs @@ -31,18 +31,12 @@ namespace Umbraco.Web.Editors public class DashboardController : UmbracoApiController { private readonly IDashboardService _dashboardService; - - /// - /// Initializes a new instance of the with auto dependencies. - /// - public DashboardController() - { } - + /// /// Initializes a new instance of the with all its dependencies. /// - public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _dashboardService = dashboardService; } diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index ca747e83f5..97d800a845 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -45,8 +45,8 @@ namespace Umbraco.Web.Editors private readonly ITreeService _treeService; public EntityController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, - ITreeService treeService) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + ITreeService treeService, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _treeService = treeService; } diff --git a/src/Umbraco.Web/Editors/MacroRenderingController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs index 65abde759a..f88a84dd72 100644 --- a/src/Umbraco.Web/Editors/MacroRenderingController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -32,9 +32,12 @@ namespace Umbraco.Web.Editors { private readonly IMacroService _macroService; private readonly IContentService _contentService; + private readonly IUmbracoComponentRenderer _componentRenderer; private readonly IVariationContextAccessor _variationContextAccessor; - public MacroRenderingController(IVariationContextAccessor variationContextAccessor, IMacroService macroService, IContentService contentService) + + public MacroRenderingController(IUmbracoComponentRenderer componentRenderer, IVariationContextAccessor variationContextAccessor, IMacroService macroService, IContentService contentService) { + _componentRenderer = componentRenderer; _variationContextAccessor = variationContextAccessor; _macroService = macroService; _contentService = contentService; @@ -103,17 +106,14 @@ namespace Umbraco.Web.Editors var doc = _contentService.GetById(pageId); if (doc == null) - { throw new HttpResponseException(HttpStatusCode.NotFound); - } var m = _macroService.GetByAlias(macroAlias); if (m == null) throw new HttpResponseException(HttpStatusCode.NotFound); - var macro = new MacroModel(m); //if it isn't supposed to be rendered in the editor then return an empty string - if (macro.RenderInEditor == false) + if (!m.UseInEditor) { var response = Request.CreateResponse(); //need to create a specific content result formatted as HTML since this controller has been configured @@ -132,23 +132,24 @@ namespace Umbraco.Web.Editors // to set the current culture to the culture related to the content item. This is hacky but it works. var publishedContent = UmbracoContext.ContentCache.GetById(doc.Id); var culture = publishedContent?.GetCulture(); + _variationContextAccessor.VariationContext = new VariationContext(); //must have an active variation context! if (culture != null) { Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture.Culture); + _variationContextAccessor.VariationContext = new VariationContext(Thread.CurrentThread.CurrentCulture.Name); } - var legacyPage = new global::Umbraco.Web.Macros.PublishedContentHashtableConverter(doc, _variationContextAccessor); + //fixme: don't think we need this anymore + var legacyPage = new PublishedContentHashtableConverter(doc, _variationContextAccessor); UmbracoContext.HttpContext.Items["pageElements"] = legacyPage.Elements; UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; - var renderer = new UmbracoComponentRenderer(UmbracoContext); - var result = Request.CreateResponse(); //need to create a specific content result formatted as HTML since this controller has been configured //with only json formatters. result.Content = new StringContent( - renderer.RenderMacro(macro, macroParams, legacyPage).ToString(), + _componentRenderer.RenderMacro(doc.Id, m.Alias, macroParams).ToString(), Encoding.UTF8, "text/html"); return result; diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index bb126ed1dd..d041db1862 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -37,8 +37,7 @@ namespace Umbraco.Web.Editors [MediaTypeControllerControllerConfiguration] public class MediaTypeController : ContentTypeControllerBase { - public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { } diff --git a/src/Umbraco.Web/Editors/MemberTypeController.cs b/src/Umbraco.Web/Editors/MemberTypeController.cs index b200f17372..a1a9a97572 100644 --- a/src/Umbraco.Web/Editors/MemberTypeController.cs +++ b/src/Umbraco.Web/Editors/MemberTypeController.cs @@ -30,8 +30,7 @@ namespace Umbraco.Web.Editors [UmbracoTreeAuthorize(new string[] { Constants.Trees.MemberTypes, Constants.Trees.Members})] public class MemberTypeController : ContentTypeControllerBase { - public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index e96665ebb5..63be647a12 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -36,8 +36,8 @@ namespace Umbraco.Web.Editors { public PackageInstallController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, - IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { } diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs index f6973fcbb9..0a2f17cd15 100644 --- a/src/Umbraco.Web/Editors/SectionController.cs +++ b/src/Umbraco.Web/Editors/SectionController.cs @@ -27,8 +27,8 @@ namespace Umbraco.Web.Editors private readonly ITreeService _treeService; public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, - IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _dashboardService = dashboardService; _sectionService = sectionService; @@ -43,7 +43,7 @@ namespace Umbraco.Web.Editors // this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that // since tree's by nature are controllers and require request contextual data - var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService) + var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService, Umbraco) { ControllerContext = ControllerContext }; diff --git a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs index f76f62a99b..32e56965b3 100644 --- a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs +++ b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs @@ -20,24 +20,11 @@ namespace Umbraco.Web.Editors [AngularJsonOnlyConfiguration] public abstract class UmbracoAuthorizedJsonController : UmbracoAuthorizedApiController { - /// - /// Initializes a new instance of the with auto dependencies. - /// protected UmbracoAuthorizedJsonController() { } - /// - /// Initializes a new instance of the class with all its dependencies. - /// - /// - /// - /// - /// - /// - /// - /// - protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { } } diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index c5d2a65cb9..44d0cc27ca 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -92,13 +92,13 @@ namespace Umbraco.Web { throw new InvalidOperationException("Cannot cache by page if the UmbracoContext has not been initialized, this parameter can only be used in the context of an Umbraco request"); } - cacheKey.AppendFormat("{0}-", UmbracoContext.Current.PageId); + cacheKey.AppendFormat("{0}-", UmbracoContext.Current.PublishedRequest?.PublishedContent?.Id ?? 0); } if (cacheByMember) { var helper = Current.Factory.GetInstance(); var currentMember = helper.GetCurrentMember(); - cacheKey.AppendFormat("m{0}-", currentMember == null ? 0 : currentMember.Id); + cacheKey.AppendFormat("m{0}-", currentMember?.Id ?? 0); } if (contextualKeyBuilder != null) { diff --git a/src/Umbraco.Web/IUmbracoComponentRenderer.cs b/src/Umbraco.Web/IUmbracoComponentRenderer.cs index dc91cacdc0..4dc9036e6b 100644 --- a/src/Umbraco.Web/IUmbracoComponentRenderer.cs +++ b/src/Umbraco.Web/IUmbracoComponentRenderer.cs @@ -12,32 +12,35 @@ namespace Umbraco.Web /// /// Renders the template for the specified pageId and an optional altTemplateId /// - /// + /// /// If not specified, will use the template assigned to the node /// - IHtmlString RenderTemplate(int pageId, int? altTemplateId = null); + IHtmlString RenderTemplate(int contentId, int? altTemplateId = null); /// /// Renders the macro with the specified alias. /// + /// /// The alias. /// - IHtmlString RenderMacro(string alias); + IHtmlString RenderMacro(int contentId, string alias); /// /// Renders the macro with the specified alias, passing in the specified parameters. /// + /// /// The alias. /// The parameters. /// - IHtmlString RenderMacro(string alias, object parameters); + IHtmlString RenderMacro(int contentId, string alias, object parameters); /// /// Renders the macro with the specified alias, passing in the specified parameters. /// + /// /// The alias. /// The parameters. /// - IHtmlString RenderMacro(string alias, IDictionary parameters); + IHtmlString RenderMacro(int contentId, string alias, IDictionary parameters); } } diff --git a/src/Umbraco.Web/Macros/IMacroRenderer.cs b/src/Umbraco.Web/Macros/IMacroRenderer.cs new file mode 100644 index 0000000000..d858315403 --- /dev/null +++ b/src/Umbraco.Web/Macros/IMacroRenderer.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Web.Macros +{ + /// + /// Renders a macro + /// + public interface IMacroRenderer + { + MacroContent Render(string macroAlias, IPublishedContent content, IDictionary macroParams); + } +} diff --git a/src/Umbraco.Web/Macros/MacroModel.cs b/src/Umbraco.Web/Macros/MacroModel.cs index bea07cebc5..dd9a73b147 100644 --- a/src/Umbraco.Web/Macros/MacroModel.cs +++ b/src/Umbraco.Web/Macros/MacroModel.cs @@ -1,22 +1,25 @@ using System.Collections.Generic; -using System.Text.RegularExpressions; -using Umbraco.Core; -using Umbraco.Core.IO; using Umbraco.Core.Models; -using Umbraco.Core.Services.Implement; namespace Umbraco.Web.Macros { public class MacroModel { + /// + /// The Macro Id + /// public int Id { get; set; } + /// + /// The Macro Name + /// public string Name { get; set; } + /// + /// The Macro Alias + /// public string Alias { get; set; } - public string MacroControlIdentifier { get; set; } - public MacroTypes MacroType { get; set; } public string MacroSource { get; set; } diff --git a/src/Umbraco.Web/Macros/MacroRenderer.cs b/src/Umbraco.Web/Macros/MacroRenderer.cs index c975c4a60b..b0ea90f9c1 100755 --- a/src/Umbraco.Web/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web/Macros/MacroRenderer.cs @@ -3,45 +3,44 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; -using System.Net.Security; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; using System.Text; -using System.Text.RegularExpressions; -using System.Web; using System.Web.Caching; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Macros; using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; -using Umbraco.Web.Composing; namespace Umbraco.Web.Macros { - public class MacroRenderer + internal class MacroRenderer : IMacroRenderer { private readonly IProfilingLogger _plogger; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IContentSection _contentSection; + private readonly ILocalizedTextService _textService; + private readonly AppCaches _appCaches; + private readonly IMacroService _macroService; - // TODO: there are many more things that would need to be injected in here - - public MacroRenderer(IProfilingLogger plogger) + public MacroRenderer(IProfilingLogger plogger, IUmbracoContextAccessor umbracoContextAccessor, IContentSection contentSection, ILocalizedTextService textService, AppCaches appCaches, IMacroService macroService) { - _plogger = plogger; + _plogger = plogger ?? throw new ArgumentNullException(nameof(plogger)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _contentSection = contentSection ?? throw new ArgumentNullException(nameof(contentSection)); + _textService = textService; + _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); + _macroService = macroService ?? throw new ArgumentNullException(nameof(macroService)); } - // probably can do better - just porting from v7 - public IList Exceptions { get; } = new List(); - #region MacroContent cache // gets this macro content cache identifier - private static string GetContentCacheIdentifier(MacroModel model, int pageId) + private string GetContentCacheIdentifier(MacroModel model, int pageId) { var id = new StringBuilder(); @@ -55,8 +54,9 @@ namespace Umbraco.Web.Macros { object key = 0; - if (HttpContext.Current.User.Identity.IsAuthenticated) + if (_umbracoContextAccessor.UmbracoContext.HttpContext?.User?.Identity?.IsAuthenticated ?? false) { + //ugh, membershipproviders :( var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); var member = Core.Security.MembershipProviderExtensions.GetCurrentUser(provider); key = member?.ProviderUserKey ?? 0; @@ -71,34 +71,19 @@ namespace Umbraco.Web.Macros return id.ToString(); } - private static string GenerateCacheKeyFromCode(string input) - { - if (string.IsNullOrEmpty(input)) throw new ArgumentNullException(nameof(input)); - - // step 1, calculate MD5 hash from input - var md5 = MD5.Create(); - var inputBytes = Encoding.ASCII.GetBytes(input); - var hash = md5.ComputeHash(inputBytes); - - // step 2, convert byte array to hex string - var sb = new StringBuilder(); - foreach (var h in hash) sb.Append(h.ToString("X2")); - return sb.ToString(); - } - // gets this macro content from the cache // ensuring that it is appropriate to use the cache - private static MacroContent GetMacroContentFromCache(MacroModel model) + private MacroContent GetMacroContentFromCache(MacroModel model) { // only if cache is enabled - if (UmbracoContext.Current.InPreviewMode || model.CacheDuration <= 0) return null; + if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) return null; - var cache = Current.AppCaches.RuntimeCache; + var cache = _appCaches.RuntimeCache; var macroContent = cache.GetCacheItem(CacheKeys.MacroContentCacheKey + model.CacheIdentifier); if (macroContent == null) return null; - Current.Logger.Debug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier); + _plogger.Debug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier); // ensure that the source has not changed // note: does not handle dependencies, and never has @@ -107,13 +92,13 @@ namespace Umbraco.Web.Macros { if (macroSource.Exists == false) { - Current.Logger.Debug("Macro source does not exist anymore, ignore cache."); + _plogger.Debug("Macro source does not exist anymore, ignore cache."); return null; } if (macroContent.Date < macroSource.LastWriteTime) { - Current.Logger.Debug("Macro source has changed, ignore cache."); + _plogger.Debug("Macro source has changed, ignore cache."); return null; } } @@ -126,10 +111,10 @@ namespace Umbraco.Web.Macros } // stores macro content into the cache - private static void AddMacroContentToCache(MacroModel model, MacroContent macroContent) + private void AddMacroContentToCache(MacroModel model, MacroContent macroContent) { // only if cache is enabled - if (UmbracoContext.Current.InPreviewMode || model.CacheDuration <= 0) return; + if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) return; // just make sure... if (macroContent == null) return; @@ -150,7 +135,7 @@ namespace Umbraco.Web.Macros // remember when we cache the content macroContent.Date = DateTime.Now; - var cache = Current.AppCaches.RuntimeCache; + var cache = _appCaches.RuntimeCache; cache.Insert( CacheKeys.MacroContentCacheKey + model.CacheIdentifier, () => macroContent, @@ -158,7 +143,7 @@ namespace Umbraco.Web.Macros priority: CacheItemPriority.NotRemovable ); - Current.Logger.Debug("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier); + _plogger.Debug("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier); } // gets the macro source file name @@ -183,7 +168,7 @@ namespace Umbraco.Web.Macros // gets the macro source file // null if macro is not file-based - internal static FileInfo GetMacroFile(MacroModel model) + private static FileInfo GetMacroFile(MacroModel model) { var filename = GetMacroFileName(model); if (filename == null) return null; @@ -195,29 +180,17 @@ namespace Umbraco.Web.Macros return file.Exists ? file : null; } - #endregion - - #region MacroModel properties - // updates the model properties values according to the attributes - private static void UpdateMacroModelProperties(MacroModel model, Hashtable attributes) + private static void UpdateMacroModelProperties(MacroModel model, IDictionary macroParams) { foreach (var prop in model.Properties) { var key = prop.Key.ToLowerInvariant(); - prop.Value = attributes.ContainsKey(key) - ? attributes[key]?.ToString() ?? string.Empty + prop.Value = macroParams.ContainsKey(key) + ? macroParams[key]?.ToString() ?? string.Empty : string.Empty; } - } - - // generates the model properties according to the attributes - public static void GenerateMacroModelPropertiesFromAttributes(MacroModel model, Hashtable attributes) - { - foreach (string key in attributes.Keys) - model.Properties.Add(new MacroPropertyModel(key, attributes[key].ToString())); - } - + } #endregion #region Render/Execute @@ -226,16 +199,23 @@ namespace Umbraco.Web.Macros // referring to IPublishedContent we're rendering the macro against, // this is all so convoluted ;-( - public MacroContent Render(MacroModel macro, Hashtable pageElements, int pageId, Hashtable attributes) + public MacroContent Render(string macroAlias, IPublishedContent content, IDictionary macroParams) { - UpdateMacroModelProperties(macro, attributes); - return Render(macro, pageElements, pageId); + var m = _macroService.GetByAlias(macroAlias); + if (m == null) + throw new InvalidOperationException("No macro found by alias " + macroAlias); + + var page = new PublishedContentHashtableConverter(content); + + var macro = new MacroModel(m); + + UpdateMacroModelProperties(macro, macroParams); + return Render(macro, content, page.Elements); } - public MacroContent Render(MacroModel macro, Hashtable pageElements, int pageId) + private MacroContent Render(MacroModel macro, IPublishedContent content, IDictionary pageElements) { - // trigger MacroRendering event so that the model can be manipulated before rendering - OnMacroRendering(new MacroRenderingEventArgs(pageElements, pageId)); + if (content == null) throw new ArgumentNullException(nameof(content)); var macroInfo = $"Render Macro: {macro.Name}, type: {macro.MacroType}, cache: {macro.CacheDuration}"; using (_plogger.DebugDuration(macroInfo, "Rendered Macro.")) @@ -244,7 +224,7 @@ namespace Umbraco.Web.Macros foreach (var prop in macro.Properties) prop.Value = ParseAttribute(pageElements, prop.Value); - macro.CacheIdentifier = GetContentCacheIdentifier(macro, pageId); + macro.CacheIdentifier = GetContentCacheIdentifier(macro, content.Id); // get the macro from cache if it is there var macroContent = GetMacroContentFromCache(macro); @@ -258,7 +238,7 @@ namespace Umbraco.Web.Macros // this will take care of errors // it may throw, if we actually want to throw, so better not // catch anything here and let the exception be thrown - var attempt = ExecuteMacroOfType(macro); + var attempt = ExecuteMacroOfType(macro, content); // by convention ExecuteMacroByType must either throw or return a result // just check to avoid internal errors @@ -300,8 +280,6 @@ namespace Umbraco.Web.Macros } catch (Exception e) { - Exceptions.Add(e); - _plogger.Warn(e, "Failed {MsgIn}", msgIn); var macroErrorEventArgs = new MacroErrorEventArgs @@ -310,11 +288,9 @@ namespace Umbraco.Web.Macros Alias = macro.Alias, MacroSource = macro.MacroSource, Exception = e, - Behaviour = Current.Configs.Settings().Content.MacroErrorBehaviour + Behaviour = _contentSection.MacroErrorBehaviour }; - OnError(macroErrorEventArgs); - switch (macroErrorEventArgs.Behaviour) { case MacroErrorBehaviour.Inline: @@ -341,16 +317,17 @@ namespace Umbraco.Web.Macros /// Returns an attempt that is successful if the macro ran successfully. If the macro failed /// to run properly, the attempt fails, though it may contain a content. But for instance that content /// should not be cached. In that case the attempt may also contain an exception. - private Attempt ExecuteMacroOfType(MacroModel model) + private Attempt ExecuteMacroOfType(MacroModel model, IPublishedContent content) { + if (model == null) throw new ArgumentNullException(nameof(model)); + // ensure that we are running against a published node (ie available in XML) // that may not be the case if the macro is embedded in a RTE of an unpublished document - if (UmbracoContext.Current.PublishedRequest == null - || UmbracoContext.Current.PublishedRequest.HasPublishedContent == false) - return Attempt.Fail(new MacroContent { Text = "[macro]" }); + if (content == null) + return Attempt.Fail(new MacroContent { Text = "[macro failed (no content)]" }); - var textService = Current.Services.TextService; + var textService = _textService; switch (model.MacroType) { @@ -358,7 +335,7 @@ namespace Umbraco.Web.Macros return ExecuteMacroWithErrorWrapper(model, $"Executing PartialView: MacroSource=\"{model.MacroSource}\".", "Executed PartialView.", - () => ExecutePartialView(model), + () => ExecutePartialView(model, content), () => textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource })); default: @@ -370,21 +347,6 @@ namespace Umbraco.Web.Macros } } - // raised when a macro triggers an error - public static event TypedEventHandler Error; - - protected void OnError(MacroErrorEventArgs e) - { - Error?.Invoke(this, e); - } - - // raised before the macro renders, allowing devs to modify it - public static event TypedEventHandler MacroRendering; - - protected void OnMacroRendering(MacroRenderingEventArgs e) - { - MacroRendering?.Invoke(this, e); - } #endregion @@ -394,10 +356,9 @@ namespace Umbraco.Web.Macros /// Renders a PartialView Macro. /// /// The text output of the macro execution. - private static MacroContent ExecutePartialView(MacroModel macro) + private MacroContent ExecutePartialView(MacroModel macro, IPublishedContent content) { var engine = new PartialViewMacroEngine(); - var content = UmbracoContext.Current.PublishedRequest.PublishedContent; return engine.Execute(macro, content); } @@ -407,8 +368,9 @@ namespace Umbraco.Web.Macros // parses attribute value looking for [@requestKey], [%sessionKey], [#pageElement], [$recursiveValue] // supports fallbacks eg "[@requestKey],[%sessionKey],1234" - public static string ParseAttribute(IDictionary pageElements, string attributeValue) + private string ParseAttribute(IDictionary pageElements, string attributeValue) { + if (pageElements == null) throw new ArgumentNullException(nameof(pageElements)); // check for potential querystring/cookie variables attributeValue = attributeValue.Trim(); @@ -431,7 +393,7 @@ namespace Umbraco.Web.Macros return attributeValue; } - var context = HttpContext.Current; + var context = _umbracoContextAccessor.UmbracoContext.HttpContext; foreach (var token in tokens) { @@ -458,11 +420,9 @@ namespace Umbraco.Web.Macros attributeValue = context?.Request.GetCookieValue(name); break; case '#': - if (pageElements == null) pageElements = GetPageElements(); attributeValue = pageElements[name]?.ToString(); break; case '$': - if (pageElements == null) pageElements = GetPageElements(); attributeValue = pageElements[name]?.ToString(); if (string.IsNullOrEmpty(attributeValue)) attributeValue = ParseAttributeOnParents(pageElements, name); @@ -477,12 +437,13 @@ namespace Umbraco.Web.Macros return attributeValue; } - private static string ParseAttributeOnParents(IDictionary pageElements, string name) + private string ParseAttributeOnParents(IDictionary pageElements, string name) { + if (pageElements == null) throw new ArgumentNullException(nameof(pageElements)); // this was, and still is, an ugly piece of nonsense var value = string.Empty; - var cache = UmbracoContext.Current.ContentCache; // should be injected + var cache = _umbracoContextAccessor.UmbracoContext.ContentCache; var splitpath = (string[])pageElements["splitpath"]; for (var i = splitpath.Length - 1; i > 0; i--) // at 0 we have root (-1) @@ -495,195 +456,9 @@ namespace Umbraco.Web.Macros return value; } - - private static IDictionary GetPageElements() - { - IDictionary pageElements = null; - if (HttpContext.Current.Items["pageElements"] != null) - pageElements = (IDictionary)HttpContext.Current.Items["pageElements"]; - return pageElements; - } - - #endregion - - #region RTE macros - - public static string RenderMacroStartTag(Hashtable attributes, int pageId, Guid versionId) - { - var div = "
"; - - return div; - } - - private static string EncodeMacroAttribute(string attributeContents) - { - // replace line breaks - attributeContents = attributeContents.Replace("\n", "\\n").Replace("\r", "\\r"); - - // replace quotes - attributeContents = attributeContents.Replace("\"", """); - - // replace tag start/ends - attributeContents = attributeContents.Replace("<", "<").Replace(">", ">"); - - return attributeContents; - } - - public static string RenderMacroEndTag() - { - return "
"; - } - - private static readonly Regex HrefRegex = new Regex("href=\"([^\"]*)\"", - RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - - public static string GetRenderedMacro(int macroId, Hashtable elements, Hashtable attributes, int pageId, IMacroService macroService, IProfilingLogger plogger) - { - var m = macroService.GetById(macroId); - if (m == null) return string.Empty; - var model = new MacroModel(m); - - // get as text, will render the control if any - var renderer = new MacroRenderer(plogger); - var macroContent = renderer.Render(model, elements, pageId); - var text = macroContent.GetAsText(); - - // remove hrefs - text = HrefRegex.Replace(text, match => "href=\"javascript:void(0)\""); - - return text; - } - - public static string MacroContentByHttp(int pageId, Guid pageVersion, Hashtable attributes, IMacroService macroService) - { - // though... we only support FullTrust now? - if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted) - return "Cannot render macro content in the rich text editor when the application is running in a Partial Trust environment"; - - var tempAlias = attributes["macroalias"]?.ToString() ?? attributes["macroAlias"].ToString(); - - var m = macroService.GetByAlias(tempAlias); - if (m == null) return string.Empty; - var macro = new MacroModel(m); - if (macro.RenderInEditor == false) - return ShowNoMacroContent(macro); - - var querystring = $"umbPageId={pageId}&umbVersionId={pageVersion}"; - var ide = attributes.GetEnumerator(); - while (ide.MoveNext()) - querystring += $"&umb_{ide.Key}={HttpContext.Current.Server.UrlEncode((ide.Value ?? String.Empty).ToString())}"; - - // create a new 'HttpWebRequest' object to the mentioned URL. - var useSsl = Current.Configs.Global().UseHttps; - var protocol = useSsl ? "https" : "http"; - var currentRequest = HttpContext.Current.Request; - var serverVars = currentRequest.ServerVariables; - var umbracoDir = IOHelper.ResolveUrl(SystemDirectories.Umbraco); - var url = $"{protocol}://{serverVars["SERVER_NAME"]}:{serverVars["SERVER_PORT"]}{umbracoDir}/macroResultWrapper.aspx?{querystring}"; - - var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); - - // allows for validation of SSL conversations (to bypass SSL errors in debug mode!) - ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate; - - // propagate the user's context - // TODO: this is the worst thing ever. - // also will not work if people decide to put their own custom auth system in place. - var inCookie = currentRequest.Cookies[Current.Configs.Settings().Security.AuthCookieName]; - if (inCookie == null) throw new NullReferenceException("No auth cookie found"); - var cookie = new Cookie(inCookie.Name, inCookie.Value, inCookie.Path, serverVars["SERVER_NAME"]); - myHttpWebRequest.CookieContainer = new CookieContainer(); - myHttpWebRequest.CookieContainer.Add(cookie); - - // assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable. - HttpWebResponse myHttpWebResponse = null; - var text = string.Empty; - try - { - myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); - if (myHttpWebResponse.StatusCode == HttpStatusCode.OK) - { - var streamResponse = myHttpWebResponse.GetResponseStream(); - if (streamResponse == null) - throw new Exception("Internal error, no response stream."); - var streamRead = new StreamReader(streamResponse); - var readBuff = new char[256]; - var count = streamRead.Read(readBuff, 0, 256); - while (count > 0) - { - var outputData = new string(readBuff, 0, count); - text += outputData; - count = streamRead.Read(readBuff, 0, 256); - } - - streamResponse.Close(); - streamRead.Close(); - - // find the content of a form - const string grabStart = ""; - const string grabEnd = ""; - - var grabStartPos = text.InvariantIndexOf(grabStart) + grabStart.Length; - var grabEndPos = text.InvariantIndexOf(grabEnd) - grabStartPos; - text = text.Substring(grabStartPos, grabEndPos); - } - else - { - text = ShowNoMacroContent(macro); - } - } - catch (Exception) - { - text = ShowNoMacroContent(macro); - } - finally - { - // release the HttpWebResponse Resource. - myHttpWebResponse?.Close(); - } - - return text.Replace("\n", string.Empty).Replace("\r", string.Empty); - } - - private static string ShowNoMacroContent(MacroModel model) - { - var name = HttpUtility.HtmlEncode(model.Name); // safe - return $"{name}
No macro content available for WYSIWYG editing
"; - } - - private static bool ValidateRemoteCertificate( - object sender, - X509Certificate certificate, - X509Chain chain, - SslPolicyErrors policyErrors - ) - { - // allow any old dodgy certificate in debug mode - return GlobalSettings.DebugMode || policyErrors == SslPolicyErrors.None; - } - + #endregion + } - public class MacroRenderingEventArgs : EventArgs - { - public MacroRenderingEventArgs(Hashtable pageElements, int pageId) - { - PageElements = pageElements; - PageId = pageId; - } - - public int PageId { get; } - - public Hashtable PageElements { get; } - } } diff --git a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs index ece76090d8..faf33a74cb 100644 --- a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs +++ b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs @@ -30,14 +30,13 @@ namespace Umbraco.Web.Macros /// internal PublishedContentHashtableConverter(PublishedRequest frequest) { - if (!frequest.HasPublishedContent) - throw new ArgumentException("Document request has no node.", "frequest"); + throw new ArgumentException("Document request has no node.", nameof(frequest)); PopulatePageData(frequest.PublishedContent.Id, frequest.PublishedContent.Name, frequest.PublishedContent.ContentType.Id, frequest.PublishedContent.ContentType.Alias, frequest.PublishedContent.WriterName, frequest.PublishedContent.CreatorName, frequest.PublishedContent.CreateDate, frequest.PublishedContent.UpdateDate, - frequest.PublishedContent.Path, frequest.PublishedContent.Parent == null ? -1 : frequest.PublishedContent.Parent.Id); + frequest.PublishedContent.Path, frequest.PublishedContent.Parent?.Id ?? -1); if (frequest.HasTemplate) { @@ -54,12 +53,12 @@ namespace Umbraco.Web.Macros /// internal PublishedContentHashtableConverter(IPublishedContent doc) { - if (doc == null) throw new ArgumentNullException("doc"); + if (doc == null) throw new ArgumentNullException(nameof(doc)); PopulatePageData(doc.Id, doc.Name, doc.ContentType.Id, doc.ContentType.Alias, doc.WriterName, doc.CreatorName, doc.CreateDate, doc.UpdateDate, - doc.Path, doc.Parent == null ? -1 : doc.Parent.Id); + doc.Path, doc.Parent?.Id ?? -1); if (doc.TemplateId.HasValue) { @@ -132,6 +131,7 @@ namespace Umbraco.Web.Macros /// public Hashtable Elements { get; } = new Hashtable(); + #region PublishedContent private class PagePublishedProperty : PublishedPropertyBase diff --git a/src/Umbraco.Web/Models/Mapping/RedirectUrlMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/RedirectUrlMapperProfile.cs index 53baa13379..5899c79b72 100644 --- a/src/Umbraco.Web/Models/Mapping/RedirectUrlMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/RedirectUrlMapperProfile.cs @@ -9,12 +9,14 @@ namespace Umbraco.Web.Models.Mapping internal class RedirectUrlMapperProfile : Profile { - public RedirectUrlMapperProfile() + public RedirectUrlMapperProfile(IUmbracoContextAccessor umbracoContextAccessor) { CreateMap() .ForMember(x => x.OriginalUrl, expression => expression.MapFrom(item => Current.UmbracoContext.UrlProvider.GetUrlFromRoute(item.ContentId, item.Url, item.Culture))) - .ForMember(x => x.DestinationUrl, expression => expression.MapFrom(item => item.ContentId > 0 ? new UmbracoHelper(Current.UmbracoContext, Current.Services).Url(item.ContentId, item.Culture) : "#")) + .ForMember(x => x.DestinationUrl, expression => expression.MapFrom(item => item.ContentId > 0 ? GetUrl(umbracoContextAccessor, item) : "#")) .ForMember(x => x.RedirectId, expression => expression.MapFrom(item => item.Key)); } + + private static string GetUrl(IUmbracoContextAccessor umbracoContextAccessor, IRedirectUrl item) => umbracoContextAccessor?.UmbracoContext?.UrlProvider?.GetUrl(item.Id, item.Culture); } } diff --git a/src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs b/src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs index 62a7c48d2b..bba1522350 100644 --- a/src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs +++ b/src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs @@ -79,8 +79,7 @@ namespace Umbraco.Web.Mvc /// /// Exposes an UmbracoHelper /// - protected UmbracoHelper Umbraco => _helper - ?? (_helper = new UmbracoHelper(Current.UmbracoContext, Current.Services)); + protected UmbracoHelper Umbraco => _helper ?? (_helper = Current.Factory.GetInstance()); public override void OnActionExecuted(ActionExecutedContext filterContext) { diff --git a/src/Umbraco.Web/Mvc/PluginController.cs b/src/Umbraco.Web/Mvc/PluginController.cs index e3f4b45ce6..8f113dc0a4 100644 --- a/src/Umbraco.Web/Mvc/PluginController.cs +++ b/src/Umbraco.Web/Mvc/PluginController.cs @@ -20,8 +20,6 @@ namespace Umbraco.Web.Mvc private static readonly ConcurrentDictionary MetadataStorage = new ConcurrentDictionary(); - private UmbracoHelper _umbracoHelper; - // for debugging purposes internal Guid InstanceId { get; } = Guid.NewGuid(); @@ -70,18 +68,7 @@ namespace Umbraco.Web.Mvc /// /// Gets the Umbraco helper. /// - public UmbracoHelper Umbraco - { - get - { - return _umbracoHelper - ?? (_umbracoHelper = new UmbracoHelper(UmbracoContext, Services)); - } - internal set // tests - { - _umbracoHelper = value; - } - } + public UmbracoHelper Umbraco { get; } /// /// Gets metadata for this instance. @@ -95,12 +82,13 @@ namespace Umbraco.Web.Mvc Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance() + Current.Factory.GetInstance(), + Current.Factory.GetInstance() ) { } - protected PluginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) + protected PluginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) { UmbracoContext = umbracoContext; DatabaseFactory = databaseFactory; @@ -108,6 +96,7 @@ namespace Umbraco.Web.Mvc AppCaches = appCaches; Logger = logger; ProfilingLogger = profilingLogger; + Umbraco = umbracoHelper; } /// diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index e5ad2bb01e..da7e3b08fc 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -23,8 +23,8 @@ namespace Umbraco.Web.Mvc ActionInvoker = new RenderActionInvoker(); } - public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger) + public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) { ActionInvoker = new RenderActionInvoker(); } @@ -32,7 +32,7 @@ namespace Umbraco.Web.Mvc /// /// Gets the Umbraco context. /// - public override UmbracoContext UmbracoContext => PublishedRequest.UmbracoContext; + public override UmbracoContext UmbracoContext => PublishedRequest.UmbracoContext; //TODO: Why? /// /// Gets the current content item. diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs index 2bf73b7dd1..05c095940c 100644 --- a/src/Umbraco.Web/Mvc/SurfaceController.cs +++ b/src/Umbraco.Web/Mvc/SurfaceController.cs @@ -19,8 +19,8 @@ namespace Umbraco.Web.Mvc protected SurfaceController() { } - protected SurfaceController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger) + protected SurfaceController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper) { } /// diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs index 89364fe9cf..a54958c4f7 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs @@ -18,10 +18,11 @@ namespace Umbraco.Web.Mvc public abstract class UmbracoAuthorizedController : UmbracoController { protected UmbracoAuthorizedController() - { } + { + } - protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) - : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger) - { } + protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) + { + } } } diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs index 4d70263cb8..61198bd263 100644 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoController.cs @@ -17,15 +17,13 @@ namespace Umbraco.Web.Mvc /// public abstract class UmbracoController : Controller { - private UmbracoHelper _umbracoHelper; - // for debugging purposes internal Guid InstanceId { get; } = Guid.NewGuid(); /// /// Gets or sets the Umbraco context. /// - public virtual IGlobalSettings GlobalSettings { get; set; } + public IGlobalSettings GlobalSettings { get; set; } /// /// Gets or sets the Umbraco context. @@ -62,8 +60,7 @@ namespace Umbraco.Web.Mvc /// /// Gets the Umbraco helper. /// - public UmbracoHelper Umbraco => _umbracoHelper - ?? (_umbracoHelper = new UmbracoHelper(UmbracoContext, Services)); + public UmbracoHelper Umbraco { get; } /// /// Gets the web security helper. @@ -77,12 +74,13 @@ namespace Umbraco.Web.Mvc Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance() + Current.Factory.GetInstance(), + Current.Factory.GetInstance() ) { } - protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) + protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) { GlobalSettings = globalSettings; UmbracoContext = umbracoContext; @@ -90,6 +88,7 @@ namespace Umbraco.Web.Mvc AppCaches = appCaches; Logger = logger; ProfilingLogger = profilingLogger; + Umbraco = umbracoHelper; } } } diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs index a16f9661aa..2dcb883ed3 100644 --- a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs +++ b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -84,7 +85,7 @@ namespace Umbraco.Web.Mvc /// /// Gets the Umbraco helper. /// - public virtual UmbracoHelper Umbraco + public UmbracoHelper Umbraco { get { @@ -94,9 +95,12 @@ namespace Umbraco.Web.Mvc var content = model as IPublishedContent; if (content == null && model is IContentModel) content = ((IContentModel) model).Content; - _helper = content == null - ? new UmbracoHelper(UmbracoContext, Services) - : new UmbracoHelper(UmbracoContext, Services, content); + + _helper = Current.UmbracoHelper; + + if (content != null) + _helper.AssignedContentItem = content; + return _helper; } } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs index 5a0fc87cb0..e6e66b79ff 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs @@ -20,12 +20,12 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public class MacroContainerValueConverter : PropertyValueConverterBase { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly ServiceContext _services; + private readonly IMacroRenderer _macroRenderer; - public MacroContainerValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services) + public MacroContainerValueConverter(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); - _services = services ?? throw new ArgumentNullException(nameof(services)); + _macroRenderer = macroRenderer ?? throw new ArgumentNullException(nameof(macroRenderer)); } public override bool IsConverter(PublishedPropertyType propertyType) @@ -48,14 +48,14 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var sb = new StringBuilder(); - var umbracoHelper = new UmbracoHelper(umbracoContext, _services); MacroTagParser.ParseMacros( source, //callback for when text block is found textBlock => sb.Append(textBlock), //callback for when macro syntax is found - (macroAlias, macroAttributes) => sb.Append(umbracoHelper.RenderMacro( + (macroAlias, macroAttributes) => sb.Append(_macroRenderer.Render( macroAlias, + umbracoContext.PublishedRequest?.PublishedContent, //needs to be explicitly casted to Dictionary macroAttributes.ConvertTo(x => (string)x, x => x)).ToString())); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 7a089b6f9e..e636369c74 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public class RteMacroRenderingValueConverter : TinyMceValueConverter { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly ServiceContext _services; + private readonly IMacroRenderer _macroRenderer; public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) { @@ -30,10 +30,10 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return PropertyCacheLevel.Snapshot; } - public RteMacroRenderingValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services) + public RteMacroRenderingValueConverter(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer) { _umbracoContextAccessor = umbracoContextAccessor; - _services = services; + _macroRenderer = macroRenderer; } // NOT thread-safe over a request because it modifies the @@ -47,14 +47,14 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var sb = new StringBuilder(); - var umbracoHelper = new UmbracoHelper(umbracoContext, _services); MacroTagParser.ParseMacros( source, //callback for when text block is found textBlock => sb.Append(textBlock), //callback for when macro syntax is found - (macroAlias, macroAttributes) => sb.Append(umbracoHelper.RenderMacro( + (macroAlias, macroAttributes) => sb.Append(_macroRenderer.Render( macroAlias, + umbracoContext.PublishedRequest?.PublishedContent, //needs to be explicitly casted to Dictionary macroAttributes.ConvertTo(x => (string)x, x => x)).ToString())); diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index de3ca47b38..27c42e2c91 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -23,6 +23,7 @@ using Umbraco.Web.Dictionary; using Umbraco.Web.Editors; using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; +using Umbraco.Web.Macros; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; @@ -32,6 +33,7 @@ using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; using Umbraco.Web.Services; using Umbraco.Web.SignalR; +using Umbraco.Web.Templates; using Umbraco.Web.Tour; using Umbraco.Web.Trees; using Umbraco.Web.WebApi; @@ -85,8 +87,19 @@ namespace Umbraco.Web.Runtime // TODO: stop doing this composition.Register(factory => factory.GetInstance().UmbracoContext, Lifetime.Request); - // register the umbraco helper - composition.RegisterUnique(); + composition.Register(factory => + { + var umbCtx = factory.GetInstance(); + return new PublishedContentQuery(umbCtx.UmbracoContext.ContentCache, umbCtx.UmbracoContext.MediaCache, factory.GetInstance()); + }, Lifetime.Request); + composition.Register(Lifetime.Request); + + composition.RegisterUnique(); + composition.RegisterUnique(); + composition.RegisterUnique(); + + // register the umbraco helper - this is Transient! very important! + composition.Register(); // register distributed cache composition.RegisterUnique(f => new DistributedCache()); diff --git a/src/Umbraco.Web/Templates/ITemplateRenderer.cs b/src/Umbraco.Web/Templates/ITemplateRenderer.cs new file mode 100644 index 0000000000..f01edc58ed --- /dev/null +++ b/src/Umbraco.Web/Templates/ITemplateRenderer.cs @@ -0,0 +1,12 @@ +using System.IO; + +namespace Umbraco.Web.Templates +{ + /// + /// This is used purely for the RenderTemplate functionality in Umbraco + /// + public interface ITemplateRenderer + { + void Render(int pageId, int? altTemplateId, StringWriter writer); + } +} diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index 9279eea124..facafdea63 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Globalization; using System.IO; using System.Linq; @@ -9,6 +10,7 @@ using Umbraco.Web.Models; using Umbraco.Web.Mvc; using Umbraco.Web.Routing; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Services; using Umbraco.Web.Macros; using Current = Umbraco.Web.Composing.Current; @@ -21,92 +23,81 @@ namespace Umbraco.Web.Templates /// /// This allows you to render an MVC template based purely off of a node id and an optional alttemplate id as string output. /// - internal class TemplateRenderer + internal class TemplateRenderer : ITemplateRenderer { - private readonly UmbracoContext _umbracoContext; - private object _oldPageElements; - private PublishedRequest _oldPublishedRequest; - private object _oldAltTemplate; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly PublishedRouter _publishedRouter; + private readonly IFileService _fileService; + private readonly ILocalizationService _languageService; + private readonly IWebRoutingSection _webRoutingSection; - public TemplateRenderer(UmbracoContext umbracoContext, int pageId, int? altTemplateId) + public TemplateRenderer(IUmbracoContextAccessor umbracoContextAccessor, PublishedRouter publishedRouter, IFileService fileService, ILocalizationService textService, IWebRoutingSection webRoutingSection) { - PageId = pageId; - AltTemplateId = altTemplateId; - _umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter)); + _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); + _languageService = textService ?? throw new ArgumentNullException(nameof(textService)); + _webRoutingSection = webRoutingSection ?? throw new ArgumentNullException(nameof(webRoutingSection)); } - - private IFileService FileService => Current.Services.FileService; // TODO: inject - private PublishedRouter PublishedRouter => Core.Composing.Current.Factory.GetInstance(); // TODO: inject - - - /// - /// Gets/sets the page id for the template to render - /// - public int PageId { get; } - - /// - /// Gets/sets the alt template to render if there is one - /// - public int? AltTemplateId { get; } - - public void Render(StringWriter writer) + + public void Render(int pageId, int? altTemplateId, StringWriter writer) { if (writer == null) throw new ArgumentNullException(nameof(writer)); // instantiate a request and process // important to use CleanedUmbracoUrl - lowercase path-only version of the current url, though this isn't going to matter // terribly much for this implementation since we are just creating a doc content request to modify it's properties manually. - var contentRequest = PublishedRouter.CreateRequest(_umbracoContext); + var contentRequest = _publishedRouter.CreateRequest(_umbracoContextAccessor.UmbracoContext); - var doc = contentRequest.UmbracoContext.ContentCache.GetById(PageId); + var doc = contentRequest.UmbracoContext.ContentCache.GetById(pageId); if (doc == null) { - writer.Write("", PageId); + writer.Write("", pageId); return; } //in some cases the UmbracoContext will not have a PublishedContentRequest assigned to it if we are not in the //execution of a front-end rendered page. In this case set the culture to the default. //set the culture to the same as is currently rendering - if (_umbracoContext.PublishedRequest == null) + if (_umbracoContextAccessor.UmbracoContext.PublishedRequest == null) { - var defaultLanguage = Current.Services.LocalizationService.GetAllLanguages().FirstOrDefault(); + var defaultLanguage = _languageService.GetAllLanguages().FirstOrDefault(); contentRequest.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : defaultLanguage.CultureInfo; } else { - contentRequest.Culture = _umbracoContext.PublishedRequest.Culture; + contentRequest.Culture = _umbracoContextAccessor.UmbracoContext.PublishedRequest.Culture; } //set the doc that was found by id contentRequest.PublishedContent = doc; //set the template, either based on the AltTemplate found or the standard template of the doc - var templateId = Current.Configs.Settings().WebRouting.DisableAlternativeTemplates || !AltTemplateId.HasValue + var templateId = _webRoutingSection.DisableAlternativeTemplates || !altTemplateId.HasValue ? doc.TemplateId - : AltTemplateId.Value; + : altTemplateId.Value; if (templateId.HasValue) - contentRequest.TemplateModel = FileService.GetTemplate(templateId.Value); + contentRequest.TemplateModel = _fileService.GetTemplate(templateId.Value); //if there is not template then exit if (contentRequest.HasTemplate == false) { - if (AltTemplateId.HasValue == false) + if (altTemplateId.HasValue == false) { writer.Write("", doc.TemplateId); } else { - writer.Write("", AltTemplateId); + writer.Write("", altTemplateId); } return; } //First, save all of the items locally that we know are used in the chain of execution, we'll need to restore these //after this page has rendered. - SaveExistingItems(); + SaveExistingItems(out var oldPageElements, out var oldPublishedRequest, out var oldAltTemplate); try { @@ -119,7 +110,7 @@ namespace Umbraco.Web.Templates finally { //restore items on context objects to continuing rendering the parent template - RestoreItems(); + RestoreItems(oldPageElements, oldPublishedRequest, oldAltTemplate); } } @@ -134,11 +125,11 @@ namespace Umbraco.Web.Templates //var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys // .ToDictionary(key => key, key => context.Request.QueryString[key]); - var requestContext = new RequestContext(_umbracoContext.HttpContext, new RouteData() + var requestContext = new RequestContext(_umbracoContextAccessor.UmbracoContext.HttpContext, new RouteData() { Route = RouteTable.Routes["Umbraco_default"] }); - var routeHandler = new RenderRouteHandler(_umbracoContext, ControllerBuilder.Current.GetControllerFactory()); + var routeHandler = new RenderRouteHandler(_umbracoContextAccessor, ControllerBuilder.Current.GetControllerFactory()); var routeDef = routeHandler.GetUmbracoRouteDefinition(requestContext, request); var renderModel = new ContentModel(request.PublishedContent); //manually add the action/controller, this is required by mvc @@ -184,31 +175,31 @@ namespace Umbraco.Web.Templates // handlers like default.aspx will want it and most macros currently need it request.LegacyContentHashTable = new PublishedContentHashtableConverter(request); //now, set the new ones for this page execution - _umbracoContext.HttpContext.Items["pageElements"] = request.LegacyContentHashTable.Elements; - _umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; - _umbracoContext.PublishedRequest = request; + _umbracoContextAccessor.UmbracoContext.HttpContext.Items["pageElements"] = request.LegacyContentHashTable.Elements; + _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; + _umbracoContextAccessor.UmbracoContext.PublishedRequest = request; } /// /// Save all items that we know are used for rendering execution to variables so we can restore after rendering /// - private void SaveExistingItems() + private void SaveExistingItems(out object oldPageElements, out PublishedRequest oldPublishedRequest, out object oldAltTemplate) { //Many objects require that these legacy items are in the http context items... before we render this template we need to first //save the values in them so that we can re-set them after we render so the rest of the execution works as per normal - _oldPageElements = _umbracoContext.HttpContext.Items["pageElements"]; - _oldPublishedRequest = _umbracoContext.PublishedRequest; - _oldAltTemplate = _umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate]; + oldPageElements = _umbracoContextAccessor.UmbracoContext.HttpContext.Items["pageElements"]; + oldPublishedRequest = _umbracoContextAccessor.UmbracoContext.PublishedRequest; + oldAltTemplate = _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate]; } /// /// Restores all items back to their context's to continue normal page rendering execution /// - private void RestoreItems() + private void RestoreItems(object oldPageElements, PublishedRequest oldPublishedRequest, object oldAltTemplate) { - _umbracoContext.PublishedRequest = _oldPublishedRequest; - _umbracoContext.HttpContext.Items["pageElements"] = _oldPageElements; - _umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = _oldAltTemplate; + _umbracoContextAccessor.UmbracoContext.PublishedRequest = oldPublishedRequest; + _umbracoContextAccessor.UmbracoContext.HttpContext.Items["pageElements"] = oldPageElements; + _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = oldAltTemplate; } } } diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 605d5e4352..68d7fbb3fd 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -36,8 +36,8 @@ namespace Umbraco.Web.Trees public ApplicationTreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, - IRuntimeState runtimeState, ITreeService treeService) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + IRuntimeState runtimeState, ITreeService treeService, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _treeService = treeService; } diff --git a/src/Umbraco.Web/Trees/TreeController.cs b/src/Umbraco.Web/Trees/TreeController.cs index e6d948e19a..be0b862988 100644 --- a/src/Umbraco.Web/Trees/TreeController.cs +++ b/src/Umbraco.Web/Trees/TreeController.cs @@ -18,8 +18,8 @@ namespace Umbraco.Web.Trees private readonly TreeAttribute _treeAttribute; - protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _treeAttribute = GetTreeAttribute(); } diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs index 8632c15d24..e3946ce532 100644 --- a/src/Umbraco.Web/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs @@ -27,11 +27,12 @@ namespace Umbraco.Web.Trees public abstract class TreeControllerBase : UmbracoAuthorizedApiController, ITree { protected TreeControllerBase() - { } + { + } - protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) - { } + protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } /// /// The method called to render the contents of the tree structure diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f078e9d79f..9b685550a8 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -143,6 +143,7 @@ + @@ -194,6 +195,7 @@ + diff --git a/src/Umbraco.Web/UmbracoAuthorizedHttpHandler.cs b/src/Umbraco.Web/UmbracoAuthorizedHttpHandler.cs index 1d8475111f..b18ba55799 100644 --- a/src/Umbraco.Web/UmbracoAuthorizedHttpHandler.cs +++ b/src/Umbraco.Web/UmbracoAuthorizedHttpHandler.cs @@ -2,6 +2,7 @@ using System.Security; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Logging; using Umbraco.Web.Security; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -11,10 +12,10 @@ namespace Umbraco.Web public abstract class UmbracoAuthorizedHttpHandler : UmbracoHttpHandler { protected UmbracoAuthorizedHttpHandler() - { } + { + } - protected UmbracoAuthorizedHttpHandler(UmbracoContext umbracoContext, ServiceContext services) - : base(umbracoContext, services) + protected UmbracoAuthorizedHttpHandler(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper, ServiceContext service, IProfilingLogger plogger) : base(umbracoContext, umbracoHelper, service, plogger) { } diff --git a/src/Umbraco.Web/UmbracoComponentRenderer.cs b/src/Umbraco.Web/UmbracoComponentRenderer.cs index f59962a0f2..4ce25acb29 100644 --- a/src/Umbraco.Web/UmbracoComponentRenderer.cs +++ b/src/Umbraco.Web/UmbracoComponentRenderer.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections; using System.IO; using System.Web; @@ -6,6 +7,9 @@ using System.Web.UI; using Umbraco.Core; using Umbraco.Web.Templates; using System.Collections.Generic; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Macros; @@ -20,31 +24,34 @@ namespace Umbraco.Web /// internal class UmbracoComponentRenderer : IUmbracoComponentRenderer { - private readonly UmbracoContext _umbracoContext; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IMacroRenderer _macroRenderer; + private readonly ITemplateRenderer _templateRenderer; - public UmbracoComponentRenderer(UmbracoContext umbracoContext) + public UmbracoComponentRenderer(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer, ITemplateRenderer templateRenderer) { - _umbracoContext = umbracoContext; + _umbracoContextAccessor = umbracoContextAccessor; + _macroRenderer = macroRenderer; + _templateRenderer = templateRenderer ?? throw new ArgumentNullException(nameof(templateRenderer)); } /// /// Renders the template for the specified pageId and an optional altTemplateId /// - /// + /// /// If not specified, will use the template assigned to the node /// - public IHtmlString RenderTemplate(int pageId, int? altTemplateId = null) + public IHtmlString RenderTemplate(int contentId, int? altTemplateId = null) { - var templateRenderer = new TemplateRenderer(_umbracoContext, pageId, altTemplateId); using (var sw = new StringWriter()) { try { - templateRenderer.Render(sw); + _templateRenderer.Render(contentId, altTemplateId, sw); } catch (Exception ex) { - sw.Write("", pageId, ex); + sw.Write("", contentId, ex); } return new HtmlString(sw.ToString()); } @@ -53,129 +60,107 @@ namespace Umbraco.Web /// /// Renders the macro with the specified alias. /// + /// /// The alias. /// - public IHtmlString RenderMacro(string alias) + public IHtmlString RenderMacro(int contentId, string alias) { - return RenderMacro(alias, new { }); + return RenderMacro(contentId, alias, new { }); } /// /// Renders the macro with the specified alias, passing in the specified parameters. /// + /// /// The alias. /// The parameters. /// - public IHtmlString RenderMacro(string alias, object parameters) + public IHtmlString RenderMacro(int contentId, string alias, object parameters) { - return RenderMacro(alias, parameters.ToDictionary()); + return RenderMacro(contentId, alias, parameters.ToDictionary()); } /// /// Renders the macro with the specified alias, passing in the specified parameters. /// + /// /// The alias. /// The parameters. /// - public IHtmlString RenderMacro(string alias, IDictionary parameters) + public IHtmlString RenderMacro(int contentId, string alias, IDictionary parameters) { + if (contentId == default) + throw new ArgumentException("Invalid content id " + contentId); - if (_umbracoContext.PublishedRequest == null) - { - throw new InvalidOperationException("Cannot render a macro when there is no current PublishedContentRequest."); - } + var content = _umbracoContextAccessor.UmbracoContext.ContentCache?.GetById(contentId); - return RenderMacro(alias, parameters, _umbracoContext.PublishedRequest.LegacyContentHashTable); + if (content == null) + throw new InvalidOperationException("Cannot render a macro, no content found by id " + contentId); + + return RenderMacro(alias, parameters, content); } /// /// Renders the macro with the specified alias, passing in the specified parameters. /// - /// The alias. + /// The macro alias. /// The parameters. - /// The legacy umbraco page object that is required for some macros + /// The content used for macro rendering /// - internal IHtmlString RenderMacro(string alias, IDictionary parameters, PublishedContentHashtableConverter umbracoPage) + private IHtmlString RenderMacro(string alias, IDictionary parameters, IPublishedContent content) { - if (alias == null) throw new ArgumentNullException("alias"); - if (umbracoPage == null) throw new ArgumentNullException("umbracoPage"); + if (content == null) throw new ArgumentNullException(nameof(content)); - var m = Current.Services.MacroService.GetByAlias(alias); - if (m == null) - throw new KeyNotFoundException("Could not find macro with alias " + alias); - - return RenderMacro(new MacroModel(m), parameters, umbracoPage); - } - - /// - /// Renders the macro with the specified alias, passing in the specified parameters. - /// - /// The macro. - /// The parameters. - /// The legacy umbraco page object that is required for some macros - /// - internal IHtmlString RenderMacro(MacroModel m, IDictionary parameters, PublishedContentHashtableConverter umbracoPage) - { - if (umbracoPage == null) throw new ArgumentNullException(nameof(umbracoPage)); - if (m == null) throw new ArgumentNullException(nameof(m)); - - if (_umbracoContext.PageId == null) - { - throw new InvalidOperationException("Cannot render a macro when UmbracoContext.PageId is null."); - } - - var macroProps = new Hashtable(); - foreach (var i in parameters) - { - // TODO: We are doing at ToLower here because for some insane reason the UpdateMacroModel method of macro.cs - // looks for a lower case match. WTF. the whole macro concept needs to be rewritten. - - - //NOTE: the value could have HTML encoded values, so we need to deal with that - macroProps.Add(i.Key.ToLowerInvariant(), (i.Value is string) ? HttpUtility.HtmlDecode(i.Value.ToString()) : i.Value); - } - var renderer = new MacroRenderer(Current.ProfilingLogger); - var macroControl = renderer.Render(m, umbracoPage.Elements, _umbracoContext.PageId.Value, macroProps).GetAsControl(); + // TODO: We are doing at ToLower here because for some insane reason the UpdateMacroModel method looks for a lower case match. the whole macro concept needs to be rewritten. + //NOTE: the value could have HTML encoded values, so we need to deal with that + var macroProps = parameters.ToDictionary( + x => x.Key.ToLowerInvariant(), + i => (i.Value is string) ? HttpUtility.HtmlDecode(i.Value.ToString()) : i.Value); + + var macroControl = _macroRenderer.Render(alias, content, macroProps).GetAsControl(); string html; - if (macroControl is LiteralControl) + if (macroControl is LiteralControl control) { // no need to execute, we already have text - html = (macroControl as LiteralControl).Text; + html = control.Text; } else { - var containerPage = new FormlessPage(); - containerPage.Controls.Add(macroControl); - - using (var output = new StringWriter()) + using (var containerPage = new FormlessPage()) { - // .Execute() does a PushTraceContext/PopTraceContext and writes trace output straight into 'output' - // and I do not see how we could wire the trace context to the current context... so it creates dirty - // trace output right in the middle of the page. - // - // The only thing we can do is fully disable trace output while .Execute() runs and restore afterwards - // which means trace output is lost if the macro is a control (.ascx or user control) that is invoked - // from within Razor -- which makes sense anyway because the control can _not_ run correctly from - // within Razor since it will never be inserted into the page pipeline (which may even not exist at all - // if we're running MVC). - // - // I'm sure there's more things that will get lost with this context changing but I guess we'll figure - // those out as we go along. One thing we lose is the content type response output. - // http://issues.umbraco.org/issue/U4-1599 if it is setup during the macro execution. So - // here we'll save the content type response and reset it after execute is called. + containerPage.Controls.Add(macroControl); - var contentType = _umbracoContext.HttpContext.Response.ContentType; - var traceIsEnabled = containerPage.Trace.IsEnabled; - containerPage.Trace.IsEnabled = false; - _umbracoContext.HttpContext.Server.Execute(containerPage, output, true); - containerPage.Trace.IsEnabled = traceIsEnabled; - //reset the content type - _umbracoContext.HttpContext.Response.ContentType = contentType; + using (var output = new StringWriter()) + { + // .Execute() does a PushTraceContext/PopTraceContext and writes trace output straight into 'output' + // and I do not see how we could wire the trace context to the current context... so it creates dirty + // trace output right in the middle of the page. + // + // The only thing we can do is fully disable trace output while .Execute() runs and restore afterwards + // which means trace output is lost if the macro is a control (.ascx or user control) that is invoked + // from within Razor -- which makes sense anyway because the control can _not_ run correctly from + // within Razor since it will never be inserted into the page pipeline (which may even not exist at all + // if we're running MVC). + // + // I'm sure there's more things that will get lost with this context changing but I guess we'll figure + // those out as we go along. One thing we lose is the content type response output. + // http://issues.umbraco.org/issue/U4-1599 if it is setup during the macro execution. So + // here we'll save the content type response and reset it after execute is called. - //Now, we need to ensure that local links are parsed - html = TemplateUtilities.ParseInternalLinks(output.ToString(), _umbracoContext.UrlProvider); + var contentType = _umbracoContextAccessor.UmbracoContext.HttpContext.Response.ContentType; + var traceIsEnabled = containerPage.Trace.IsEnabled; + containerPage.Trace.IsEnabled = false; + _umbracoContextAccessor.UmbracoContext.HttpContext.Server.Execute(containerPage, output, true); + containerPage.Trace.IsEnabled = traceIsEnabled; + //reset the content type + _umbracoContextAccessor.UmbracoContext.HttpContext.Response.ContentType = contentType; + + //Now, we need to ensure that local links are parsed + html = TemplateUtilities.ParseInternalLinks(output.ToString(), _umbracoContextAccessor.UmbracoContext.UrlProvider); + } } + } return new HtmlString(html); diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 04a9658ee5..a1b443c3ee 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -281,29 +281,7 @@ namespace Umbraco.Web || string.IsNullOrEmpty(request["umbdebug"]) == false); } } - - /// - /// Gets the current page ID, or null if no page ID is available (e.g. a custom page). - /// - public int? PageId - { - get - { - try - { - // This was changed but the comments used to refer to - // macros in the backoffice not working with this Id - // it's probably not a problem any more though. Old comment: - // https://github.com/umbraco/Umbraco-CMS/blob/7a615133ff9de84ee667fb7794169af65e2b4d7a/src/Umbraco.Web/UmbracoContext.cs#L256 - return Current.PublishedRequest.PublishedContent.Id; - } - catch - { - return null; - } - } - } - + /// /// Determines whether the current user is in a preview mode and browsing the site (ie. not in the admin UI) /// @@ -312,7 +290,7 @@ namespace Umbraco.Web get { if (_previewing.HasValue == false) DetectPreviewMode(); - return _previewing.Value; + return _previewing ?? false; } private set => _previewing = value; } diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 9d55299ecc..73e93300ec 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -8,105 +8,76 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.Exceptions; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; using Umbraco.Core.Xml; -using Umbraco.Core.Composing; using Umbraco.Web.Routing; using Umbraco.Web.Security; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Web { - using Examine = global::Examine; - /// /// A helper class that provides many useful methods and functionality for using Umbraco in templates /// - public class UmbracoHelper : IUmbracoComponentRenderer + /// + /// This object is a request based lifetime + /// + public class UmbracoHelper { private static readonly HtmlStringUtilities StringUtilities = new HtmlStringUtilities(); private readonly UmbracoContext _umbracoContext; - private readonly IPublishedContent _currentPage; - private readonly ServiceContext _services; + private IPublishedContent _currentPage; - private IUmbracoComponentRenderer _componentRenderer; - private IPublishedContentQuery _query; - private MembershipHelper _membershipHelper; - private ITagQuery _tag; + private readonly IUmbracoComponentRenderer _componentRenderer; + private readonly ICultureDictionaryFactory _cultureDictionaryFactory; private ICultureDictionary _cultureDictionary; #region Constructors /// - /// Initializes a new instance of the class. + /// Initializes a new instance of . /// - /// For tests. - internal UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content, - ITagQuery tagQuery, - ICultureDictionary cultureDictionary, + /// An Umbraco context. + /// + /// + /// + /// + /// + /// Sets the current page to the context's published content request's content item. + public UmbracoHelper(UmbracoContext umbracoContext, ITagQuery tagQuery, + ICultureDictionaryFactory cultureDictionary, IUmbracoComponentRenderer componentRenderer, - MembershipHelper membershipHelper, - ServiceContext services) + IPublishedContentQuery publishedContentQuery, + MembershipHelper membershipHelper) { _umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); - _tag = tagQuery ?? throw new ArgumentNullException(nameof(tagQuery)); - _cultureDictionary = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary)); + TagQuery = tagQuery ?? throw new ArgumentNullException(nameof(tagQuery)); + _cultureDictionaryFactory = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary)); _componentRenderer = componentRenderer ?? throw new ArgumentNullException(nameof(componentRenderer)); - _membershipHelper = membershipHelper ?? throw new ArgumentNullException(nameof(membershipHelper)); - _currentPage = content ?? throw new ArgumentNullException(nameof(content)); - _services = services ?? throw new ArgumentNullException(nameof(services)); + MembershipHelper = membershipHelper ?? throw new ArgumentNullException(nameof(membershipHelper)); + ContentQuery = publishedContentQuery ?? throw new ArgumentNullException(nameof(publishedContentQuery)); + + if (_umbracoContext.IsFrontEndUmbracoRequest) + _currentPage = _umbracoContext.PublishedRequest.PublishedContent; } /// - /// Initializes a new instance of the class. + /// Initializes a new empty instance of . /// /// For tests - nothing is initialized. internal UmbracoHelper() { } - - /// - /// Initializes a new instance of the class with an Umbraco context - /// and a specific content item. - /// - /// An Umbraco context. - /// A content item. - /// A services context. - /// Sets the current page to the supplied content item. - public UmbracoHelper(UmbracoContext umbracoContext, ServiceContext services, IPublishedContent content) - : this(umbracoContext, services) - { - _currentPage = content ?? throw new ArgumentNullException(nameof(content)); - } - - /// - /// Initializes a new instance of the class with an Umbraco context. - /// - /// An Umbraco context. - /// A services context. - /// Sets the current page to the context's published content request's content item. - public UmbracoHelper(UmbracoContext umbracoContext, ServiceContext services) - { - _services = services ?? throw new ArgumentNullException(nameof(services)); - _umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); - if (_umbracoContext.IsFrontEndUmbracoRequest) - _currentPage = _umbracoContext.PublishedRequest.PublishedContent; - } - #endregion /// /// Gets the tag context. /// - public ITagQuery TagQuery => _tag ?? - (_tag = new TagQuery(_services.TagService, ContentQuery)); + public ITagQuery TagQuery { get; } /// /// Gets the query context. /// - public IPublishedContentQuery ContentQuery => _query ?? - (_query = new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache, UmbracoContext.VariationContextAccessor)); + public IPublishedContentQuery ContentQuery { get; } /// /// Gets the Umbraco context. @@ -124,8 +95,7 @@ namespace Umbraco.Web /// /// Gets the membership helper. /// - public MembershipHelper MembershipHelper => _membershipHelper - ?? (_membershipHelper = Current.Factory.GetInstance()); + public MembershipHelper MembershipHelper { get; } /// /// Gets the url provider. @@ -133,14 +103,7 @@ namespace Umbraco.Web public UrlProvider UrlProvider => UmbracoContext.UrlProvider; /// - /// Gets the component renderer. - /// - public IUmbracoComponentRenderer UmbracoComponentRenderer => _componentRenderer - ?? (_componentRenderer = new UmbracoComponentRenderer(UmbracoContext)); - - /// - /// Returns the current item - /// assigned to the UmbracoHelper. + /// Gets (or sets) the current item assigned to the UmbracoHelper. /// /// /// @@ -173,17 +136,18 @@ namespace Umbraco.Web ); } + set => _currentPage = value; } /// /// Renders the template for the specified pageId and an optional altTemplateId /// - /// + /// /// If not specified, will use the template assigned to the node /// - public IHtmlString RenderTemplate(int pageId, int? altTemplateId = null) + public IHtmlString RenderTemplate(int contentId, int? altTemplateId = null) { - return UmbracoComponentRenderer.RenderTemplate(pageId, altTemplateId); + return _componentRenderer.RenderTemplate(contentId, altTemplateId); } #region RenderMacro @@ -195,7 +159,7 @@ namespace Umbraco.Web /// public IHtmlString RenderMacro(string alias) { - return UmbracoComponentRenderer.RenderMacro(alias, new { }); + return _componentRenderer.RenderMacro(_umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0, alias, new { }); } /// @@ -206,7 +170,7 @@ namespace Umbraco.Web /// public IHtmlString RenderMacro(string alias, object parameters) { - return UmbracoComponentRenderer.RenderMacro(alias, parameters.ToDictionary()); + return _componentRenderer.RenderMacro(_umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0, alias, parameters.ToDictionary()); } /// @@ -217,7 +181,7 @@ namespace Umbraco.Web /// public IHtmlString RenderMacro(string alias, IDictionary parameters) { - return UmbracoComponentRenderer.RenderMacro(alias, parameters); + return _componentRenderer.RenderMacro(_umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0, alias, parameters); } #endregion @@ -254,7 +218,7 @@ namespace Umbraco.Web /// Returns the ICultureDictionary for access to dictionary items /// public ICultureDictionary CultureDictionary => _cultureDictionary - ?? (_cultureDictionary = Current.CultureDictionaryFactory.CreateDictionary()); + ?? (_cultureDictionary = _cultureDictionaryFactory.CreateDictionary()); #endregion @@ -287,6 +251,7 @@ namespace Umbraco.Web /// Gets the url of a content identified by its identifier. /// /// The content identifier. + /// /// The url for the content. public string Url(int contentId, string culture = null) { @@ -454,11 +419,9 @@ namespace Umbraco.Web private IEnumerable ContentForObjects(IEnumerable ids) { var idsA = ids.ToArray(); - IEnumerable intIds; - if (ConvertIdsObjectToInts(idsA, out intIds)) + if (ConvertIdsObjectToInts(idsA, out var intIds)) return ContentQuery.Content(intIds); - IEnumerable guidIds; - if (ConvertIdsObjectToGuids(idsA, out guidIds)) + if (ConvertIdsObjectToGuids(idsA, out var guidIds)) return ContentQuery.Content(guidIds); return Enumerable.Empty(); } @@ -638,12 +601,7 @@ namespace Umbraco.Web public IPublishedContent Media(Guid id) { - // TODO: This is horrible but until the media cache properly supports GUIDs we have no choice here and - // currently there won't be any way to add this method correctly to `ITypedPublishedContentQuery` without breaking an interface and adding GUID support for media - - var entityService = Current.Services.EntityService; // TODO: inject - var mediaAttempt = entityService.GetId(id, UmbracoObjectTypes.Media); - return mediaAttempt.Success ? ContentQuery.Media(mediaAttempt.Result) : null; + return ContentQuery.Media(id); } /// @@ -696,12 +654,10 @@ namespace Umbraco.Web private IEnumerable MediaForObjects(IEnumerable ids) { var idsA = ids.ToArray(); - IEnumerable intIds; - if (ConvertIdsObjectToInts(idsA, out intIds)) + if (ConvertIdsObjectToInts(idsA, out var intIds)) return ContentQuery.Media(intIds); - //IEnumerable guidIds; - //if (ConvertIdsObjectToGuids(idsA, out guidIds)) - // return ContentQuery.Media(guidIds); + if (ConvertIdsObjectToGuids(idsA, out var guidIds)) + return ContentQuery.Media(guidIds); return Enumerable.Empty(); } diff --git a/src/Umbraco.Web/UmbracoHttpHandler.cs b/src/Umbraco.Web/UmbracoHttpHandler.cs index 336b53e9e0..eca3fc303e 100644 --- a/src/Umbraco.Web/UmbracoHttpHandler.cs +++ b/src/Umbraco.Web/UmbracoHttpHandler.cs @@ -14,19 +14,16 @@ namespace Umbraco.Web private UrlHelper _url; protected UmbracoHttpHandler() - : this(Current.UmbracoContext, Current.Services) + : this(Current.UmbracoContext, Current.UmbracoHelper, Current.Services, Current.ProfilingLogger) { } - protected UmbracoHttpHandler(UmbracoContext umbracoContext, ServiceContext services) + protected UmbracoHttpHandler(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper, ServiceContext service, IProfilingLogger plogger) { - if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext)); UmbracoContext = umbracoContext; - Umbraco = new UmbracoHelper(umbracoContext, services); - - // TODO: inject somehow - Logger = Current.Logger; - ProfilingLogger = Current.ProfilingLogger; - Services = Current.Services; + Logger = plogger; + ProfilingLogger = plogger; + Services = service; + Umbraco = umbracoHelper; } public abstract void ProcessRequest(HttpContext context); diff --git a/src/Umbraco.Web/UmbracoWebService.cs b/src/Umbraco.Web/UmbracoWebService.cs index b970a0e8c2..781e521fcd 100644 --- a/src/Umbraco.Web/UmbracoWebService.cs +++ b/src/Umbraco.Web/UmbracoWebService.cs @@ -21,15 +21,19 @@ namespace Umbraco.Web { private UrlHelper _url; - protected UmbracoWebService() + protected UmbracoWebService(IProfilingLogger profilingLogger, UmbracoContext umbracoContext, UmbracoHelper umbraco, ServiceContext services, IGlobalSettings globalSettings) { - UmbracoContext = Current.UmbracoContext; - Umbraco = new UmbracoHelper(UmbracoContext, Current.Services); + Logger = profilingLogger; + ProfilingLogger = profilingLogger; + UmbracoContext = umbracoContext; + Umbraco = umbraco; + Services = services; + GlobalSettings = globalSettings; + } - Logger = Current.Logger; - ProfilingLogger = Current.ProfilingLogger; - Services = Current.Services; - GlobalSettings = Current.Configs.Global(); + protected UmbracoWebService() + : this(Current.ProfilingLogger, Current.UmbracoContext, Current.UmbracoHelper, Current.Services, Current.Configs.Global()) + { } /// diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index 31778d4b0c..2091d47202 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -13,18 +13,12 @@ namespace Umbraco.Web.WebApi /// public abstract class UmbracoApiController : UmbracoApiControllerBase, IDiscoverable { - /// - /// Initializes a new instance of the with auto dependencies. - /// - /// Dependencies are obtained from the service locator. protected UmbracoApiController() - { } + { + } - /// - /// Initialize a new instance of the with all its dependencies. - /// - protected UmbracoApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) - { } + protected UmbracoApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } } } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs index 7e32296e12..c6ac35267d 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs @@ -21,8 +21,6 @@ namespace Umbraco.Web.WebApi [FeatureAuthorize] public abstract class UmbracoApiControllerBase : ApiController { - private UmbracoHelper _umbracoHelper; - // note: all Umbraco controllers have two constructors: one with all dependencies, which should be used, // and one with auto dependencies, ie no dependencies - and then dependencies are automatically obtained // here from the Current service locator - this is obviously evil, but it allows us to add new dependencies @@ -40,14 +38,15 @@ namespace Umbraco.Web.WebApi Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance() + Current.Factory.GetInstance(), + Current.Factory.GetInstance() ) { } /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoApiControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) + protected UmbracoApiControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) { GlobalSettings = globalSettings; SqlContext = sqlContext; @@ -56,6 +55,7 @@ namespace Umbraco.Web.WebApi Logger = logger; RuntimeState = runtimeState; UmbracoContext = umbracoContext; + Umbraco = umbracoHelper; } /// @@ -112,9 +112,8 @@ namespace Umbraco.Web.WebApi /// /// Gets the Umbraco helper. /// - public UmbracoHelper Umbraco => _umbracoHelper - ?? (_umbracoHelper = new UmbracoHelper(UmbracoContext, Services)); - + public UmbracoHelper Umbraco { get; } + /// /// Gets the web security helper. /// diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 039e462e0b..e188fb4fef 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -30,19 +30,13 @@ namespace Umbraco.Web.WebApi { private BackOfficeUserManager _userManager; - /// - /// Initializes a new instance of the with auto dependencies. - /// - /// Dependencies are obtained from the service locator. protected UmbracoAuthorizedApiController() - { } + { + } - /// - /// Initializes a new instance of the class with all its dependencies. - /// - protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) - { } + protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } /// /// Gets the user manager. From 2f1c39ab96936db1281f9d99ae0ba2f72ac29d57 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 31 Jan 2019 15:44:39 +1100 Subject: [PATCH 035/555] Removes the old/strange "pageElements" thing, it's no longer needed --- src/Umbraco.Web/Editors/MacroRenderingController.cs | 6 ------ src/Umbraco.Web/Macros/MacroRenderer.cs | 4 ---- src/Umbraco.Web/Routing/PublishedRouter.cs | 7 +------ src/Umbraco.Web/Templates/TemplateRenderer.cs | 13 ++++--------- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Web/Editors/MacroRenderingController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs index f88a84dd72..0fd88e2b1e 100644 --- a/src/Umbraco.Web/Editors/MacroRenderingController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -139,12 +139,6 @@ namespace Umbraco.Web.Editors _variationContextAccessor.VariationContext = new VariationContext(Thread.CurrentThread.CurrentCulture.Name); } - - //fixme: don't think we need this anymore - var legacyPage = new PublishedContentHashtableConverter(doc, _variationContextAccessor); - UmbracoContext.HttpContext.Items["pageElements"] = legacyPage.Elements; - UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; - var result = Request.CreateResponse(); //need to create a specific content result formatted as HTML since this controller has been configured //with only json formatters. diff --git a/src/Umbraco.Web/Macros/MacroRenderer.cs b/src/Umbraco.Web/Macros/MacroRenderer.cs index b0ea90f9c1..9736aa283b 100755 --- a/src/Umbraco.Web/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web/Macros/MacroRenderer.cs @@ -195,10 +195,6 @@ namespace Umbraco.Web.Macros #region Render/Execute - // still, this is ugly. The macro should have a Content property - // referring to IPublishedContent we're rendering the macro against, - // this is all so convoluted ;-( - public MacroContent Render(string macroAlias, IPublishedContent content, IDictionary macroParams) { var m = _macroService.GetByAlias(macroAlias); diff --git a/src/Umbraco.Web/Routing/PublishedRouter.cs b/src/Umbraco.Web/Routing/PublishedRouter.cs index 14c36198d8..27baf86522 100644 --- a/src/Umbraco.Web/Routing/PublishedRouter.cs +++ b/src/Umbraco.Web/Routing/PublishedRouter.cs @@ -207,9 +207,6 @@ namespace Umbraco.Web.Routing // handlers like default.aspx will want it and most macros currently need it frequest.LegacyContentHashTable = new PublishedContentHashtableConverter(frequest); - // used by many legacy objects - frequest.UmbracoContext.HttpContext.Items["pageElements"] = frequest.LegacyContentHashTable.Elements; - return true; } @@ -252,9 +249,7 @@ namespace Umbraco.Web.Routing // assign the legacy page back to the docrequest // handlers like default.aspx will want it and most macros currently need it request.LegacyContentHashTable = new PublishedContentHashtableConverter(request); - - // this is used by many legacy objects - request.UmbracoContext.HttpContext.Items["pageElements"] = request.LegacyContentHashTable.Elements; + } #endregion diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index facafdea63..dc8ca0b16d 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -97,7 +97,7 @@ namespace Umbraco.Web.Templates //First, save all of the items locally that we know are used in the chain of execution, we'll need to restore these //after this page has rendered. - SaveExistingItems(out var oldPageElements, out var oldPublishedRequest, out var oldAltTemplate); + SaveExistingItems(out var oldPublishedRequest, out var oldAltTemplate); try { @@ -110,7 +110,7 @@ namespace Umbraco.Web.Templates finally { //restore items on context objects to continuing rendering the parent template - RestoreItems(oldPageElements, oldPublishedRequest, oldAltTemplate); + RestoreItems(oldPublishedRequest, oldAltTemplate); } } @@ -172,10 +172,7 @@ namespace Umbraco.Web.Templates private void SetNewItemsOnContextObjects(PublishedRequest request) { - // handlers like default.aspx will want it and most macros currently need it - request.LegacyContentHashTable = new PublishedContentHashtableConverter(request); //now, set the new ones for this page execution - _umbracoContextAccessor.UmbracoContext.HttpContext.Items["pageElements"] = request.LegacyContentHashTable.Elements; _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null; _umbracoContextAccessor.UmbracoContext.PublishedRequest = request; } @@ -183,11 +180,10 @@ namespace Umbraco.Web.Templates /// /// Save all items that we know are used for rendering execution to variables so we can restore after rendering /// - private void SaveExistingItems(out object oldPageElements, out PublishedRequest oldPublishedRequest, out object oldAltTemplate) + private void SaveExistingItems(out PublishedRequest oldPublishedRequest, out object oldAltTemplate) { //Many objects require that these legacy items are in the http context items... before we render this template we need to first //save the values in them so that we can re-set them after we render so the rest of the execution works as per normal - oldPageElements = _umbracoContextAccessor.UmbracoContext.HttpContext.Items["pageElements"]; oldPublishedRequest = _umbracoContextAccessor.UmbracoContext.PublishedRequest; oldAltTemplate = _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate]; } @@ -195,10 +191,9 @@ namespace Umbraco.Web.Templates /// /// Restores all items back to their context's to continue normal page rendering execution /// - private void RestoreItems(object oldPageElements, PublishedRequest oldPublishedRequest, object oldAltTemplate) + private void RestoreItems(PublishedRequest oldPublishedRequest, object oldAltTemplate) { _umbracoContextAccessor.UmbracoContext.PublishedRequest = oldPublishedRequest; - _umbracoContextAccessor.UmbracoContext.HttpContext.Items["pageElements"] = oldPageElements; _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = oldAltTemplate; } } From f9e673ca4c7c26b51c7adcd0b3341d31c8fbc332 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 31 Jan 2019 16:54:17 +1100 Subject: [PATCH 036/555] Updates tinymce, adds back the styles for the rendered macro in the rte, properly uses tinymce's noneditable plugin and removes a ton of code relating to the old work arounds we had, now just need to get the macro re-rendering --- src/Umbraco.Web.UI.Client/package-lock.json | 381 ++++++++++++++---- src/Umbraco.Web.UI.Client/package.json | 2 +- .../src/common/services/tinymce.service.js | 184 +-------- src/Umbraco.Web.UI.Client/src/less/rte.less | 9 + 4 files changed, 317 insertions(+), 259 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index fe657ae470..207eba38c5 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1104,6 +1104,7 @@ "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.2.0.tgz", "integrity": "sha1-nNnABpV+vpX62tW9YJiUKoE3N/Y=", "dev": true, + "optional": true, "requires": { "file-type": "^3.1.0" }, @@ -1112,7 +1113,8 @@ "version": "3.9.0", "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true + "dev": true, + "optional": true } } }, @@ -1523,6 +1525,7 @@ "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, + "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -1532,13 +1535,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1554,6 +1559,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -1742,7 +1748,8 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true + "dev": true, + "optional": true }, "buffer-fill": { "version": "1.0.0", @@ -1761,6 +1768,7 @@ "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz", "integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=", "dev": true, + "optional": true, "requires": { "file-type": "^3.1.0", "readable-stream": "^2.0.2", @@ -1772,19 +1780,22 @@ "version": "3.9.0", "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true + "dev": true, + "optional": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1800,6 +1811,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -1808,13 +1820,15 @@ "version": "2.0.3", "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", - "dev": true + "dev": true, + "optional": true }, "vinyl": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, + "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -1935,7 +1949,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true + "dev": true, + "optional": true }, "caseless": { "version": "0.12.0", @@ -1948,6 +1963,7 @@ "resolved": "https://registry.npmjs.org/caw/-/caw-1.2.0.tgz", "integrity": "sha1-/7Im/n78VHKI3GLuPpcHPCEtEDQ=", "dev": true, + "optional": true, "requires": { "get-proxy": "^1.0.1", "is-obj": "^1.0.0", @@ -1959,7 +1975,8 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true + "dev": true, + "optional": true } } }, @@ -2220,7 +2237,8 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=", - "dev": true + "dev": true, + "optional": true }, "coa": { "version": "2.0.1", @@ -2316,6 +2334,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, + "optional": true, "requires": { "graceful-readlink": ">= 1.0.0" } @@ -2528,6 +2547,7 @@ "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, + "optional": true, "requires": { "capture-stack-trace": "^1.0.0" } @@ -2782,6 +2802,7 @@ "resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz", "integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=", "dev": true, + "optional": true, "requires": { "buffer-to-vinyl": "^1.0.0", "concat-stream": "^1.4.6", @@ -2799,6 +2820,7 @@ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, + "optional": true, "requires": { "arr-flatten": "^1.0.1" } @@ -2807,13 +2829,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true + "dev": true, + "optional": true }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, + "optional": true, "requires": { "expand-range": "^1.8.1", "preserve": "^0.2.0", @@ -2825,6 +2849,7 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, + "optional": true, "requires": { "is-posix-bracket": "^0.1.0" } @@ -2834,6 +2859,7 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -2843,6 +2869,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, + "optional": true, "requires": { "inflight": "^1.0.4", "inherits": "2", @@ -2856,6 +2883,7 @@ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", "dev": true, + "optional": true, "requires": { "extend": "^3.0.0", "glob": "^5.0.3", @@ -2871,13 +2899,15 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -2889,13 +2919,15 @@ "version": "0.10.31", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "dev": true, + "optional": true }, "through2": { "version": "0.6.5", "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, + "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -2907,19 +2939,22 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true + "dev": true, + "optional": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true + "dev": true, + "optional": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -2928,13 +2963,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -2944,6 +2981,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, + "optional": true, "requires": { "arr-diff": "^2.0.0", "array-unique": "^0.2.1", @@ -2964,13 +3002,15 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "dev": true, + "optional": true }, "ordered-read-streams": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", "dev": true, + "optional": true, "requires": { "is-stream": "^1.0.1", "readable-stream": "^2.0.1" @@ -2981,6 +3021,7 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2996,6 +3037,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3005,6 +3047,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, + "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -3014,6 +3057,7 @@ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", "dev": true, + "optional": true, "requires": { "first-chunk-stream": "^1.0.0", "strip-bom": "^2.0.0" @@ -3024,6 +3068,7 @@ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", "dev": true, + "optional": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", "through2-filter": "^3.0.0" @@ -3034,6 +3079,7 @@ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, + "optional": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" @@ -3046,6 +3092,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, + "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -3057,6 +3104,7 @@ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", "dev": true, + "optional": true, "requires": { "duplexify": "^3.2.0", "glob-stream": "^5.3.2", @@ -3084,6 +3132,7 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz", "integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=", "dev": true, + "optional": true, "requires": { "is-tar": "^1.0.0", "object-assign": "^2.0.0", @@ -3097,19 +3146,22 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3122,6 +3174,7 @@ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, + "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3132,6 +3185,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, + "optional": true, "requires": { "clone": "^0.2.0", "clone-stats": "^0.0.1" @@ -3144,6 +3198,7 @@ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz", "integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=", "dev": true, + "optional": true, "requires": { "is-bzip2": "^1.0.0", "object-assign": "^2.0.0", @@ -3158,19 +3213,22 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3183,6 +3241,7 @@ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, + "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3193,6 +3252,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, + "optional": true, "requires": { "clone": "^0.2.0", "clone-stats": "^0.0.1" @@ -3205,6 +3265,7 @@ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz", "integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=", "dev": true, + "optional": true, "requires": { "is-gzip": "^1.0.0", "object-assign": "^2.0.0", @@ -3218,19 +3279,22 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3243,6 +3307,7 @@ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, + "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3253,6 +3318,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, + "optional": true, "requires": { "clone": "^0.2.0", "clone-stats": "^0.0.1" @@ -3265,6 +3331,7 @@ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz", "integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=", "dev": true, + "optional": true, "requires": { "is-zip": "^1.0.0", "read-all-stream": "^3.0.0", @@ -3280,6 +3347,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, + "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -3292,7 +3360,8 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true + "dev": true, + "optional": true }, "deep-is": { "version": "0.1.3", @@ -3491,6 +3560,7 @@ "resolved": "https://registry.npmjs.org/download/-/download-4.4.3.tgz", "integrity": "sha1-qlX9rTktldS2jowr4D4MKqIbqaw=", "dev": true, + "optional": true, "requires": { "caw": "^1.0.1", "concat-stream": "^1.4.7", @@ -3514,6 +3584,7 @@ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, + "optional": true, "requires": { "arr-flatten": "^1.0.1" } @@ -3522,13 +3593,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true + "dev": true, + "optional": true }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, + "optional": true, "requires": { "expand-range": "^1.8.1", "preserve": "^0.2.0", @@ -3540,6 +3613,7 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, + "optional": true, "requires": { "is-posix-bracket": "^0.1.0" } @@ -3549,6 +3623,7 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -3558,6 +3633,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, + "optional": true, "requires": { "inflight": "^1.0.4", "inherits": "2", @@ -3571,6 +3647,7 @@ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", "dev": true, + "optional": true, "requires": { "extend": "^3.0.0", "glob": "^5.0.3", @@ -3586,13 +3663,15 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3604,13 +3683,15 @@ "version": "0.10.31", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "dev": true, + "optional": true }, "through2": { "version": "0.6.5", "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, + "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3622,19 +3703,22 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true + "dev": true, + "optional": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true + "dev": true, + "optional": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -3643,13 +3727,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -3659,6 +3745,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, + "optional": true, "requires": { "arr-diff": "^2.0.0", "array-unique": "^0.2.1", @@ -3679,13 +3766,15 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "dev": true, + "optional": true }, "ordered-read-streams": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", "dev": true, + "optional": true, "requires": { "is-stream": "^1.0.1", "readable-stream": "^2.0.1" @@ -3696,6 +3785,7 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3711,6 +3801,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3720,6 +3811,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, + "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -3729,6 +3821,7 @@ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", "dev": true, + "optional": true, "requires": { "first-chunk-stream": "^1.0.0", "strip-bom": "^2.0.0" @@ -3739,6 +3832,7 @@ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", "dev": true, + "optional": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", "through2-filter": "^3.0.0" @@ -3749,6 +3843,7 @@ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, + "optional": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" @@ -3761,6 +3856,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, + "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -3772,6 +3868,7 @@ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", "dev": true, + "optional": true, "requires": { "duplexify": "^3.2.0", "glob-stream": "^5.3.2", @@ -3814,6 +3911,7 @@ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", "dev": true, + "optional": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -3826,6 +3924,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, + "optional": true, "requires": { "once": "^1.4.0" } @@ -3834,13 +3933,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3850,6 +3951,7 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3865,6 +3967,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3876,6 +3979,7 @@ "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz", "integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=", "dev": true, + "optional": true, "requires": { "onetime": "^1.0.0", "set-immediate-shim": "^1.0.0" @@ -3885,7 +3989,8 @@ "version": "1.1.0", "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true + "dev": true, + "optional": true } } }, @@ -4825,6 +4930,7 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, + "optional": true, "requires": { "pend": "~1.2.0" } @@ -4872,13 +4978,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz", "integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=", - "dev": true + "dev": true, + "optional": true }, "filenamify": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz", "integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=", "dev": true, + "optional": true, "requires": { "filename-reserved-regex": "^1.0.0", "strip-outer": "^1.0.0", @@ -5125,7 +5233,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", - "dev": true + "dev": true, + "optional": true }, "fs-extra": { "version": "1.0.0", @@ -5189,7 +5298,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5210,12 +5320,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5230,17 +5342,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5357,7 +5472,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5369,6 +5485,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5383,6 +5500,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5390,12 +5508,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5414,6 +5534,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5494,7 +5615,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5506,6 +5628,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5591,7 +5714,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5627,6 +5751,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5646,6 +5771,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5689,12 +5815,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -5730,6 +5858,7 @@ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz", "integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=", "dev": true, + "optional": true, "requires": { "rc": "^1.1.2" } @@ -6036,6 +6165,7 @@ "resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz", "integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=", "dev": true, + "optional": true, "requires": { "create-error-class": "^3.0.1", "duplexer2": "^0.1.4", @@ -6059,6 +6189,7 @@ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, + "optional": true, "requires": { "readable-stream": "^2.0.2" } @@ -6067,19 +6198,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "dev": true, + "optional": true }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, + "optional": true, "requires": { "error-ex": "^1.2.0" } @@ -6089,6 +6223,7 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6104,6 +6239,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -6123,7 +6259,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true + "dev": true, + "optional": true }, "growly": { "version": "1.3.0", @@ -6419,6 +6556,7 @@ "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.2.0.tgz", "integrity": "sha1-jutlpeAV+O2FMsr+KEVJYGJvDcc=", "dev": true, + "optional": true, "requires": { "archive-type": "^3.0.0", "decompress": "^3.0.0", @@ -6430,13 +6568,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6452,6 +6592,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -7069,6 +7210,7 @@ "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", "dev": true, + "optional": true, "requires": { "convert-source-map": "^1.1.1", "graceful-fs": "^4.1.2", @@ -7081,13 +7223,15 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true + "dev": true, + "optional": true }, "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, + "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -7097,6 +7241,7 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, + "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -7927,7 +8072,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz", "integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=", - "dev": true + "dev": true, + "optional": true }, "is-callable": { "version": "1.1.4", @@ -8062,7 +8208,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=", - "dev": true + "dev": true, + "optional": true }, "is-jpg": { "version": "1.0.1", @@ -8075,7 +8222,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz", "integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=", - "dev": true + "dev": true, + "optional": true }, "is-number": { "version": "3.0.0", @@ -8141,7 +8289,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true + "dev": true, + "optional": true }, "is-regex": { "version": "1.0.4", @@ -8171,7 +8320,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true + "dev": true, + "optional": true }, "is-stream": { "version": "1.1.0", @@ -8201,7 +8351,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz", "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=", - "dev": true + "dev": true, + "optional": true }, "is-typedarray": { "version": "1.0.0", @@ -8222,7 +8373,8 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true + "dev": true, + "optional": true }, "is-utf8": { "version": "0.2.1", @@ -8234,7 +8386,8 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=", - "dev": true + "dev": true, + "optional": true }, "is-windows": { "version": "1.0.2", @@ -8252,7 +8405,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=", - "dev": true + "dev": true, + "optional": true }, "isarray": { "version": "0.0.1", @@ -8573,6 +8727,7 @@ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "dev": true, + "optional": true, "requires": { "readable-stream": "^2.0.5" }, @@ -8581,13 +8736,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8603,6 +8760,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -8908,7 +9066,8 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true + "dev": true, + "optional": true }, "lodash.isobject": { "version": "2.4.1", @@ -9105,7 +9264,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", - "dev": true + "dev": true, + "optional": true }, "lpad-align": { "version": "1.1.2", @@ -9501,7 +9661,8 @@ "version": "1.0.0", "resolved": "http://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=", - "dev": true + "dev": true, + "optional": true }, "node.extend": { "version": "1.1.8", @@ -12551,7 +12712,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "dev": true, + "optional": true }, "p-pipe": { "version": "1.2.0", @@ -13262,7 +13424,8 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true + "dev": true, + "optional": true }, "preserve": { "version": "0.2.0", @@ -13394,6 +13557,7 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, + "optional": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -13406,6 +13570,7 @@ "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", "dev": true, + "optional": true, "requires": { "pinkie-promise": "^2.0.0", "readable-stream": "^2.0.0" @@ -13415,13 +13580,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13437,6 +13604,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -14053,6 +14221,7 @@ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", "dev": true, + "optional": true, "requires": { "commander": "~2.8.1" } @@ -14198,7 +14367,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true + "dev": true, + "optional": true }, "set-value": { "version": "2.0.0", @@ -14703,7 +14873,8 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=", - "dev": true + "dev": true, + "optional": true }, "static-extend": { "version": "0.1.2", @@ -14747,6 +14918,7 @@ "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, + "optional": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" @@ -14757,6 +14929,7 @@ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, + "optional": true, "requires": { "readable-stream": "^2.0.2" } @@ -14765,13 +14938,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14787,6 +14962,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -14803,7 +14979,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", - "dev": true + "dev": true, + "optional": true }, "streamroller": { "version": "0.7.0", @@ -14981,6 +15158,7 @@ "resolved": "http://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz", "integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=", "dev": true, + "optional": true, "requires": { "chalk": "^1.0.0", "get-stdin": "^4.0.1", @@ -14994,13 +15172,15 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "dev": true, + "optional": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, + "optional": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -15014,6 +15194,7 @@ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=", "dev": true, + "optional": true, "requires": { "is-relative": "^0.1.0" } @@ -15022,13 +15203,15 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=", - "dev": true + "dev": true, + "optional": true }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "dev": true, + "optional": true } } }, @@ -15059,6 +15242,7 @@ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, + "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15092,6 +15276,7 @@ "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz", "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=", "dev": true, + "optional": true, "requires": { "chalk": "^1.0.0" }, @@ -15100,13 +15285,15 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "dev": true, + "optional": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, + "optional": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -15119,7 +15306,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "dev": true, + "optional": true } } }, @@ -15181,6 +15369,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, + "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -15196,6 +15385,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "dev": true, + "optional": true, "requires": { "once": "^1.4.0" } @@ -15204,13 +15394,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -15220,6 +15412,7 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15235,6 +15428,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15333,6 +15527,7 @@ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", "dev": true, + "optional": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" @@ -15357,7 +15552,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz", "integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=", - "dev": true + "dev": true, + "optional": true }, "timsort": { "version": "0.3.0", @@ -15402,9 +15598,9 @@ } }, "tinymce": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.0.tgz", - "integrity": "sha512-hrPeCLXY/sVCo3i64CTW8P5xbDiEI8Uii/vWpcmQWAMhex6GWWd2U+L8WIMj5tKKGdfcIQAJfpfQthc/92bcKw==" + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.2.tgz", + "integrity": "sha512-ZRoTGG4GAsOI73QPSNkabO7nkoYw9H6cglRB44W2mMkxSiqxYi8WJlgkUphk0fDqo6ZD6r3E+NSP4UHxF2lySg==" }, "tmp": { "version": "0.0.33", @@ -15420,6 +15616,7 @@ "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=", "dev": true, + "optional": true, "requires": { "extend-shallow": "^2.0.1" }, @@ -15429,6 +15626,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -15445,7 +15643,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", - "dev": true + "dev": true, + "optional": true }, "to-fast-properties": { "version": "2.0.0", @@ -15524,6 +15723,7 @@ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", "dev": true, + "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15772,7 +15972,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", - "dev": true + "dev": true, + "optional": true }, "upath": { "version": "1.1.0", @@ -15800,6 +16001,7 @@ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, + "optional": true, "requires": { "prepend-http": "^1.0.1" } @@ -15885,7 +16087,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", - "dev": true + "dev": true, + "optional": true }, "validate-npm-package-license": { "version": "3.0.4", @@ -15930,6 +16133,7 @@ "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz", "integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=", "dev": true, + "optional": true, "requires": { "object-assign": "^4.0.1", "readable-stream": "^2.0.0" @@ -15939,19 +16143,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "dev": true, + "optional": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15967,6 +16174,7 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -16106,6 +16314,7 @@ "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz", "integrity": "sha1-0bFPOdLiy0q4xAmPdW/ksWTkc9Q=", "dev": true, + "optional": true, "requires": { "wrap-fn": "^0.1.0" } @@ -16196,6 +16405,7 @@ "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz", "integrity": "sha1-8htuQQFv9KfjFyDbxjoJAWvfmEU=", "dev": true, + "optional": true, "requires": { "co": "3.1.0" } @@ -16293,6 +16503,7 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, + "optional": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 3f4314db0e..f24275420a 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -39,7 +39,7 @@ "npm": "^6.4.1", "signalr": "2.4.0", "spectrum-colorpicker": "1.8.0", - "tinymce": "4.9.0", + "tinymce": "4.9.2", "typeahead.js": "0.11.1", "underscore": "1.9.1" }, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 0ba795626a..b2ec94fffe 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -502,96 +502,22 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s onPostRender: function () { var ctrl = this; - var isOnMacroElement = false; /** - if the selection comes from a different element that is not the macro's - we need to check if the selection includes part of the macro, if so we'll force the selection - to clear to the next element since if people can select part of the macro markup they can then modify it. - */ - function handleSelectionChange() { - - if (!editor.selection.isCollapsed()) { - var endSelection = tinymce.activeEditor.selection.getEnd(); - var startSelection = tinymce.activeEditor.selection.getStart(); - //don't proceed if it's an entire element selected - if (endSelection !== startSelection) { - - //if the end selection is a macro then move the cursor - //NOTE: we don't have to handle when the selection comes from a previous parent because - // that is automatically taken care of with the normal onNodeChanged logic since the - // evt.element will be the macro once it becomes part of the selection. - var $testForMacro = $(endSelection).closest(".umb-macro-holder"); - if ($testForMacro.length > 0) { - - //it came from before so move after, if there is no after then select ourselves - var next = $testForMacro.next(); - if (next.length > 0) { - editor.selection.setCursorLocation($testForMacro.next().get(0)); - } else { - selectMacroElement($testForMacro.get(0)); - } - - } - } - } - } - - /** helper method to select the macro element */ - function selectMacroElement(macroElement) { - - // move selection to top element to ensure we can't edit this - editor.selection.select(macroElement); - - // check if the current selection *is* the element (ie bug) - var currentSelection = editor.selection.getStart(); - if (tinymce.isIE) { - if (!editor.dom.hasClass(currentSelection, 'umb-macro-holder')) { - while (!editor.dom.hasClass(currentSelection, 'umb-macro-holder') && currentSelection.parentNode) { - currentSelection = currentSelection.parentNode; - } - editor.selection.select(currentSelection); - } - } - } - - /** - * Add a node change handler, test if we're editing a macro and select the whole thing, then set our isOnMacroElement flag. - * If we change the selection inside this method, then we end up in an infinite loop, so we have to remove ourselves - * from the event listener before changing selection, however, it seems that putting a break point in this method - * will always cause an 'infinite' loop as the caret keeps changing. - * - * TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/ + * Check if the macro is currently selected and toggle the menu button */ function onNodeChanged(evt) { //set our macro button active when on a node of class umb-macro-holder var $macroElement = $(evt.element).closest(".umb-macro-holder"); - handleSelectionChange(); - - //set the button active + //set the button active/inactive ctrl.active($macroElement.length !== 0); - - if ($macroElement.length > 0) { - var macroElement = $macroElement.get(0); - - //remove the event listener before re-selecting - editor.off('NodeChange', onNodeChanged); - - selectMacroElement(macroElement); - - //set the flag - isOnMacroElement = true; - - //re-add the event listener - editor.on('NodeChange', onNodeChanged); - } else { - isOnMacroElement = false; - } - } + //NOTE: This could be another way to deal with the active/inactive state + //editor.on('ObjectSelected', function (e) {}); + /** when the contents load we need to find any macros declared and load in their content */ editor.on("LoadContent", function (o) { @@ -602,102 +528,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s }); - /** - * This prevents any other commands from executing when the current element is the macro so the content cannot be edited - * - * TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/ - */ - editor.on('BeforeExecCommand', function (o) { - if (isOnMacroElement) { - if (o.preventDefault) { - o.preventDefault(); - } - if (o.stopImmediatePropagation) { - o.stopImmediatePropagation(); - } - return; - } - }); - - /** - * This double checks and ensures you can't paste content into the rendered macro - * - * TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/ - */ - editor.on("Paste", function (o) { - if (isOnMacroElement) { - if (o.preventDefault) { - o.preventDefault(); - } - if (o.stopImmediatePropagation) { - o.stopImmediatePropagation(); - } - return; - } - }); - //set onNodeChanged event listener editor.on('NodeChange', onNodeChanged); - /** - * Listen for the keydown in the editor, we'll check if we are currently on a macro element, if so - * we'll check if the key down is a supported key which requires an action, otherwise we ignore the request - * so the macro cannot be edited. - * - * TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/ - */ - editor.on('KeyDown', function (e) { - if (isOnMacroElement) { - var macroElement = editor.selection.getNode(); - - //get the 'real' element (either p or the real one) - macroElement = getRealMacroElem(macroElement); - - //prevent editing - e.preventDefault(); - e.stopPropagation(); - - var moveSibling = function (element, isNext) { - var $e = $(element); - var $sibling = isNext ? $e.next() : $e.prev(); - if ($sibling.length > 0) { - editor.selection.select($sibling.get(0)); - editor.selection.collapse(true); - } else { - //if we're moving previous and there is no sibling, then lets recurse and just select the next one - if (!isNext) { - moveSibling(element, true); - return; - } - - //if there is no sibling we'll generate a new p at the end and select it - editor.setContent(editor.getContent() + "

 

"); - editor.selection.select($(editor.dom.getRoot()).children().last().get(0)); - editor.selection.collapse(true); - - } - }; - - //supported keys to move to the next or prev element (13-enter, 27-esc, 38-up, 40-down, 39-right, 37-left) - //supported keys to remove the macro (8-backspace, 46-delete) - // TODO: Should we make the enter key insert a line break before or leave it as moving to the next element? - if ($.inArray(e.keyCode, [13, 40, 39]) !== -1) { - //move to next element - moveSibling(macroElement, true); - } else if ($.inArray(e.keyCode, [27, 38, 37]) !== -1) { - //move to prev element - moveSibling(macroElement, false); - } else if ($.inArray(e.keyCode, [8, 46]) !== -1) { - //delete macro element - - //move first, then delete - moveSibling(macroElement, false); - editor.dom.remove(macroElement); - } - return; - } - }); - }, /** The insert macro button click event handler */ @@ -739,6 +572,10 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s insertMacroInEditor: function (editor, macroObject) { + //Important note: the TinyMce plugin "noneditable" is used here so that the macro cannot be edited, + // for this to work the mceNonEditable class needs to come last and we also need to use the attribute contenteditable = false + // (even though all the docs and examples say that is not necessary) + //put the macro syntax in comments, we will parse this out on the server side to be used //for persisting. var macroSyntaxComment = ""; @@ -746,7 +583,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s var uniqueId = "umb-macro-" + editor.dom.uniqueId(); var macroDiv = editor.dom.create('div', { - 'class': 'umb-macro-holder ' + macroObject.macroAlias + ' mceNonEditable ' + uniqueId + 'class': 'umb-macro-holder ' + macroObject.macroAlias + " " + uniqueId + ' mceNonEditable', + 'contenteditable': 'false' }, macroSyntaxComment + 'Macro alias: ' + macroObject.macroAlias + ''); diff --git a/src/Umbraco.Web.UI.Client/src/less/rte.less b/src/Umbraco.Web.UI.Client/src/less/rte.less index 9aae9840d1..d9888eb9d3 100644 --- a/src/Umbraco.Web.UI.Client/src/less/rte.less +++ b/src/Umbraco.Web.UI.Client/src/less/rte.less @@ -26,7 +26,16 @@ } /* loader for macro loading in tinymce*/ +.mce-content-body .umb-macro-holder { + border: 3px dotted @pinkLight; + padding: 7px; + display: block; + margin: 3px; +} .umb-rte .mce-content-body .umb-macro-holder.loading { + + /*fixme: this image doesn't exist*/ + background: url(img/loader.gif) right no-repeat; background-size: 18px; background-position-x: 99%; From 9abd72f6231a9fc517b2cb89776448df41a2453a Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 31 Jan 2019 17:12:44 +1100 Subject: [PATCH 037/555] gets macro content loading on rte load --- .../src/common/services/tinymce.service.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index b2ec94fffe..90cb793a91 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -474,6 +474,16 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s } }); + }); + + /** when the contents load we need to find any macros declared and load in their content */ + editor.on("SetContent", function (o) { + + //get all macro divs and load their content + $(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () { + createInsertMacroScope.loadMacroContent($(this), null); + }); + }); /** @@ -518,16 +528,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s //NOTE: This could be another way to deal with the active/inactive state //editor.on('ObjectSelected', function (e) {}); - /** when the contents load we need to find any macros declared and load in their content */ - editor.on("LoadContent", function (o) { - - //get all macro divs and load their content - $(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () { - createInsertMacroScope.loadMacroContent($(this), null); - }); - - }); - //set onNodeChanged event listener editor.on('NodeChange', onNodeChanged); From a36b1962c6288541fb1c1c0cefd743382ae765e2 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 09:32:50 +0000 Subject: [PATCH 038/555] Last of providers moved across & the old config file gone --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 - .../config/EmbeddedMedia.Release.config | 134 ------------------ .../config/EmbeddedMedia.config | 24 ---- .../Media/EmbedProviders/DailyMotion.cs | 28 ++++ .../Media/EmbedProviders/Youtube.cs | 29 ++++ src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 13 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 + 7 files changed, 64 insertions(+), 170 deletions(-) delete mode 100644 src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config delete mode 100644 src/Umbraco.Web.UI/config/EmbeddedMedia.config create mode 100644 src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs create mode 100644 src/Umbraco.Web/Media/EmbedProviders/Youtube.cs diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 38f43f344f..e0660f8f12 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -178,9 +178,6 @@ Designer - - EmbeddedMedia.config - Designer @@ -300,7 +297,6 @@ Designer - diff --git a/src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config b/src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config deleted file mode 100644 index 442493e3d6..0000000000 --- a/src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - json - - - - - - - - - - - - - - - - - - - - 1 - xml - https - - - - - - - - - - - - - - xml - - - - - - - - xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web.UI/config/EmbeddedMedia.config b/src/Umbraco.Web.UI/config/EmbeddedMedia.config deleted file mode 100644 index a5edaf3834..0000000000 --- a/src/Umbraco.Web.UI/config/EmbeddedMedia.config +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - 1 - xml - https - - - - - - - - - xml - - - - diff --git a/src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs b/src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs new file mode 100644 index 0000000000..78ea0b8662 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class DailyMotion : EmbedProviderBase + { + public override string ApiEndpoint => "https://www.dailymotion.com/services/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"dailymotion.com/video/.*" + }; + + public override Dictionary RequestParams => new Dictionary() + { + //ApiUrl/?format=xml + {"format", "xml"} + }; + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs b/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs new file mode 100644 index 0000000000..7755a36958 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class YouTube : EmbedProviderBase + { + public override string ApiEndpoint => "https://www.youtube.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"youtu.be/.*", + @"youtu.be/.*" + }; + + public override Dictionary RequestParams => new Dictionary() + { + //ApiUrl/?format=json + {"format", "json"} + }; + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 5974288daf..43add0f15e 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -217,22 +217,19 @@ namespace Umbraco.Web.Runtime // register OEmbed providers // no type scanning - all explicit opt-in of adding types composition.WithCollectionBuilder() + .Append() + .Append() + .Append() + .Append() + .Append() .Append() .Append() .Append() .Append() - .Append() - .Append() - .Append() .Append() .Append() .Append() .Append(); - - - //Giphy - //Meetup - //Spotify } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f9fdb5aabb..8be153889e 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -143,11 +143,13 @@ + + From 26e0c6cb79a60a99b0170118f852458a0066e90b Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 31 Jan 2019 10:43:34 +0100 Subject: [PATCH 039/555] Don't break for root relations + minimize number of XHR --- .../views/relationtypes/edit.controller.js | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js index ed0845a773..9ae3813bd2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/relationtypes/edit.controller.js @@ -71,18 +71,40 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource, } function getRelationNames(relationType) { - if(relationType.relations) { - angular.forEach(relationType.relations, function(relation){ - entityResource.getById(relation.parentId, relationType.parentObjectTypeName).then(function(entity) { - relation.parentName = entity.name; + if (relationType.relations) { + // can we grab app entity types in one go? + if (relationType.parentObjectType === relationType.childObjectType) { + // yep, grab the distinct list of parent and child entities + var entityIds = _.uniq(_.union(_.pluck(relationType.relations, "parentId"), _.pluck(relationType.relations, "childId"))); + entityResource.getByIds(entityIds, relationType.parentObjectTypeName).then(function (entities) { + updateRelationNames(relationType, entities); }); - entityResource.getById(relation.childId, relationType.childObjectTypeName).then(function(entity) { - relation.childName = entity.name; + } else { + // nope, grab the parent and child entities individually + var parentEntityIds = _.uniq(_.pluck(relationType.relations, "parentId")); + var childEntityIds = _.uniq(_.pluck(relationType.relations, "childId")); + entityResource.getByIds(parentEntityIds, relationType.parentObjectTypeName).then(function (entities) { + updateRelationNames(relationType, entities); }); - }); + entityResource.getByIds(childEntityIds, relationType.childObjectTypeName).then(function (entities) { + updateRelationNames(relationType, entities); + }); + } } } + function updateRelationNames(relationType, entities) { + var entitiesById = _.indexBy(entities, "id"); + _.each(relationType.relations, function(relation) { + if (entitiesById[relation.parentId]) { + relation.parentName = entitiesById[relation.parentId].name; + } + if (entitiesById[relation.childId]) { + relation.childName = entitiesById[relation.childId].name; + } + }); + } + function saveRelationType() { vm.page.saveButtonState = "busy"; From 8d55340325b457427661d0ae31d8b0a5e66b255a Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 10:23:54 +0000 Subject: [PATCH 040/555] Fix up youtube URL regex matching --- src/Umbraco.Web/Media/EmbedProviders/Youtube.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs b/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs index 7755a36958..4e6f437047 100644 --- a/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs +++ b/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs @@ -9,7 +9,7 @@ namespace Umbraco.Web.Media.EmbedProviders public override string[] UrlSchemeRegex => new string[] { @"youtu.be/.*", - @"youtu.be/.*" + @"youtube.com/watch.*" }; public override Dictionary RequestParams => new Dictionary() From 14b97b6abe3858101a5945c46c83547efb9477a5 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 10:24:15 +0000 Subject: [PATCH 041/555] Fix up JS as the API model had changed --- .../infiniteeditors/embed/embed.controller.js | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js index fb66552731..06a5f028ef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js @@ -54,21 +54,22 @@ $scope.model.embed.preview = ""; - switch (response.data.Status) { + + switch (response.data.OEmbedStatus) { case 0: - //not supported - $scope.model.embed.info = "Not supported"; - break; + //not supported + $scope.model.embed.info = "Not supported"; + break; case 1: - //error - $scope.model.embed.info = "Could not embed media - please ensure the URL is valid"; - break; + //error + $scope.model.embed.info = "Could not embed media - please ensure the URL is valid"; + break; case 2: - $scope.model.embed.preview = response.data.Markup; - vm.trustedPreview = $sce.trustAsHtml(response.data.Markup); - $scope.model.embed.supportsDimensions = response.data.SupportsDimensions; - $scope.model.embed.success = true; - break; + $scope.model.embed.preview = response.data.Markup; + vm.trustedPreview = $sce.trustAsHtml(response.data.Markup); + $scope.model.embed.supportsDimensions = response.data.SupportsDimensions; + $scope.model.embed.success = true; + break; } }, function() { $scope.model.embed.supportsDimensions = false; From 1a64c0a8034fbf5308b0ac2a5775e349bf557d13 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 31 Jan 2019 11:45:08 +0100 Subject: [PATCH 042/555] Fix disappearing media thumbnails --- .../src/common/directives/components/umbmediagrid.directive.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js index 308ffbf00f..0a69533938 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js @@ -157,7 +157,8 @@ Use this directive to generate a thumbnail grid of media items. item.isFolder = !mediaHelper.hasFilePropertyType(item); } - if (!item.isFolder) { + // if it's not a folder, get the thumbnail, extension etc. if we haven't already + if (!item.isFolder && !item.thumbnail) { // handle entity if(item.image) { From 34be548aec4593433d21c31d0499c22419074023 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 10:56:09 +0000 Subject: [PATCH 043/555] Start work on adding AppSettings keys into a constants class & use new prefix of Umbraco.Core. --- build/NuSpecs/tools/install.ps1 | 2 +- src/Umbraco.Core/Composing/RegisterFactory.cs | 4 ++-- .../Configuration/GlobalSettings.cs | 6 +++--- src/Umbraco.Core/Constants-AppSettings.cs | 20 +++++++++++++++++++ .../Migrations/Upgrade/UmbracoPlan.cs | 4 ++-- .../Migrations/Upgrade/UmbracoUpgrader.cs | 4 ++-- src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Tests/App.config | 2 +- src/Umbraco.Tests/Runtimes/StandaloneTests.cs | 2 +- .../Security/BackOfficeCookieManagerTests.cs | 2 +- src/Umbraco.Web.UI/web.Template.config | 2 +- 11 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 src/Umbraco.Core/Constants-AppSettings.cs diff --git a/build/NuSpecs/tools/install.ps1 b/build/NuSpecs/tools/install.ps1 index 9cc7bd5b26..5ca42b54a1 100644 --- a/build/NuSpecs/tools/install.ps1 +++ b/build/NuSpecs/tools/install.ps1 @@ -54,7 +54,7 @@ if ($project) { [xml]$config = Get-Content $destinationWebConfig $config.configuration.appSettings.ChildNodes | ForEach-Object { - if($_.key -eq "umbracoConfigurationStatus") + if($_.key -eq "Umbraco.Core.ConfigurationStatus") { # The web.config has an umbraco-specific appSetting in it # don't overwrite it and let config transforms do their thing diff --git a/src/Umbraco.Core/Composing/RegisterFactory.cs b/src/Umbraco.Core/Composing/RegisterFactory.cs index 8ee6e5a94c..975de7647d 100644 --- a/src/Umbraco.Core/Composing/RegisterFactory.cs +++ b/src/Umbraco.Core/Composing/RegisterFactory.cs @@ -18,14 +18,14 @@ namespace Umbraco.Core.Composing /// Creates a new instance of the configured container. ///
/// - /// To override the default LightInjectContainer, add an appSetting named umbracoContainerType with + /// To override the default LightInjectContainer, add an appSetting named umbracoRegisterType with /// a fully qualified type name to a class with a static method "Create" returning an IRegister. /// public static IRegister Create() { Type type; - var configuredTypeName = ConfigurationManager.AppSettings["umbracoRegisterType"]; + var configuredTypeName = ConfigurationManager.AppSettings[Constants.AppSettings.RegisterType]; if (configuredTypeName.IsNullOrWhiteSpace()) { // try to get the web LightInject container type, diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index b89a4d1daf..b9bce30cd8 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -161,13 +161,13 @@ namespace Umbraco.Core.Configuration { get { - return ConfigurationManager.AppSettings.ContainsKey("umbracoConfigurationStatus") - ? ConfigurationManager.AppSettings["umbracoConfigurationStatus"] + return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ConfigurationStatus) + ? ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus] : string.Empty; } set { - SaveSetting("umbracoConfigurationStatus", value); + SaveSetting(Constants.AppSettings.ConfigurationStatus, value); } } diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs new file mode 100644 index 0000000000..800f476c2a --- /dev/null +++ b/src/Umbraco.Core/Constants-AppSettings.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel; + +namespace Umbraco.Core +{ + public static partial class Constants + { + /// + /// Defines the identifiers for Umbraco system nodes. + /// + public static class AppSettings + { + public const string RegisterType = "Umbraco.Core.RegisterType"; + + public const string ConfigurationStatus = "Umbraco.Core.ConfigurationStatus"; //umbracoConfigurationStatus + + + } + } +} diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 9bf58c8d2f..0d0e733591 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -36,8 +36,8 @@ namespace Umbraco.Core.Migrations.Upgrade get { // no state in database yet - assume we have something in web.config that makes some sense - if (!SemVersion.TryParse(ConfigurationManager.AppSettings["umbracoConfigurationStatus"], out var currentVersion)) - throw new InvalidOperationException("Could not get current version from web.config umbracoConfigurationStatus appSetting."); + if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var currentVersion)) + throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting."); // we currently support upgrading from 7.10.0 and later if (currentVersion < new SemVersion(7, 10)) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs index fa29e80a6b..ac87b8c94d 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs @@ -35,8 +35,8 @@ namespace Umbraco.Core.Migrations.Upgrade public override void AfterMigrations(IScope scope, ILogger logger) { // assume we have something in web.config that makes some sense = the origin version - if (!SemVersion.TryParse(ConfigurationManager.AppSettings["umbracoConfigurationStatus"], out var originVersion)) - throw new InvalidOperationException("Could not get current version from web.config umbracoConfigurationStatus appSetting."); + if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var originVersion)) + throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting."); // target version is the code version var targetVersion = UmbracoVersion.SemanticVersion; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 4e6e832294..64a62d1cf0 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -285,6 +285,7 @@ + diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 4c5bb57aa2..6607a288b5 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -4,7 +4,7 @@ - + diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs index 3790a49cfc..49bc8149a9 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -52,7 +52,7 @@ namespace Umbraco.Tests.Runtimes // settings // reset the current version to 0.0.0, clear connection strings - ConfigurationManager.AppSettings["umbracoConfigurationStatus"] = ""; + ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus] = ""; // FIXME: we need a better management of settings here (and, true config files?) // create the very basic and essential things we need diff --git a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs index f0409d8928..e32df610b9 100644 --- a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Security public void ShouldAuthenticateRequest_When_Not_Configured() { //should force app ctx to show not-configured - ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", ""); + ConfigurationManager.AppSettings.Set(Constants.AppSettings.ConfigurationStatus, ""); var globalSettings = TestObjects.GetGlobalSettings(); var umbracoContext = new UmbracoContext( diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 2eb3551797..06c055b98e 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -30,7 +30,7 @@ - + From 69f7a1b7b9b2467346af2e7c895aea5d7e7bd37a Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 12:05:56 +0000 Subject: [PATCH 044/555] Finish up remaining AppSetting keys as Constants --- src/Umbraco.Core/Composing/TypeFinder.cs | 2 +- src/Umbraco.Core/Configuration/CoreDebug.cs | 4 +- .../Configuration/GlobalSettings.cs | 34 ++++++++--------- .../Configuration/UmbracoVersion.cs | 2 +- src/Umbraco.Core/Constants-AppSettings.cs | 37 +++++++++++++++++++ src/Umbraco.Core/IO/SystemFiles.cs | 5 ++- src/Umbraco.Core/Models/Language.cs | 2 +- .../Persistence/UmbracoDatabaseFactory.cs | 2 +- .../Runtime/CoreRuntimeComposer.cs | 2 +- src/Umbraco.Tests/App.config | 15 ++++---- .../PublishedMediaCache.cs | 2 +- src/Umbraco.Web.UI/web.Template.config | 14 +++---- .../Runtime/WebRuntimeComponent.cs | 2 +- ...eDirectoryBackOfficeUserPasswordChecker.cs | 1 + 14 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs index 308d0ecfd7..5ad1e43580 100644 --- a/src/Umbraco.Core/Composing/TypeFinder.cs +++ b/src/Umbraco.Core/Composing/TypeFinder.cs @@ -32,7 +32,7 @@ namespace Umbraco.Core.Composing if (_assembliesAcceptingLoadExceptions != null) return _assembliesAcceptingLoadExceptions; - var s = ConfigurationManager.AppSettings["Umbraco.AssembliesAcceptingLoadExceptions"]; + var s = ConfigurationManager.AppSettings[Constants.AppSettings.AssembliesAcceptingLoadExceptions]; return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s) ? Array.Empty() : s.Split(',').Select(x => x.Trim()).ToArray(); diff --git a/src/Umbraco.Core/Configuration/CoreDebug.cs b/src/Umbraco.Core/Configuration/CoreDebug.cs index 3e39eb6db5..b24e8a3329 100644 --- a/src/Umbraco.Core/Configuration/CoreDebug.cs +++ b/src/Umbraco.Core/Configuration/CoreDebug.cs @@ -7,8 +7,8 @@ namespace Umbraco.Core.Configuration public CoreDebug() { var appSettings = System.Configuration.ConfigurationManager.AppSettings; - LogUncompletedScopes = string.Equals("true", appSettings["Umbraco.CoreDebug.LogUncompletedScopes"], StringComparison.OrdinalIgnoreCase); - DumpOnTimeoutThreadAbort = string.Equals("true", appSettings["Umbraco.CoreDebug.DumpOnTimeoutThreadAbort"], StringComparison.OrdinalIgnoreCase); + LogUncompletedScopes = string.Equals("true", appSettings[Constants.AppSettings.Debug.LogUncompletedScopes], StringComparison.OrdinalIgnoreCase); + DumpOnTimeoutThreadAbort = string.Equals("true", appSettings[Constants.AppSettings.Debug.DumpOnTimeoutThreadAbort], StringComparison.OrdinalIgnoreCase); } // when true, Scope logs the stack trace for any scope that gets disposed without being completed. diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index b9bce30cd8..e30bf85fd0 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -85,8 +85,8 @@ namespace Umbraco.Core.Configuration { if (_reservedUrls != null) return _reservedUrls; - var urls = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls") - ? ConfigurationManager.AppSettings["umbracoReservedUrls"] + var urls = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ReservedUrls) + ? ConfigurationManager.AppSettings[Constants.AppSettings.ReservedUrls] : string.Empty; //ensure the built on (non-changeable) reserved paths are there at all times @@ -107,14 +107,14 @@ namespace Umbraco.Core.Configuration if (_reservedPaths != null) return _reservedPaths; var reservedPaths = StaticReservedPaths; - var umbPath = ConfigurationManager.AppSettings.ContainsKey("umbracoPath") && !ConfigurationManager.AppSettings["umbracoPath"].IsNullOrWhiteSpace() - ? ConfigurationManager.AppSettings["umbracoPath"] + var umbPath = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path) && !ConfigurationManager.AppSettings[Constants.AppSettings.Path].IsNullOrWhiteSpace() + ? ConfigurationManager.AppSettings[Constants.AppSettings.Path] : "~/umbraco"; //always add the umbraco path to the list reservedPaths += umbPath.EnsureEndsWith(','); - var allPaths = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths") - ? ConfigurationManager.AppSettings["umbracoReservedPaths"] + var allPaths = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ReservedPaths) + ? ConfigurationManager.AppSettings[Constants.AppSettings.ReservedPaths] : string.Empty; _reservedPaths = reservedPaths + allPaths; @@ -133,8 +133,8 @@ namespace Umbraco.Core.Configuration { get { - return ConfigurationManager.AppSettings.ContainsKey("umbracoContentXML") - ? ConfigurationManager.AppSettings["umbracoContentXML"] + return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ContentXML) + ? ConfigurationManager.AppSettings[Constants.AppSettings.ContentXML] : "~/App_Data/umbraco.config"; } } @@ -147,8 +147,8 @@ namespace Umbraco.Core.Configuration { get { - return ConfigurationManager.AppSettings.ContainsKey("umbracoPath") - ? IOHelper.ResolveUrl(ConfigurationManager.AppSettings["umbracoPath"]) + return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path) + ? IOHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path]) : string.Empty; } } @@ -249,7 +249,7 @@ namespace Umbraco.Core.Configuration { try { - return int.Parse(ConfigurationManager.AppSettings["umbracoTimeOutInMinutes"]); + return int.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.TimeOutInMinutes]); } catch { @@ -268,7 +268,7 @@ namespace Umbraco.Core.Configuration { try { - return int.Parse(ConfigurationManager.AppSettings["umbracoVersionCheckPeriod"]); + return int.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.VersionCheckPeriod]); } catch { @@ -287,7 +287,7 @@ namespace Umbraco.Core.Configuration { get { - var setting = ConfigurationManager.AppSettings["umbracoLocalTempStorage"]; + var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage]; if (!string.IsNullOrWhiteSpace(setting)) return Enum.Parse(setting); @@ -304,8 +304,8 @@ namespace Umbraco.Core.Configuration { get { - return ConfigurationManager.AppSettings.ContainsKey("umbracoDefaultUILanguage") - ? ConfigurationManager.AppSettings["umbracoDefaultUILanguage"] + return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.DefaultUILanguage) + ? ConfigurationManager.AppSettings[Constants.AppSettings.DefaultUILanguage] : string.Empty; } } @@ -322,7 +322,7 @@ namespace Umbraco.Core.Configuration { try { - return bool.Parse(ConfigurationManager.AppSettings["umbracoHideTopLevelNodeFromPath"]); + return bool.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.HideTopLevelNodeFromPath]); } catch { @@ -340,7 +340,7 @@ namespace Umbraco.Core.Configuration { try { - return bool.Parse(ConfigurationManager.AppSettings["umbracoUseHttps"]); + return bool.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.UseHttps]); } catch { diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 7ab97500f0..2f615d26b3 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -82,7 +82,7 @@ namespace Umbraco.Core.Configuration try { // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings - var value = ConfigurationManager.AppSettings["umbracoConfigurationStatus"]; + var value = ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus]; return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null; } catch diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs index 800f476c2a..67f92f4046 100644 --- a/src/Umbraco.Core/Constants-AppSettings.cs +++ b/src/Umbraco.Core/Constants-AppSettings.cs @@ -10,11 +10,48 @@ namespace Umbraco.Core ///
public static class AppSettings { + // TODO: Kill me - still used in Umbraco.Core.IO.SystemFiles:27 + [Obsolete("We need to kill this appsetting as we do not use XML content cache umbraco.config anymore due to NuCache")] + public const string ContentXML = "Umbraco.Core.ContentXML"; //umbracoContentXML + + public const string RegisterType = "Umbraco.Core.RegisterType"; + + public const string PublishedMediaCacheSeconds = "Umbraco.Core.PublishedMediaCacheSeconds"; //"Umbraco.PublishedMediaCache.Seconds" + + public const string AssembliesAcceptingLoadExceptions = "Umbraco.Core.AssembliesAcceptingLoadExceptions"; //Umbraco.AssembliesAcceptingLoadExceptions public const string ConfigurationStatus = "Umbraco.Core.ConfigurationStatus"; //umbracoConfigurationStatus + + public const string Path = "Umbraco.Core.Path"; //umbracoPath + + public const string ReservedUrls = "Umbraco.Core.ReservedUrls"; //umbracoReservedUrls + + public const string ReservedPaths = "Umbraco.Core.ReservedPaths"; //umbracoReservedPaths + + public const string TimeOutInMinutes = "Umbraco.Core.TimeOutInMinutes"; //umbracoTimeOutInMinutes + + public const string VersionCheckPeriod = "Umbraco.Core.VersionCheckPeriod"; //umbracoVersionCheckPeriod + + public const string LocalTempStorage = "Umbraco.Core.LocalTempStorage"; //umbracoLocalTempStorage + + public const string DefaultUILanguage = "Umbraco.Core.DefaultUILanguage"; //umbracoDefaultUILanguage + + public const string HideTopLevelNodeFromPath = "Umbraco.Core.HideTopLevelNodeFromPath"; //umbracoHideTopLevelNodeFromPath + + public const string UseHttps = "Umbraco.Core.UseHttps"; //umbracoUseHttps + + public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer"; //umbracoDisableElectionForSingleServer + + public const string DatabaseFactoryServerVersion = "Umbraco.Core.DatabaseFactoryServerVersion"; //Umbraco.DatabaseFactory.ServerVersion + public static class Debug + { + public const string LogUncompletedScopes = "Umbraco.Core.LogUncompletedScopes"; //"Umbraco.CoreDebug.LogUncompletedScopes" + + public const string DumpOnTimeoutThreadAbort = "Umbraco.Core.DumpOnTimeoutThreadAbort"; //Umbraco.CoreDebug.DumpOnTimeoutThreadAbort + } } } } diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 0e5ae8388b..f3376901a9 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -8,7 +8,8 @@ namespace Umbraco.Core.IO public class SystemFiles { public static string TinyMceConfig => SystemDirectories.Config + "/tinyMceConfig.config"; - + + // TODO: Kill this off we don't have umbraco.config XML cache we now have NuCache public static string GetContentCacheXml(IGlobalSettings globalSettings) { switch (globalSettings.LocalTempStorageLocation) @@ -24,7 +25,7 @@ namespace Umbraco.Core.IO appDomainHash); return Path.Combine(cachePath, "umbraco.config"); case LocalTempStorage.Default: - return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config"); + return IOHelper.ReturnPath(Constants.AppSettings.ContentXML, "~/App_Data/umbraco.config"); default: throw new ArgumentOutOfRangeException(); } diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs index 03f8f87cd3..b02eb4805c 100644 --- a/src/Umbraco.Core/Models/Language.cs +++ b/src/Umbraco.Core/Models/Language.cs @@ -67,7 +67,7 @@ namespace Umbraco.Core.Models // culture // // I assume that, on a site, all language names should be in the SAME language, in DB, - // and that would be the umbracoDefaultUILanguage (app setting) - BUT if by accident + // and that would be the Umbraco.Core.DefaultUILanguage (app setting) - BUT if by accident // ANY culture has been retrieved with another current thread culture - it's now corrupt // // so, the logic below ensures that the name always end up being the correct name diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs index eab0ae5509..3d0d49a5f0 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs @@ -139,7 +139,7 @@ namespace Umbraco.Core.Persistence { // replace NPoco database type by a more efficient one - var setting = ConfigurationManager.AppSettings["Umbraco.DatabaseFactory.ServerVersion"]; + var setting = ConfigurationManager.AppSettings[Constants.AppSettings.DatabaseFactoryServerVersion]; var fromSettings = false; if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.") diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs index ee289ddcfa..2d1a4c1650 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs @@ -76,7 +76,7 @@ namespace Umbraco.Core.Runtime // TODO: this is a hack, use proper configuration! // also: we still register the full IServerMessenger because // even on 1 single server we can have 2 concurrent app domains - var singleServer = "true".InvariantEquals(ConfigurationManager.AppSettings["umbracoDisableElectionForSingleServer"]); + var singleServer = "true".InvariantEquals(ConfigurationManager.AppSettings[Constants.AppSettings.DisableElectionForSingleServer]); return singleServer ? (IServerRegistrar) new SingleServerRegistrar(f.GetInstance()) : new DatabaseServerRegistrar( diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 6607a288b5..5e366eef33 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -5,14 +5,13 @@ - - - - - - - - + + + + + + + diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs index 8cfc06c501..c62614ef22 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs @@ -645,7 +645,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache private static void InitializeCacheConfig() { - var value = ConfigurationManager.AppSettings["Umbraco.PublishedMediaCache.Seconds"]; + var value = ConfigurationManager.AppSettings[Constants.AppSettings.PublishedMediaCacheSeconds]; int seconds; if (int.TryParse(value, out seconds) == false) seconds = PublishedMediaCacheTimespanSeconds; diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 06c055b98e..d93089fe21 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -31,13 +31,13 @@ - - - - - - - + + + + + + + diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 4fb8dadf17..123cb952d7 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -248,7 +248,7 @@ namespace Umbraco.Web.Runtime XmlFileMapper.FileMapDefaultFolder = SystemDirectories.TempData.EnsureEndsWith('/') + "ClientDependency"; BaseCompositeFileProcessingProvider.UrlTypeDefault = CompositeUrlType.Base64QueryStrings; - // Now we need to detect if we are running umbracoLocalTempStorage as EnvironmentTemp and in that case we want to change the CDF file + // Now we need to detect if we are running 'Umbraco.Core.LocalTempStorage' as EnvironmentTemp and in that case we want to change the CDF file // location to be there if (globalSettings.LocalTempStorageLocation == LocalTempStorage.EnvironmentTemp) { diff --git a/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs b/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs index 5b571f304e..036a1718b0 100644 --- a/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs +++ b/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs @@ -13,6 +13,7 @@ namespace Umbraco.Web.Security { get { + // TODO: Verify this AppSetting key is used in .NET Framework & canot be changed to Umbraco.Core. prefix return ConfigurationManager.AppSettings["ActiveDirectoryDomain"]; } } From bc7748aed618019785b62474238b7d26dfed81b9 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 12:37:54 +0000 Subject: [PATCH 045/555] Adds in XML docs summary - still need assitance with a few keys so put in some TODOs --- src/Umbraco.Core/Composing/RegisterFactory.cs | 2 +- src/Umbraco.Core/Constants-AppSettings.cs | 135 +++++++++++++----- .../Persistence/UmbracoDatabaseFactory.cs | 2 +- 3 files changed, 103 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Core/Composing/RegisterFactory.cs b/src/Umbraco.Core/Composing/RegisterFactory.cs index 975de7647d..ea25d6a135 100644 --- a/src/Umbraco.Core/Composing/RegisterFactory.cs +++ b/src/Umbraco.Core/Composing/RegisterFactory.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Composing /// Creates a new instance of the configured container. /// /// - /// To override the default LightInjectContainer, add an appSetting named umbracoRegisterType with + /// To override the default LightInjectContainer, add an appSetting named 'Umbraco.Core.RegisterType' with /// a fully qualified type name to a class with a static method "Create" returning an IRegister. /// public static IRegister Create() diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs index 67f92f4046..ac0cbde8de 100644 --- a/src/Umbraco.Core/Constants-AppSettings.cs +++ b/src/Umbraco.Core/Constants-AppSettings.cs @@ -1,12 +1,11 @@ using System; -using System.ComponentModel; namespace Umbraco.Core { public static partial class Constants { /// - /// Defines the identifiers for Umbraco system nodes. + /// Specific web.config AppSetting keys for Umbraco.Core application /// public static class AppSettings { @@ -14,43 +13,111 @@ namespace Umbraco.Core [Obsolete("We need to kill this appsetting as we do not use XML content cache umbraco.config anymore due to NuCache")] public const string ContentXML = "Umbraco.Core.ContentXML"; //umbracoContentXML - + /// + /// TODO: FILL ME IN + /// public const string RegisterType = "Umbraco.Core.RegisterType"; + + /// + /// This is used for a unit test in PublishedMediaCache + /// + public const string PublishedMediaCacheSeconds = "Umbraco.Core.PublishedMediaCacheSeconds"; + + /// + /// TODO: FILL ME IN + /// + public const string AssembliesAcceptingLoadExceptions = "Umbraco.Core.AssembliesAcceptingLoadExceptions"; + + /// + /// This will return the version number of the currently installed umbraco instance + /// + /// + /// Umbraco will automatically set & modify this value when installing & upgrading + /// + public const string ConfigurationStatus = "Umbraco.Core.ConfigurationStatus"; + + /// + /// Gets the path to umbraco's root directory (/umbraco by default). + /// + public const string Path = "Umbraco.Core.Path"; + + /// + /// The reserved urls from web.config. + /// + public const string ReservedUrls = "Umbraco.Core.ReservedUrls"; + + /// + /// The reserved paths from web.config + /// + public const string ReservedPaths = "Umbraco.Core.ReservedPaths"; + + /// + /// Set the timeout for the Umbraco backoffice in minutes + /// + public const string TimeOutInMinutes = "Umbraco.Core.TimeOutInMinutes"; + + /// + /// The number of days to check for a new version of Umbraco + /// + /// + /// Default is set to 7. Setting this to 0 will never check + /// This is used to help track statistics + /// + public const string VersionCheckPeriod = "Umbraco.Core.VersionCheckPeriod"; + + /// + /// This is the location type to store temporary files such as cache files or other localized files for a given machine + /// + /// + /// Currently used for the xml cache file and the plugin cache files + /// + public const string LocalTempStorage = "Umbraco.Core.LocalTempStorage"; + + /// + /// The default UI language of the backoffice such as 'en-US' + /// + public const string DefaultUILanguage = "Umbraco.Core.DefaultUILanguage"; + + /// + /// A true/false value indicating whether umbraco should hide top level nodes from generated urls. + /// + public const string HideTopLevelNodeFromPath = "Umbraco.Core.HideTopLevelNodeFromPath"; + + /// + /// A true or false indicating whether umbraco should force a secure (https) connection to the backoffice. + /// + public const string UseHttps = "Umbraco.Core.UseHttps"; + + /// + /// TODO: FILL ME IN + /// + public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer"; + - public const string PublishedMediaCacheSeconds = "Umbraco.Core.PublishedMediaCacheSeconds"; //"Umbraco.PublishedMediaCache.Seconds" - - public const string AssembliesAcceptingLoadExceptions = "Umbraco.Core.AssembliesAcceptingLoadExceptions"; //Umbraco.AssembliesAcceptingLoadExceptions - - public const string ConfigurationStatus = "Umbraco.Core.ConfigurationStatus"; //umbracoConfigurationStatus - - public const string Path = "Umbraco.Core.Path"; //umbracoPath - - public const string ReservedUrls = "Umbraco.Core.ReservedUrls"; //umbracoReservedUrls - - public const string ReservedPaths = "Umbraco.Core.ReservedPaths"; //umbracoReservedPaths - - public const string TimeOutInMinutes = "Umbraco.Core.TimeOutInMinutes"; //umbracoTimeOutInMinutes - - public const string VersionCheckPeriod = "Umbraco.Core.VersionCheckPeriod"; //umbracoVersionCheckPeriod - - public const string LocalTempStorage = "Umbraco.Core.LocalTempStorage"; //umbracoLocalTempStorage - - public const string DefaultUILanguage = "Umbraco.Core.DefaultUILanguage"; //umbracoDefaultUILanguage - - public const string HideTopLevelNodeFromPath = "Umbraco.Core.HideTopLevelNodeFromPath"; //umbracoHideTopLevelNodeFromPath - - public const string UseHttps = "Umbraco.Core.UseHttps"; //umbracoUseHttps - - public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer"; //umbracoDisableElectionForSingleServer - - public const string DatabaseFactoryServerVersion = "Umbraco.Core.DatabaseFactoryServerVersion"; //Umbraco.DatabaseFactory.ServerVersion - - + /// + /// Debug specific web.config AppSetting keys for Umbraco + /// + /// + /// Do not use these keys in a production environment + /// public static class Debug { - public const string LogUncompletedScopes = "Umbraco.Core.LogUncompletedScopes"; //"Umbraco.CoreDebug.LogUncompletedScopes" + /// + /// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed. + /// this helps troubleshooting rogue scopes that we forget to complete + /// + public const string LogUncompletedScopes = "Umbraco.Core.Debug.LogUncompletedScopes"; - public const string DumpOnTimeoutThreadAbort = "Umbraco.Core.DumpOnTimeoutThreadAbort"; //Umbraco.CoreDebug.DumpOnTimeoutThreadAbort + /// + /// When set to true, the Logger creates a mini dump of w3wp in ~/App_Data/MiniDump whenever it logs + /// an error due to a ThreadAbortException that is due to a timeout. + /// + public const string DumpOnTimeoutThreadAbort = "Umbraco.Core.Debug.DumpOnTimeoutThreadAbort"; + + /// + /// TODO: FILL ME IN + /// + public const string DatabaseFactoryServerVersion = "Umbraco.Core.Debug.DatabaseFactoryServerVersion"; } } } diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs index 3d0d49a5f0..681eb1232e 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs @@ -139,7 +139,7 @@ namespace Umbraco.Core.Persistence { // replace NPoco database type by a more efficient one - var setting = ConfigurationManager.AppSettings[Constants.AppSettings.DatabaseFactoryServerVersion]; + var setting = ConfigurationManager.AppSettings[Constants.AppSettings.Debug.DatabaseFactoryServerVersion]; var fromSettings = false; if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.") From 14c43d76c112a42f0de3e67de592b0f2eee6257d Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 31 Jan 2019 13:37:47 +0000 Subject: [PATCH 046/555] Adds OEmbedProviders to the composition extension to make it easier to add/append the collection --- src/Umbraco.Web/CompositionExtensions.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs index 6039d97a72..4302cdaeee 100644 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ b/src/Umbraco.Web/CompositionExtensions.cs @@ -6,6 +6,7 @@ using Umbraco.Web.ContentApps; using Umbraco.Web.Dashboards; using Umbraco.Web.Editors; using Umbraco.Web.HealthCheck; +using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -101,6 +102,13 @@ namespace Umbraco.Web public static DashboardCollectionBuilder Dashboards(this Composition composition) => composition.WithCollectionBuilder(); + /// + /// Gets the backoffice OEmbed Providers collection builder. + /// + /// The composition. + public static EmbedProvidersCollectionBuilder OEmbedProviders(this Composition composition) + => composition.WithCollectionBuilder(); + #endregion #region Uniques From 3199aa6693655c5dc1ccc7f27230073f84bf3c08 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 31 Jan 2019 14:03:09 +0100 Subject: [PATCH 047/555] Support culture in content Saving and Publishing events --- src/Umbraco.Core/Events/EventNameExtractor.cs | 29 ++- src/Umbraco.Core/Models/Content.cs | 47 ++-- src/Umbraco.Core/Models/ContentBase.cs | 14 +- .../Models/ContentCultureInfosCollection.cs | 4 +- ...ContentCultureInfosCollectionExtensions.cs | 12 + src/Umbraco.Core/Models/IContent.cs | 24 ++ src/Umbraco.Core/Models/IContentBase.cs | 17 ++ .../Implement/DocumentRepository.cs | 3 + .../Services/Implement/ContentService.cs | 5 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Services/AmbiguousEventTests.cs | 78 ++++++ .../Services/ContentServiceEventTests.cs | 224 ++++++++++++++++++ .../Services/ContentServiceTests.cs | 32 +-- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 6 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 + 15 files changed, 431 insertions(+), 67 deletions(-) create mode 100644 src/Umbraco.Core/Models/ContentCultureInfosCollectionExtensions.cs create mode 100644 src/Umbraco.Tests/Services/AmbiguousEventTests.cs create mode 100644 src/Umbraco.Tests/Services/ContentServiceEventTests.cs diff --git a/src/Umbraco.Core/Events/EventNameExtractor.cs b/src/Umbraco.Core/Events/EventNameExtractor.cs index 5cb9ca64ef..627426f2ee 100644 --- a/src/Umbraco.Core/Events/EventNameExtractor.cs +++ b/src/Umbraco.Core/Events/EventNameExtractor.cs @@ -35,6 +35,24 @@ namespace Umbraco.Core.Events /// null if not found or an ambiguous match /// public static Attempt FindEvent(Type senderType, Type argsType, Func exclude) + { + var events = FindEvents(senderType, argsType, exclude); + + switch (events.Length) + { + case 0: + return Attempt.Fail(new EventNameExtractorResult(EventNameExtractorError.NoneFound)); + + case 1: + return Attempt.Succeed(new EventNameExtractorResult(events[0])); + + default: + //there's more than one left so it's ambiguous! + return Attempt.Fail(new EventNameExtractorResult(EventNameExtractorError.Ambiguous)); + } + } + + internal static string[] FindEvents(Type senderType, Type argsType, Func exclude) { var found = MatchedEventNames.GetOrAdd(new Tuple(senderType, argsType), tuple => { @@ -78,16 +96,7 @@ namespace Umbraco.Core.Events }).Select(x => x.EventInfo.Name).ToArray(); }); - var filtered = found.Where(x => exclude(x) == false).ToArray(); - - if (filtered.Length == 0) - return Attempt.Fail(new EventNameExtractorResult(EventNameExtractorError.NoneFound)); - - if (filtered.Length == 1) - return Attempt.Succeed(new EventNameExtractorResult(filtered[0])); - - //there's more than one left so it's ambiguous! - return Attempt.Fail(new EventNameExtractorResult(EventNameExtractorError.Ambiguous)); + return found.Where(x => exclude(x) == false).ToArray(); } /// diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 0c679e5e70..1093ef3a0c 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -15,14 +15,12 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class Content : ContentBase, IContent { - private IContentType _contentType; private int? _templateId; private ContentScheduleCollection _schedule; private bool _published; private PublishedState _publishedState; - private ContentCultureInfosCollection _publishInfos; - private ContentCultureInfosCollection _publishInfosOrig; private HashSet _editedCultures; + private ContentCultureInfosCollection _publishInfos, _publishInfos1, _publishInfos2; private static readonly Lazy Ps = new Lazy(); @@ -48,7 +46,7 @@ namespace Umbraco.Core.Models public Content(string name, IContent parent, IContentType contentType, PropertyCollection properties, string culture = null) : base(name, parent, contentType, properties, culture) { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); + ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); _publishedState = PublishedState.Unpublished; PublishedVersionId = 0; } @@ -75,7 +73,7 @@ namespace Umbraco.Core.Models public Content(string name, int parentId, IContentType contentType, PropertyCollection properties, string culture = null) : base(name, parentId, contentType, properties, culture) { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); + ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); _publishedState = PublishedState.Unpublished; PublishedVersionId = 0; } @@ -137,7 +135,6 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _templateId, Ps.Value.TemplateSelector); } - /// /// Gets or sets a value indicating whether this content item is published or not. /// @@ -181,7 +178,7 @@ namespace Umbraco.Core.Models /// Gets the ContentType used by this content object /// [IgnoreDataMember] - public IContentType ContentType => _contentType; + public IContentType ContentType { get; private set; } /// [IgnoreDataMember] @@ -217,7 +214,7 @@ namespace Umbraco.Core.Models public bool WasCulturePublished(string culture) // just check _publishInfosOrig - a copy of _publishInfos // a non-available culture could not become published anyways - => _publishInfosOrig != null && _publishInfosOrig.ContainsKey(culture); + => _publishInfos1 != null && _publishInfos1.ContainsKey(culture); // adjust dates to sync between version, cultures etc // used by the repo when persisting @@ -228,7 +225,7 @@ namespace Umbraco.Core.Models if (_publishInfos == null || !_publishInfos.TryGetValue(culture, out var publishInfos)) continue; - if (_publishInfosOrig != null && _publishInfosOrig.TryGetValue(culture, out var publishInfosOrig) + if (_publishInfos1 != null && _publishInfos1.TryGetValue(culture, out var publishInfosOrig) && publishInfosOrig.Date == publishInfos.Date) continue; @@ -285,6 +282,24 @@ namespace Umbraco.Core.Models _publishInfos.AddOrUpdate(culture, name, date); } + // internal for repository + internal void AknPublishInfo() + { + _publishInfos1 = _publishInfos2 = new ContentCultureInfosCollection(_publishInfos); + } + + /// + public bool IsPublishingCulture(string culture) => _publishInfos.IsCultureUpdated(_publishInfos1, culture); + + /// + public bool IsUnpublishingCulture(string culture) => _publishInfos.IsCultureRemoved(_publishInfos1, culture); + + /// + public bool HasPublishedCulture(string culture) => _publishInfos1.IsCultureUpdated(_publishInfos2, culture); + + /// + public bool HasUnpublishedCulture(string culture) => _publishInfos1.IsCultureRemoved(_publishInfos2, culture); + private void ClearPublishInfos() { _publishInfos = null; @@ -300,7 +315,7 @@ namespace Umbraco.Core.Models if (_publishInfos.Count == 0) _publishInfos = null; // set the culture to be dirty - it's been modified - TouchCultureInfo(culture); + TouchCulture(culture); } // sets a publish edited @@ -423,7 +438,7 @@ namespace Umbraco.Core.Models public void ChangeContentType(IContentType contentType) { ContentTypeId = contentType.Id; - _contentType = contentType; + ContentType = contentType; ContentTypeBase = contentType; Properties.EnsurePropertyTypes(PropertyTypes); @@ -442,7 +457,7 @@ namespace Umbraco.Core.Models if(clearProperties) { ContentTypeId = contentType.Id; - _contentType = contentType; + ContentType = contentType; ContentTypeBase = contentType; Properties.EnsureCleanPropertyTypes(PropertyTypes); @@ -457,16 +472,18 @@ namespace Umbraco.Core.Models public override void ResetDirtyProperties(bool rememberDirty) { base.ResetDirtyProperties(rememberDirty); - + if (ContentType != null) ContentType.ResetDirtyProperties(rememberDirty); // take care of the published state _publishedState = _published ? PublishedState.Published : PublishedState.Unpublished; + _publishInfos2 = _publishInfos1; + // Make a copy of the _publishInfos, this is purely so that we can detect // if this entity's previous culture publish state (regardless of the rememberDirty flag) - _publishInfosOrig = _publishInfos == null + _publishInfos1 = _publishInfos == null ? null : new ContentCultureInfosCollection(_publishInfos); @@ -500,7 +517,7 @@ namespace Umbraco.Core.Models var clonedContent = (Content)clone; //need to manually clone this since it's not settable - clonedContent._contentType = (IContentType) ContentType.DeepClone(); + clonedContent.ContentType = (IContentType) ContentType.DeepClone(); //if culture infos exist then deal with event bindings if (clonedContent._publishInfos != null) diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index ca1152a9a4..e540866c3e 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Models protected IContentTypeComposition ContentTypeBase; private int _writerId; private PropertyCollection _properties; - private ContentCultureInfosCollection _cultureInfos; + private ContentCultureInfosCollection _cultureInfos, _cultureInfos1, _cultureInfos2; /// /// Initializes a new instance of the class. @@ -222,7 +222,8 @@ namespace Umbraco.Core.Models _cultureInfos = null; } - protected void TouchCultureInfo(string culture) + /// + public void TouchCulture(string culture) { if (_cultureInfos == null || !_cultureInfos.TryGetValue(culture, out var infos)) return; _cultureInfos.AddOrUpdate(culture, infos.Name, DateTime.Now); @@ -400,6 +401,9 @@ namespace Umbraco.Core.Models foreach (var prop in Properties) prop.ResetDirtyProperties(rememberDirty); + _cultureInfos2 = _cultureInfos1; + _cultureInfos1 = _cultureInfos == null ? null : new ContentCultureInfosCollection(_cultureInfos); + // take care of culture infos if (_cultureInfos == null) return; @@ -475,6 +479,12 @@ namespace Umbraco.Core.Models return instanceProperties.Concat(propertyTypes); } + /// + public bool IsSavingCulture(string culture) => _cultureInfos.IsCultureUpdated(_cultureInfos1, culture); + + /// + public bool HasSavedCulture(string culture) => _cultureInfos1.IsCultureUpdated(_cultureInfos2, culture); + #endregion /// diff --git a/src/Umbraco.Core/Models/ContentCultureInfosCollection.cs b/src/Umbraco.Core/Models/ContentCultureInfosCollection.cs index 82b0ba6475..287182d20e 100644 --- a/src/Umbraco.Core/Models/ContentCultureInfosCollection.cs +++ b/src/Umbraco.Core/Models/ContentCultureInfosCollection.cs @@ -31,7 +31,7 @@ namespace Umbraco.Core.Models foreach (var item in items) Add(new ContentCultureInfos(item)); } - + /// /// Adds or updates a instance. /// @@ -53,7 +53,7 @@ namespace Umbraco.Core.Models Name = name, Date = date }); - } + } } /// diff --git a/src/Umbraco.Core/Models/ContentCultureInfosCollectionExtensions.cs b/src/Umbraco.Core/Models/ContentCultureInfosCollectionExtensions.cs new file mode 100644 index 0000000000..98a0b48d07 --- /dev/null +++ b/src/Umbraco.Core/Models/ContentCultureInfosCollectionExtensions.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Models +{ + public static class ContentCultureInfosCollectionExtensions + { + public static bool IsCultureUpdated(this ContentCultureInfosCollection to, ContentCultureInfosCollection from, string culture) + => to != null && to.ContainsKey(culture) && + (from == null || !from.ContainsKey(culture) || from[culture].Date != to[culture].Date); + + public static bool IsCultureRemoved(this ContentCultureInfosCollection to, ContentCultureInfosCollection from, string culture) + => (to == null || !to.ContainsKey(culture)) && from != null && from.ContainsKey(culture); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/IContent.cs b/src/Umbraco.Core/Models/IContent.cs index 4363324c8d..d0f47bc2f2 100644 --- a/src/Umbraco.Core/Models/IContent.cs +++ b/src/Umbraco.Core/Models/IContent.cs @@ -177,5 +177,29 @@ namespace Umbraco.Core.Models /// Unpublishing must be finalized via the content service SavePublishing method. /// void UnpublishCulture(string culture = "*"); + + /// + /// Determines whether a culture is being published, during a Publishing event. + /// + /// Outside of a Publishing event handler, the returned value is unspecified. + bool IsPublishingCulture(string culture); + + /// + /// Determines whether a culture is being unpublished, during a Publishing event. + /// + /// Outside of a Publishing event handler, the returned value is unspecified. + bool IsUnpublishingCulture(string culture); + + /// + /// Determines whether a culture has been published, during a Published event. + /// + /// Outside of a Published event handler, the returned value is unspecified. + bool HasPublishedCulture(string culture); + + /// + /// Determines whether a culture has been unpublished, during a Published event. + /// + /// Outside of a Published event handler, the returned value is unspecified. + bool HasUnpublishedCulture(string culture); } } diff --git a/src/Umbraco.Core/Models/IContentBase.cs b/src/Umbraco.Core/Models/IContentBase.cs index 40a1c57097..d2a928f978 100644 --- a/src/Umbraco.Core/Models/IContentBase.cs +++ b/src/Umbraco.Core/Models/IContentBase.cs @@ -143,5 +143,22 @@ namespace Umbraco.Core.Models /// If the content type is variant, then culture can be either '*' or an actual culture, but neither 'null' nor /// 'empty'. If the content type is invariant, then culture can be either '*' or null or empty. Property[] ValidateProperties(string culture = "*"); + + /// + /// Determines whether a culture is being saved, during a Saving event. + /// + /// Outside of a Saving event handler, the returned value is unspecified. + bool IsSavingCulture(string culture); + + /// + /// Determines whether a culture has been saved, during a Saved event. + /// + /// Outside of a Saved event handler, the returned value is unspecified. + bool HasSavedCulture(string culture); + + /// + /// Updates a culture date, if the culture exists. + /// + void TouchCulture(string culture); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 6af7031883..70f3bd8071 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1188,8 +1188,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var v in contentVariation) content.SetCultureInfo(v.Culture, v.Name, v.Date); if (content.PublishedVersionId > 0 && contentVariations.TryGetValue(content.PublishedVersionId, out contentVariation)) + { foreach (var v in contentVariation) content.SetPublishInfo(v.Culture, v.Name, v.Date); + content.AknPublishInfo(); + } if (documentVariations.TryGetValue(content.Id, out var documentVariation)) foreach (var v in documentVariation.Where(x => x.Edited)) content.SetCultureEdited(v.Culture); diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index 266f34cc37..804fe35dd1 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.Linq; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -27,18 +26,16 @@ namespace Umbraco.Core.Services.Implement private readonly IContentTypeRepository _contentTypeRepository; private readonly IDocumentBlueprintRepository _documentBlueprintRepository; private readonly ILanguageRepository _languageRepository; - private readonly IMediaFileSystem _mediaFileSystem; private IQuery _queryNotTrashed; #region Constructors public ContentService(IScopeProvider provider, ILogger logger, - IEventMessagesFactory eventMessagesFactory, IMediaFileSystem mediaFileSystem, + IEventMessagesFactory eventMessagesFactory, IDocumentRepository documentRepository, IEntityRepository entityRepository, IAuditRepository auditRepository, IContentTypeRepository contentTypeRepository, IDocumentBlueprintRepository documentBlueprintRepository, ILanguageRepository languageRepository) : base(provider, logger, eventMessagesFactory) { - _mediaFileSystem = mediaFileSystem; _documentRepository = documentRepository; _entityRepository = entityRepository; _auditRepository = auditRepository; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 4e6e832294..e4fbfb3892 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -388,6 +388,7 @@ + diff --git a/src/Umbraco.Tests/Services/AmbiguousEventTests.cs b/src/Umbraco.Tests/Services/AmbiguousEventTests.cs new file mode 100644 index 0000000000..e137da1188 --- /dev/null +++ b/src/Umbraco.Tests/Services/AmbiguousEventTests.cs @@ -0,0 +1,78 @@ +using System; +using System.Reflection; +using System.Text; +using NUnit.Framework; +using Umbraco.Core.Events; +using Umbraco.Core.Services.Implement; + +namespace Umbraco.Tests.Services +{ + [TestFixture] + public class AmbiguousEventTests + { + [Explicit] + [TestCase(typeof(ContentService))] + [TestCase(typeof(MediaService))] + public void ListAmbiguousEvents(Type serviceType) + { + var typedEventHandler = typeof(TypedEventHandler<,>); + + // get all events + var events = serviceType.GetEvents(BindingFlags.Static | BindingFlags.Public); + + string TypeName(Type type) + { + if (!type.IsGenericType) + return type.Name; + var sb = new StringBuilder(); + TypeNameSb(type, sb); + return sb.ToString(); + } + + void TypeNameSb(Type type, StringBuilder sb) + { + var name = type.Name; + var pos = name.IndexOf('`'); + name = pos > 0 ? name.Substring(0, pos) : name; + sb.Append(name); + if (!type.IsGenericType) + return; + sb.Append("<"); + var first = true; + foreach (var arg in type.GetGenericArguments()) + { + if (first) first = false; + else sb.Append(", "); + TypeNameSb(arg, sb); + } + sb.Append(">"); + } + + foreach (var e in events) + { + // only continue if this is a TypedEventHandler + if (!e.EventHandlerType.IsGenericType) continue; + var typeDef = e.EventHandlerType.GetGenericTypeDefinition(); + if (typedEventHandler != typeDef) continue; + + // get the event args type + var eventArgsType = e.EventHandlerType.GenericTypeArguments[1]; + + // try to find the event back, based upon sender type + args type + // exclude -ing (eg Saving) events, we don't deal with them in EventDefinitionBase (they always trigger) + var found = EventNameExtractor.FindEvents(serviceType, eventArgsType, EventNameExtractor.MatchIngNames); + + if (found.Length == 1) continue; + + if (found.Length == 0) + { + Console.WriteLine($"{typeof(ContentService).Name} {e.Name} {TypeName(eventArgsType)} NotFound"); + continue; + } + + Console.WriteLine($"{typeof(ContentService).Name} {e.Name} {TypeName(eventArgsType)} Ambiguous"); + Console.WriteLine("\t" + string.Join(", ", found)); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/ContentServiceEventTests.cs b/src/Umbraco.Tests/Services/ContentServiceEventTests.cs new file mode 100644 index 0000000000..3576425b9c --- /dev/null +++ b/src/Umbraco.Tests/Services/ContentServiceEventTests.cs @@ -0,0 +1,224 @@ +using System.Linq; +using NUnit.Framework; +using Umbraco.Core.Events; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Services +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] + public class ContentServiceEventTests : TestWithSomeContentBase + { + public override void SetUp() + { + base.SetUp(); + ContentRepositoryBase.ThrowOnWarning = true; + } + + public override void TearDown() + { + ContentRepositoryBase.ThrowOnWarning = false; + base.TearDown(); + } + + [Test] + public void SavingTest() + { + var languageService = ServiceContext.LocalizationService; + + languageService.Save(new Language("fr-FR")); + + var contentTypeService = ServiceContext.ContentTypeService; + + var contentType = MockedContentTypes.CreateTextPageContentType(); + ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); + contentType.Variations = ContentVariation.Culture; + foreach (var propertyType in contentType.PropertyTypes) + propertyType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + var contentService = ServiceContext.ContentService; + + var document = new Content("content", -1, contentType); + document.SetCultureName("hello", "en-US"); + document.SetCultureName("bonjour", "fr-FR"); + contentService.Save(document); + + // properties: title, bodyText, keywords, description + document.SetValue("title", "title-en", "en-US"); + + // touch the culture - required for IsSaving/HasSaved to work + document.TouchCulture("fr-FR"); + + void OnSaving(IContentService sender, SaveEventArgs e) + { + var saved = e.SavedEntities.First(); + + Assert.AreSame(document, saved); + + Assert.IsTrue(saved.IsSavingCulture("fr-FR")); + Assert.IsFalse(saved.IsSavingCulture("en-UK")); + } + + void OnSaved(IContentService sender, SaveEventArgs e) + { + var saved = e.SavedEntities.First(); + + Assert.AreSame(document, saved); + + Assert.IsTrue(saved.HasSavedCulture("fr-FR")); + Assert.IsFalse(saved.HasSavedCulture("en-UK")); + } + + ContentService.Saving += OnSaving; + ContentService.Saved += OnSaved; + contentService.Save(document); + ContentService.Saving -= OnSaving; + ContentService.Saved -= OnSaved; + } + + [Test] + public void PublishingTest() + { + var languageService = ServiceContext.LocalizationService; + + languageService.Save(new Language("fr-FR")); + + var contentTypeService = ServiceContext.ContentTypeService; + + var contentType = MockedContentTypes.CreateTextPageContentType(); + ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); + contentType.Variations = ContentVariation.Culture; + foreach (var propertyType in contentType.PropertyTypes) + propertyType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + var contentService = ServiceContext.ContentService; + + var document = new Content("content", -1, contentType); + document.SetCultureName("hello", "en-US"); + document.SetCultureName("bonjour", "fr-FR"); + contentService.Save(document); + + // ensure it works and does not throw + Assert.IsFalse(document.WasCulturePublished("fr-FR")); + Assert.IsFalse(document.WasCulturePublished("en-US")); + Assert.IsFalse(document.IsCulturePublished("fr-FR")); + Assert.IsFalse(document.IsCulturePublished("en-US")); + + void OnPublishing(IContentService sender, PublishEventArgs e) + { + var publishing = e.PublishedEntities.First(); + + Assert.AreSame(document, publishing); + + Assert.IsFalse(publishing.IsPublishingCulture("en-US")); + Assert.IsTrue(publishing.IsPublishingCulture("fr-FR")); + } + + void OnPublished(IContentService sender, PublishEventArgs e) + { + var published = e.PublishedEntities.First(); + + Assert.AreSame(document, published); + + Assert.IsFalse(published.HasPublishedCulture("en-US")); + Assert.IsTrue(published.HasPublishedCulture("fr-FR")); + } + + ContentService.Publishing += OnPublishing; + ContentService.Published += OnPublished; + contentService.SaveAndPublish(document, "fr-FR"); + ContentService.Publishing -= OnPublishing; + ContentService.Published -= OnPublished; + + document = (Content) contentService.GetById(document.Id); + + // ensure it works and does not throw + Assert.IsTrue(document.WasCulturePublished("fr-FR")); + Assert.IsFalse(document.WasCulturePublished("en-US")); + Assert.IsTrue(document.IsCulturePublished("fr-FR")); + Assert.IsFalse(document.IsCulturePublished("en-US")); + } + + [Test] + public void UnpublishingTest() + { + var languageService = ServiceContext.LocalizationService; + + languageService.Save(new Language("fr-FR")); + + var contentTypeService = ServiceContext.ContentTypeService; + + var contentType = MockedContentTypes.CreateTextPageContentType(); + ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); + contentType.Variations = ContentVariation.Culture; + foreach (var propertyType in contentType.PropertyTypes) + propertyType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + var contentService = ServiceContext.ContentService; + + var document = new Content("content", -1, contentType); + document.SetCultureName("hello", "en-US"); + document.SetCultureName("bonjour", "fr-FR"); + contentService.SaveAndPublish(document); + + // ensure it works and does not throw + Assert.IsTrue(document.WasCulturePublished("fr-FR")); + Assert.IsTrue(document.WasCulturePublished("en-US")); + Assert.IsTrue(document.IsCulturePublished("fr-FR")); + Assert.IsTrue(document.IsCulturePublished("en-US")); + + void OnPublishing(IContentService sender, PublishEventArgs e) + { + var publishing = e.PublishedEntities.First(); + + Assert.AreSame(document, publishing); + + Assert.IsFalse(publishing.IsPublishingCulture("en-US")); + Assert.IsFalse(publishing.IsPublishingCulture("fr-FR")); + + Assert.IsFalse(publishing.IsUnpublishingCulture("en-US")); + Assert.IsTrue(publishing.IsUnpublishingCulture("fr-FR")); + } + + void OnPublished(IContentService sender, PublishEventArgs e) + { + var published = e.PublishedEntities.First(); + + Assert.AreSame(document, published); + + Assert.IsFalse(published.HasPublishedCulture("en-US")); + Assert.IsFalse(published.HasPublishedCulture("fr-FR")); + + Assert.IsFalse(published.HasUnpublishedCulture("en-US")); + Assert.IsTrue(published.HasUnpublishedCulture("fr-FR")); + } + + document.UnpublishCulture("fr-FR"); + + ContentService.Publishing += OnPublishing; + ContentService.Published += OnPublished; + contentService.SavePublishing(document); + ContentService.Publishing -= OnPublishing; + ContentService.Published -= OnPublished; + + document = (Content) contentService.GetById(document.Id); + + // ensure it works and does not throw + Assert.IsFalse(document.WasCulturePublished("fr-FR")); + Assert.IsTrue(document.WasCulturePublished("en-US")); + Assert.IsFalse(document.IsCulturePublished("fr-FR")); + Assert.IsTrue(document.IsCulturePublished("en-US")); + } + } +} diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 37d34557bb..e339d8d1b6 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -6,7 +6,6 @@ using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -14,14 +13,11 @@ using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Core.Events; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories.Implement; -using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services.Implement; using Umbraco.Tests.Testing; -using System.Reflection; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; namespace Umbraco.Tests.Services { @@ -60,32 +56,6 @@ namespace Umbraco.Tests.Services Composition.RegisterUnique(factory => Mock.Of()); } - /// - /// Used to list out all ambiguous events that will require dispatching with a name - /// - [Test, Explicit] - public void List_Ambiguous_Events() - { - var events = ServiceContext.ContentService.GetType().GetEvents(BindingFlags.Static | BindingFlags.Public); - var typedEventHandler = typeof(TypedEventHandler<,>); - foreach(var e in events) - { - //only continue if this is a TypedEventHandler - if (!e.EventHandlerType.IsGenericType) continue; - var typeDef = e.EventHandlerType.GetGenericTypeDefinition(); - if (typedEventHandler != typeDef) continue; - - //get the event arg type - var eventArgType = e.EventHandlerType.GenericTypeArguments[1]; - - var found = EventNameExtractor.FindEvent(typeof(ContentService), eventArgType, EventNameExtractor.MatchIngNames); - if (!found.Success && found.Result.Error == EventNameExtractorError.Ambiguous) - { - Console.WriteLine($"Ambiguous event, source: {typeof(ContentService)}, args: {eventArgType}"); - } - } - } - [Test] public void Create_Blueprint() { @@ -818,7 +788,7 @@ namespace Umbraco.Tests.Services content.PublishCulture(langGB.IsoCode); content.PublishCulture(langFr.IsoCode); Assert.IsTrue(ServiceContext.ContentService.SavePublishing(content).Success); - + //re-get content = ServiceContext.ContentService.GetById(content.Id); Assert.AreEqual(PublishedState.Published, content.PublishedState); diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 7a9702031b..46af5d9e71 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -153,7 +153,7 @@ namespace Umbraco.Tests.TestHelpers var localizationService = GetLazyService(factory, c => new LocalizationService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c))); var userService = GetLazyService(factory, c => new UserService(scopeProvider, logger, eventMessagesFactory, runtimeState, GetRepo(c), GetRepo(c),globalSettings)); var dataTypeService = GetLazyService(factory, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); - var contentService = GetLazyService(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, mediaFileSystem, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); + var contentService = GetLazyService(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); var notificationService = GetLazyService(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, GetRepo(c), globalSettings, umbracoSettings.Content)); var serverRegistrationService = GetLazyService(factory, c => new ServerRegistrationService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var memberGroupService = GetLazyService(factory, c => new MemberGroupService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); @@ -176,7 +176,7 @@ namespace Umbraco.Tests.TestHelpers var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); var compiledPackageXmlParser = new CompiledPackageXmlParser(new ConflictingPackageData(macroService.Value, fileService.Value)); return new PackagingService( - auditService.Value, + auditService.Value, new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "createdPackages.config"), new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, @@ -188,7 +188,7 @@ namespace Umbraco.Tests.TestHelpers new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); - var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); + var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var redirectUrlService = GetLazyService(factory, c => new RedirectUrlService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var consentService = GetLazyService(factory, c => new ConsentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 986dad12fd..1703743c6f 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -141,6 +141,8 @@ + + From 6bf3b19d8624f2ea991eacf632ee0edd31f1daa7 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 31 Jan 2019 15:09:57 +0100 Subject: [PATCH 048/555] #4068 - Fix for ordering of grid --- .../propertyeditors/grid/grid.controller.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js index be92128280..f7e69a2683 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js @@ -60,8 +60,8 @@ angular.module("umbraco") start: function (e, ui) { // Fade out row when sorting - ui.item.context.style.display = "block"; - ui.item.context.style.opacity = "0.5"; + ui.item[0].style.display = "block"; + ui.item[0].style.opacity = "0.5"; draggedRteSettings = {}; ui.item.find(".mceNoEditor").each(function () { @@ -75,7 +75,7 @@ angular.module("umbraco") stop: function (e, ui) { // Fade in row when sorting stops - ui.item.context.style.opacity = "1"; + ui.item[0].style.opacity = "1"; // reset all RTEs affected by the dragging ui.item.parents(".umb-column").find(".mceNoEditor").each(function () { @@ -185,12 +185,12 @@ angular.module("umbraco") startingArea = area; // fade out control when sorting - ui.item.context.style.display = "block"; - ui.item.context.style.opacity = "0.5"; + ui.item[0].style.display = "block"; + ui.item[0].style.opacity = "0.5"; // reset dragged RTE settings in case a RTE isn't dragged draggedRteSettings = undefined; - ui.item.context.style.display = "block"; + ui.item[0].style.display = "block"; ui.item.find(".mceNoEditor").each(function () { notIncludedRte = []; var editors = _.findWhere(tinyMCE.editors, { id: $(this).attr("id") }); @@ -210,7 +210,7 @@ angular.module("umbraco") stop: function (e, ui) { // Fade in control when sorting stops - ui.item.context.style.opacity = "1"; + ui.item[0].style.opacity = "1"; ui.item.offsetParent().find(".mceNoEditor").each(function () { if ($.inArray($(this).attr("id"), notIncludedRte) < 0) { @@ -400,7 +400,7 @@ angular.module("umbraco") } $scope.editGridItemSettings = function (gridItem, itemType) { - + placeHolder = "{0}"; var styles, config; @@ -658,7 +658,7 @@ angular.module("umbraco") // ********************************************* $scope.initContent = function () { var clear = true; - + //settings indicator shortcut if (($scope.model.config.items.config && $scope.model.config.items.config.length > 0) || ($scope.model.config.items.styles && $scope.model.config.items.styles.length > 0)) { $scope.hasSettings = true; @@ -755,7 +755,7 @@ angular.module("umbraco") // Init layout / row // ********************************************* $scope.initRow = function (row) { - + //merge the layout data with the original config data //if there are no config info on this, splice it out var original = _.find($scope.model.config.items.layouts, function (o) { return o.name === row.name; }); From 4a480ab3918be8f0bce3c57027bd2ce750a361ba Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 31 Jan 2019 15:10:19 +0100 Subject: [PATCH 049/555] #4068 - Added interceptor to remove `$` variables from post data --- .../src/common/interceptors/_module.js | 1 + ...tpostdollarvariablesrequest.interceptor.js | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js diff --git a/src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js b/src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js index 765f44a636..05263cebf2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js +++ b/src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js @@ -6,4 +6,5 @@ angular.module('umbraco.interceptors', []) $httpProvider.interceptors.push('securityInterceptor'); $httpProvider.interceptors.push('debugRequestInterceptor'); + $httpProvider.interceptors.push('doNotPostDollarVariablesOnPostRequestInterceptor'); }]); diff --git a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js new file mode 100644 index 0000000000..0a5f6d837d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js @@ -0,0 +1,38 @@ +(function() { + 'use strict'; + + function removeProperty(obj, propertyPrefix) { + for (var property in obj) { + if (obj.hasOwnProperty(property)) { + + if (property.startsWith(propertyPrefix) && obj[property]) { + obj[property] = undefined; + } + + if (typeof obj[property] == "object") { + removeProperty(obj[property], propertyPrefix); + } + } + } + + } + + function transform(data){ + removeProperty(data, "$"); + } + + function doNotPostDollarVariablesRequestInterceptor($q, urlHelper) { + return { + //dealing with requests: + 'request': function(config) { + if(config.method === "POST"){ + config.transformRequest.push(transform); + } + + return config; + } + }; + } + + angular.module('umbraco.interceptors').factory('doNotPostDollarVariablesOnPostRequestInterceptor', doNotPostDollarVariablesRequestInterceptor); +})(); From eeaf8d594ddc569faa5c73df4c4db700102e0943 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 31 Jan 2019 19:43:57 +0100 Subject: [PATCH 050/555] Make NC resilient towards culture variance in elements --- .../PropertyEditors/NestedContentPropertyEditor.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs index 7ff6439e08..6dee2f78b5 100644 --- a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs @@ -172,18 +172,16 @@ namespace Umbraco.Web.PropertyEditors try { // create a temp property with the value + // - force it to be culture invariant as NC can't handle culture variant element properties + propType.Variations = ContentVariation.Nothing; var tempProp = new Property(propType); - // if the property varies by culture, make sure we save using the current culture - var propCulture = propType.VariesByCulture() || propType.VariesByCultureAndSegment() - ? culture - : null; - tempProp.SetValue(propValues[propAlias] == null ? null : propValues[propAlias].ToString(), propCulture); + tempProp.SetValue(propValues[propAlias] == null ? null : propValues[propAlias].ToString()); // convert that temp property, and store the converted value var propEditor = _propertyEditors[propType.PropertyEditorAlias]; var tempConfig = dataTypeService.GetDataType(propType.DataTypeId).Configuration; var valEditor = propEditor.GetValueEditor(tempConfig); - var convValue = valEditor.ToEditor(tempProp, dataTypeService, propCulture); + var convValue = valEditor.ToEditor(tempProp, dataTypeService); propValues[propAlias] = convValue == null ? null : JToken.FromObject(convValue); } catch (InvalidOperationException) From f74a49f5a3e1bbf411fa32128526eaa385eae991 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 10:18:53 +1100 Subject: [PATCH 051/555] Gets the macros being able to be updated, now to fix the Classic mode, since this now only works in distraction free mode --- .../src/common/services/tinymce.service.js | 36 +++++++++++-------- src/Umbraco.Web/Routing/PublishedRequest.cs | 1 - 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 90cb793a91..39d69158c9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -458,7 +458,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s */ createInsertMacro: function (editor, callback) { - var createInsertMacroScope = this; + let self = this; + let activeMacroElement = null; //track an active macro element /** Adds custom rules for the macro plugin and custom serialization */ editor.on('preInit', function (args) { @@ -481,7 +482,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s //get all macro divs and load their content $(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () { - createInsertMacroScope.loadMacroContent($(this), null); + self.loadMacroContent($(this), null); }); }); @@ -511,18 +512,18 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s tooltip: 'Insert macro', onPostRender: function () { - var ctrl = this; - + let ctrl = this; + /** * Check if the macro is currently selected and toggle the menu button */ function onNodeChanged(evt) { //set our macro button active when on a node of class umb-macro-holder - var $macroElement = $(evt.element).closest(".umb-macro-holder"); + activeMacroElement = getRealMacroElem(evt.element); //set the button active/inactive - ctrl.active($macroElement.length !== 0); + ctrl.active(activeMacroElement !== null); } //NOTE: This could be another way to deal with the active/inactive state @@ -543,11 +544,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s //when we click we could have a macro already selected and in that case we'll want to edit the current parameters //so we'll need to extract them and submit them to the dialog. - var macroElement = editor.selection.getNode(); - macroElement = getRealMacroElem(macroElement); - if (macroElement) { + if (activeMacroElement) { //we have a macro selected so we'll need to parse it's alias and parameters - var contents = $(macroElement).contents(); + var contents = $(activeMacroElement).contents(); var comment = _.find(contents, function (item) { return item.nodeType === 8; }); @@ -557,7 +556,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s var syntax = comment.textContent.trim(); var parsed = macroService.parseMacroSyntax(syntax); dialogData = { - macroData: parsed + macroData: parsed, + activeMacroElement: activeMacroElement //pass the active element along so we can retrieve it later }; } @@ -570,7 +570,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s }); }, - insertMacroInEditor: function (editor, macroObject) { + insertMacroInEditor: function (editor, macroObject, activeMacroElement) { //Important note: the TinyMce plugin "noneditable" is used here so that the macro cannot be edited, // for this to work the mceNonEditable class needs to come last and we also need to use the attribute contenteditable = false @@ -588,7 +588,13 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s }, macroSyntaxComment + 'Macro alias: ' + macroObject.macroAlias + ''); - editor.selection.setNode(macroDiv); + //if there's an activeMacroElement then replace it, otherwise set the contents of the selected node + if (activeMacroElement) { + activeMacroElement.replaceWith(macroDiv); //directly replaces the html node + } + else { + editor.selection.setNode(macroDiv); + } var $macroDiv = $(editor.dom.select("div.umb-macro-holder." + uniqueId)); @@ -1126,7 +1132,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s } }); - var self = this; + let self = this; //create link picker self.createLinkPicker(args.editor, function (currentTarget, anchorElement) { @@ -1184,7 +1190,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s dialogData: dialogData, submit: function (model) { var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, dialogData.renderingEngine); - self.insertMacroInEditor(args.editor, macroObject); + self.insertMacroInEditor(args.editor, macroObject, dialogData.activeMacroElement); editorService.close(); }, close: function () { diff --git a/src/Umbraco.Web/Routing/PublishedRequest.cs b/src/Umbraco.Web/Routing/PublishedRequest.cs index c5475f8b73..a2ff71e634 100644 --- a/src/Umbraco.Web/Routing/PublishedRequest.cs +++ b/src/Umbraco.Web/Routing/PublishedRequest.cs @@ -279,7 +279,6 @@ namespace Umbraco.Web.Routing /// /// Resets the template. /// - /// The RenderingEngine becomes unknown. public void ResetTemplate() { EnsureWriteable(); From dae8dfdc59cbf3dd423208851ef0769a2a0de991 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 11:34:28 +1100 Subject: [PATCH 052/555] fix merge --- src/Umbraco.Web/Templates/TemplateRenderer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index dc8ca0b16d..df711a084e 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -26,12 +26,12 @@ namespace Umbraco.Web.Templates internal class TemplateRenderer : ITemplateRenderer { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly PublishedRouter _publishedRouter; + private readonly IPublishedRouter _publishedRouter; private readonly IFileService _fileService; private readonly ILocalizationService _languageService; private readonly IWebRoutingSection _webRoutingSection; - public TemplateRenderer(IUmbracoContextAccessor umbracoContextAccessor, PublishedRouter publishedRouter, IFileService fileService, ILocalizationService textService, IWebRoutingSection webRoutingSection) + public TemplateRenderer(IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, IFileService fileService, ILocalizationService textService, IWebRoutingSection webRoutingSection) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter)); From 3eb6cd9e217b51e50396f45031260b4caa93d7c7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 13:50:39 +1100 Subject: [PATCH 053/555] Macros are now working inline in the rte with both the Classic and Distraction free modes --- .../src/common/services/tinymce.service.js | 6 +++++- src/Umbraco.Web.UI.Client/src/less/rte.less | 16 ---------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 39d69158c9..a0fbbc19d6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -232,7 +232,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s body_class: 'umb-rte', //see http://archive.tinymce.com/wiki.php/Configuration:cache_suffix - cache_suffix: "?umb__rnd=" + Umbraco.Sys.ServerVariables.application.cacheBuster + cache_suffix: "?umb__rnd=" + Umbraco.Sys.ServerVariables.application.cacheBuster, + + //this is used to style the inline macro bits, sorry hard coding this form now since we don't have a standalone + //stylesheet to load in for this with only these styles (the color is @pinkLight) + content_style: ".mce-content-body .umb-macro-holder { border: 3px dotted #f5c1bc; padding: 7px; display: block; margin: 3px; } .umb-rte .mce-content-body .umb-macro-holder.loading {background: url(assets/img/loader.gif) right no-repeat; background-size: 18px; background-position-x: 99%;}" }; if (tinyMceConfig.customConfig) { diff --git a/src/Umbraco.Web.UI.Client/src/less/rte.less b/src/Umbraco.Web.UI.Client/src/less/rte.less index d9888eb9d3..ba8d02c1e1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/rte.less +++ b/src/Umbraco.Web.UI.Client/src/less/rte.less @@ -25,22 +25,6 @@ padding:10px; } -/* loader for macro loading in tinymce*/ -.mce-content-body .umb-macro-holder { - border: 3px dotted @pinkLight; - padding: 7px; - display: block; - margin: 3px; -} -.umb-rte .mce-content-body .umb-macro-holder.loading { - - /*fixme: this image doesn't exist*/ - - background: url(img/loader.gif) right no-repeat; - background-size: 18px; - background-position-x: 99%; -} - .umb-rte .mce-container { box-sizing: border-box; } From d7d82ea98d41206bbe157598cab6ba5709958df0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 14:02:45 +1100 Subject: [PATCH 054/555] Allows grid rte to be distraction-free, the parameter was not being passed but it can be configured --- .../common/directives/components/grid/grid.rte.directive.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js index 0a8846f975..6472dd3d38 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js @@ -30,7 +30,8 @@ angular.module("umbraco.directives") promises.push(tinyMceService.getTinyMceEditorConfig({ htmlId: scope.uniqueId, stylesheets: scope.configuration ? scope.configuration.stylesheets : null, - toolbar: toolbar + toolbar: toolbar, + mode: scope.configuration.mode })); // pin toolbar to top of screen if we have focus and it scrolls off the screen From c2ff32aaab2e36204f5b464d80f655cd062142be Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 15:24:07 +1100 Subject: [PATCH 055/555] Fixing tests, don't expose UmbracoContext on UmbracoHelper, fixing all of the editor constructors --- .../TestControllerActivator.cs | 8 +- .../TestControllerActivatorBase.cs | 4 +- .../ControllerTesting/TestRunner.cs | 4 +- .../ControllerTesting/TestStartup.cs | 4 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 17 +++ .../Web/Controllers/ContentControllerTests.cs | 114 ++++++++++++++---- .../Web/Controllers/UsersControllerTests.cs | 46 +++++-- .../BackOfficeNotificationsController.cs | 14 ++- src/Umbraco.Web/Editors/CodeFileController.cs | 7 ++ src/Umbraco.Web/Editors/ContentController.cs | 5 +- .../Editors/ContentControllerBase.cs | 7 ++ src/Umbraco.Web/Editors/DataTypeController.cs | 5 +- .../Editors/DictionaryController.cs | 10 ++ src/Umbraco.Web/Editors/MacrosController.cs | 7 +- src/Umbraco.Web/Editors/MediaController.cs | 4 +- src/Umbraco.Web/Editors/MemberController.cs | 5 +- .../RedirectUrlManagementController.cs | 4 +- .../Editors/RelationTypeController.cs | 9 ++ src/Umbraco.Web/Editors/TemplateController.cs | 10 ++ src/Umbraco.Web/Editors/UsersController.cs | 6 + src/Umbraco.Web/Search/UmbracoTreeSearcher.cs | 11 +- src/Umbraco.Web/UmbracoHelper.cs | 17 +-- 22 files changed, 245 insertions(+), 73 deletions(-) diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs index 73762d4e91..2f7e50ea1e 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs @@ -7,16 +7,16 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting { public class TestControllerActivator : TestControllerActivatorBase { - private readonly Func _factory; + private readonly Func _factory; - public TestControllerActivator(Func factory) + public TestControllerActivator(Func factory) { _factory = factory; } - protected override ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoHelper helper) + protected override ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoContext umbracoContext, UmbracoHelper helper) { - return _factory(msg, helper); + return _factory(msg, umbracoContext, helper); } } } diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index f576c66291..4e352488be 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -159,9 +159,9 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting Mock.Of(), membershipHelper); - return CreateController(controllerType, request, umbHelper); + return CreateController(controllerType, request, umbCtx, umbHelper); } - protected abstract ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoHelper helper); + protected abstract ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoContext umbracoContext, UmbracoHelper helper); } } diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs index 5834415568..86d8cbdd5e 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs @@ -15,9 +15,9 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting { public class TestRunner { - private readonly Func _controllerFactory; + private readonly Func _controllerFactory; - public TestRunner(Func controllerFactory) + public TestRunner(Func controllerFactory) { _controllerFactory = controllerFactory; } diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs index 95b5a3bfeb..6143432faf 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs @@ -16,10 +16,10 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting /// public class TestStartup { - private readonly Func _controllerFactory; + private readonly Func _controllerFactory; private readonly Action _initialize; - public TestStartup(Action initialize, Func controllerFactory) + public TestStartup(Action initialize, Func controllerFactory) { _controllerFactory = controllerFactory; _initialize = initialize; diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 7c8d1100f8..4294faf4f8 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -38,9 +38,11 @@ using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Actions; using Umbraco.Web.Composing.Composers; using Umbraco.Web.ContentApps; +using Umbraco.Web.Macros; using Umbraco.Web.PublishedCache; using Current = Umbraco.Core.Composing.Current; using Umbraco.Web.Routing; +using Umbraco.Web.Templates; using Umbraco.Web.Trees; namespace Umbraco.Tests.Testing @@ -228,6 +230,21 @@ namespace Umbraco.Tests.Testing .Append() .Append(); Composition.RegisterUnique(); + + //TODO: A lot of this is just copied from the WebRuntimeComposer, maybe we should just compose it all? + Composition.Register(factory => + { + var umbCtx = factory.GetInstance(); + return new PublishedContentQuery(umbCtx.UmbracoContext.ContentCache, umbCtx.UmbracoContext.MediaCache, factory.GetInstance()); + }, Lifetime.Request); + Composition.Register(Lifetime.Request); + + Composition.RegisterUnique(); + Composition.RegisterUnique(); + Composition.RegisterUnique(); + + // register the umbraco helper - this is Transient! very important! + Composition.Register(); } protected virtual void ComposeWtf() diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs index cf0bf689a1..7afb41c983 100644 --- a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs @@ -30,6 +30,11 @@ using System; using Umbraco.Web.WebApi; using Umbraco.Web.Trees; using System.Globalization; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; using Umbraco.Web.Actions; namespace Umbraco.Tests.Web.Controllers @@ -206,17 +211,28 @@ namespace Umbraco.Tests.Web.Controllers [Test] public async Task PostSave_Validate_Existing_Content() { - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null); //do not find it var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(propertyEditorCollection); - return usersController; + + var controller = new ContentController( + propertyEditorCollection, + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); + + return controller; } - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, content: GetMultiPartRequestContent(PublishJsonInvariant), mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), @@ -232,21 +248,31 @@ namespace Umbraco.Tests.Web.Controllers [Test] public async Task PostSave_Validate_At_Least_One_Variant_Flagged_For_Saving() { - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent()); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(propertyEditorCollection); - return usersController; + var controller = new ContentController( + propertyEditorCollection, + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); + + return controller; } var json = JsonConvert.DeserializeObject(PublishJsonInvariant); //remove all save flaggs ((JArray)json["variants"])[0]["save"] = false; - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)), mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), @@ -263,14 +289,24 @@ namespace Umbraco.Tests.Web.Controllers [Test] public async Task PostSave_Validate_Properties_Exist() { - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent()); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(propertyEditorCollection); - return usersController; + var controller = new ContentController( + propertyEditorCollection, + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); + + return controller; } var json = JsonConvert.DeserializeObject(PublishJsonInvariant); @@ -283,7 +319,7 @@ namespace Umbraco.Tests.Web.Controllers value = "hello" })); - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)), mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), @@ -297,7 +333,7 @@ namespace Umbraco.Tests.Web.Controllers { var content = GetMockedContent(); - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { var contentServiceMock = Mock.Get(Current.Services.ContentService); @@ -306,11 +342,21 @@ namespace Umbraco.Tests.Web.Controllers .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(propertyEditorCollection); - return usersController; + var controller = new ContentController( + propertyEditorCollection, + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); + + return controller; } - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, content: GetMultiPartRequestContent(PublishJsonInvariant), mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), @@ -328,7 +374,7 @@ namespace Umbraco.Tests.Web.Controllers { var content = GetMockedContent(); - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { var contentServiceMock = Mock.Get(Current.Services.ContentService); @@ -337,15 +383,25 @@ namespace Umbraco.Tests.Web.Controllers .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(propertyEditorCollection); - return usersController; + var controller = new ContentController( + propertyEditorCollection, + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); + + return controller; } //clear out the name var json = JsonConvert.DeserializeObject(PublishJsonInvariant); json["variants"].ElementAt(0)["name"] = null; - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)), mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), @@ -363,7 +419,7 @@ namespace Umbraco.Tests.Web.Controllers { var content = GetMockedContent(); - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { var contentServiceMock = Mock.Get(Current.Services.ContentService); @@ -372,15 +428,25 @@ namespace Umbraco.Tests.Web.Controllers .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(propertyEditorCollection); - return usersController; + var controller = new ContentController( + propertyEditorCollection, + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); + + return controller; } //clear out one of the names var json = JsonConvert.DeserializeObject(PublishJsonVariant); json["variants"].ElementAt(0)["name"] = null; - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)), mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs index 857e922ac9..3905e62037 100644 --- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs @@ -7,9 +7,13 @@ using Moq; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Querying; @@ -49,7 +53,7 @@ namespace Umbraco.Tests.Web.Controllers [Test] public async System.Threading.Tasks.Task Save_User() { - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { //setup some mocks Umbraco.Core.Configuration.GlobalSettings.HasSmtpServer = true; @@ -68,7 +72,15 @@ namespace Umbraco.Tests.Web.Controllers userServiceMock.Setup(service => service.GetUserById(It.IsAny())) .Returns((int id) => id == 1234 ? new User(1234, "Test", "test@test.com", "test@test.com", "", new List(), new int[0], new int[0]) : null); - var usersController = new UsersController(); + var usersController = new UsersController( + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); return usersController; } @@ -82,7 +94,7 @@ namespace Umbraco.Tests.Web.Controllers UserGroups = new[] { "writers" } }; - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Users", "PostSaveUser", HttpMethod.Post, new ObjectContent(userSave, new JsonMediaTypeFormatter())); var obj = JsonConvert.DeserializeObject(response.Item2); @@ -122,15 +134,23 @@ namespace Umbraco.Tests.Web.Controllers [Test] public async System.Threading.Tasks.Task GetPagedUsers_Empty() { - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { - var usersController = new UsersController(); + var usersController = new UsersController( + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); return usersController; } MockForGetPagedUsers(); - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get); var obj = JsonConvert.DeserializeObject>(response.Item2); @@ -140,7 +160,7 @@ namespace Umbraco.Tests.Web.Controllers [Test] public async System.Threading.Tasks.Task GetPagedUsers_10() { - ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { //setup some mocks var userServiceMock = Mock.Get(Current.Services.UserService); @@ -151,13 +171,21 @@ namespace Umbraco.Tests.Web.Controllers It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())) .Returns(() => users); - var usersController = new UsersController(); + var usersController = new UsersController( + Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + helper); return usersController; } MockForGetPagedUsers(); - var runner = new TestRunner(Factory); + var runner = new TestRunner(CtrlFactory); var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get); var obj = JsonConvert.DeserializeObject>(response.Item2); diff --git a/src/Umbraco.Web/Editors/BackOfficeNotificationsController.cs b/src/Umbraco.Web/Editors/BackOfficeNotificationsController.cs index 66e7a4734a..d83c5c8fb6 100644 --- a/src/Umbraco.Web/Editors/BackOfficeNotificationsController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeNotificationsController.cs @@ -1,4 +1,10 @@ -using Umbraco.Web.WebApi; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; +using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors @@ -11,5 +17,9 @@ namespace Umbraco.Web.Editors [AppendCurrentEventMessages] [PrefixlessBodyModelValidator] public abstract class BackOfficeNotificationsController : UmbracoAuthorizedJsonController - { } + { + protected BackOfficeNotificationsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } + } } diff --git a/src/Umbraco.Web/Editors/CodeFileController.cs b/src/Umbraco.Web/Editors/CodeFileController.cs index 719f7521cb..4a29530068 100644 --- a/src/Umbraco.Web/Editors/CodeFileController.cs +++ b/src/Umbraco.Web/Editors/CodeFileController.cs @@ -8,8 +8,12 @@ using System.Net.Http; using System.Web.Http; using ClientDependency.Core; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Strings.Css; using Umbraco.Web.Composing; @@ -30,6 +34,9 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)] public class CodeFileController : BackOfficeNotificationsController { + public CodeFileController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } /// /// Used to create a brand new file diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 6cded2a253..ad261f0d04 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -11,6 +11,8 @@ using System.Web.Http.ModelBinding; using System.Web.Security; using AutoMapper; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -33,6 +35,7 @@ using Umbraco.Web.ContentApps; using Umbraco.Web.Editors.Binders; using Umbraco.Web.Editors.Filters; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Persistence; using Umbraco.Core.Security; namespace Umbraco.Web.Editors @@ -54,7 +57,7 @@ namespace Umbraco.Web.Editors public object Domains { get; private set; } - public ContentController(PropertyEditorCollection propertyEditors) + public ContentController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); _allLangs = new Lazy>(() => Services.LocalizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase)); diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs index d7c4d4f7f7..2a4d38d6f4 100644 --- a/src/Umbraco.Web/Editors/ContentControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs @@ -4,9 +4,12 @@ using System.Net; using System.Net.Http; using System.Web.Http; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; +using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.Composing; @@ -23,6 +26,10 @@ namespace Umbraco.Web.Editors [JsonDateTimeFormatAttribute] public abstract class ContentControllerBase : BackOfficeNotificationsController { + protected ContentControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } + protected HttpResponseMessage HandleContentNotFound(object id, bool throwException = true) { ModelState.AddModelError("id", $"content with id: {id} was not found"); diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs index 4446373cd3..117bc33cc4 100644 --- a/src/Umbraco.Web/Editors/DataTypeController.cs +++ b/src/Umbraco.Web/Editors/DataTypeController.cs @@ -16,8 +16,11 @@ using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; using System.Net.Http; using System.Text; +using Umbraco.Core.Cache; using Umbraco.Web.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; namespace Umbraco.Web.Editors { @@ -36,7 +39,7 @@ namespace Umbraco.Web.Editors { private readonly PropertyEditorCollection _propertyEditors; - public DataTypeController(PropertyEditorCollection propertyEditors) + public DataTypeController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _propertyEditors = propertyEditors; } diff --git a/src/Umbraco.Web/Editors/DictionaryController.cs b/src/Umbraco.Web/Editors/DictionaryController.cs index 484dd47a4e..186b3ac4a4 100644 --- a/src/Umbraco.Web/Editors/DictionaryController.cs +++ b/src/Umbraco.Web/Editors/DictionaryController.cs @@ -5,7 +5,13 @@ using System.Net; using System.Net.Http; using System.Web.Http; using AutoMapper; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; @@ -28,6 +34,10 @@ namespace Umbraco.Web.Editors [EnableOverrideAuthorization] public class DictionaryController : BackOfficeNotificationsController { + public DictionaryController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } + /// /// Deletes a data type with a given ID /// diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 7fbcdbf98a..38ec0ffc1b 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -7,9 +7,12 @@ using System.Net; using System.Net.Http; using System.Web.Http; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; using Umbraco.Web.Composing; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; @@ -29,9 +32,9 @@ namespace Umbraco.Web.Editors { private readonly IMacroService _macroService; - public MacrosController(IMacroService macroService) + public MacrosController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { - _macroService = macroService; + _macroService = Services.MacroService; } /// diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 7a787d8848..24b230df13 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -21,7 +21,9 @@ using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using System.Linq; using System.Web.Http.Controllers; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; using Umbraco.Core.Persistence.Querying; @@ -47,7 +49,7 @@ namespace Umbraco.Web.Editors [MediaControllerControllerConfiguration] public class MediaController : ContentControllerBase { - public MediaController(PropertyEditorCollection propertyEditors) + public MediaController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); } diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index f4a8dfbd56..af4061f5cd 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -26,7 +26,10 @@ using Umbraco.Web.Mvc; using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; using System.Collections.Generic; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.Models.ContentEditing; +using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Web.ContentApps; using Umbraco.Web.Editors.Binders; @@ -43,7 +46,7 @@ namespace Umbraco.Web.Editors [OutgoingNoHyphenGuidFormat] public class MemberController : ContentControllerBase { - public MemberController(PropertyEditorCollection propertyEditors) + public MemberController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); } diff --git a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs index aa2626ca3b..04a19ec437 100644 --- a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs @@ -35,7 +35,7 @@ namespace Umbraco.Web.Editors public IHttpActionResult GetEnableState() { var enabled = Current.Configs.Settings().WebRouting.DisableRedirectUrlTracking == false; - var userIsAdmin = Umbraco.UmbracoContext.Security.CurrentUser.IsAdmin(); + var userIsAdmin = UmbracoContext.Security.CurrentUser.IsAdmin(); return Ok(new { enabled, userIsAdmin }); } @@ -92,7 +92,7 @@ namespace Umbraco.Web.Editors [HttpPost] public IHttpActionResult ToggleUrlTracker(bool disable) { - var userIsAdmin = Umbraco.UmbracoContext.Security.CurrentUser.IsAdmin(); + var userIsAdmin = UmbracoContext.Security.CurrentUser.IsAdmin(); if (userIsAdmin == false) { var errorMessage = "User is not a member of the administrators group and so is not allowed to toggle the URL tracker"; diff --git a/src/Umbraco.Web/Editors/RelationTypeController.cs b/src/Umbraco.Web/Editors/RelationTypeController.cs index ef3def1889..7113e30909 100644 --- a/src/Umbraco.Web/Editors/RelationTypeController.cs +++ b/src/Umbraco.Web/Editors/RelationTypeController.cs @@ -5,7 +5,12 @@ using System.Net.Http; using System.Web.Http; using AutoMapper; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; @@ -22,6 +27,10 @@ namespace Umbraco.Web.Editors [EnableOverrideAuthorization] public class RelationTypeController : BackOfficeNotificationsController { + public RelationTypeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } + /// /// Gets a relation type by ID. /// diff --git a/src/Umbraco.Web/Editors/TemplateController.cs b/src/Umbraco.Web/Editors/TemplateController.cs index f91d27ceae..17faf4349f 100644 --- a/src/Umbraco.Web/Editors/TemplateController.cs +++ b/src/Umbraco.Web/Editors/TemplateController.cs @@ -4,8 +4,14 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi.Filters; @@ -17,6 +23,10 @@ namespace Umbraco.Web.Editors [UmbracoTreeAuthorize(Constants.Trees.Templates)] public class TemplateController : BackOfficeNotificationsController { + public TemplateController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } + /// /// Gets data type by alias /// diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index c31d005ea6..3789e22b49 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -17,10 +17,12 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Identity; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Security; @@ -43,6 +45,10 @@ namespace Umbraco.Web.Editors [IsCurrentUserModelFilter] public class UsersController : UmbracoAuthorizedJsonController { + public UsersController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) + { + } + /// /// Returns a list of the sizes of gravatar urls for the user or null if the gravatar server cannot be reached /// diff --git a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs index 2bb093a659..cd87d9dd37 100644 --- a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs @@ -23,16 +23,19 @@ namespace Umbraco.Web.Search public class UmbracoTreeSearcher { private readonly IExamineManager _examineManager; + private readonly UmbracoContext _umbracoContext; private readonly UmbracoHelper _umbracoHelper; private readonly ILocalizationService _languageService; private readonly IEntityService _entityService; public UmbracoTreeSearcher(IExamineManager examineManager, + UmbracoContext umbracoContext, UmbracoHelper umbracoHelper, ILocalizationService languageService, IEntityService entityService) { _examineManager = examineManager ?? throw new ArgumentNullException(nameof(examineManager)); + _umbracoContext = umbracoContext; _umbracoHelper = umbracoHelper ?? throw new ArgumentNullException(nameof(umbracoHelper)); _languageService = languageService; _entityService = entityService; @@ -61,9 +64,7 @@ namespace Umbraco.Web.Search string type; var indexName = Constants.UmbracoIndexes.InternalIndexName; var fields = new[] { "id", "__NodeId" }; - - var umbracoContext = _umbracoHelper.UmbracoContext; - + // TODO: WE should try to allow passing in a lucene raw query, however we will still need to do some manual string // manipulation for things like start paths, member types, etc... //if (Examine.ExamineExtensions.TryParseLuceneQuery(query)) @@ -86,12 +87,12 @@ namespace Umbraco.Web.Search break; case UmbracoEntityTypes.Media: type = "media"; - var allMediaStartNodes = umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService); + var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService); AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, _entityService); break; case UmbracoEntityTypes.Document: type = "content"; - var allContentStartNodes = umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService); + var allContentStartNodes = _umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService); AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, _entityService); break; default: diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 73e93300ec..4b1b125a96 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -78,20 +78,7 @@ namespace Umbraco.Web /// Gets the query context. /// public IPublishedContentQuery ContentQuery { get; } - - /// - /// Gets the Umbraco context. - /// - public UmbracoContext UmbracoContext - { - get - { - if (_umbracoContext == null) - throw new NullReferenceException("UmbracoContext has not been set."); - return _umbracoContext; - } - } - + /// /// Gets the membership helper. /// @@ -100,7 +87,7 @@ namespace Umbraco.Web /// /// Gets the url provider. /// - public UrlProvider UrlProvider => UmbracoContext.UrlProvider; + public UrlProvider UrlProvider => _umbracoContext.UrlProvider; /// /// Gets (or sets) the current item assigned to the UmbracoHelper. From 036ca7f1e5a20804860f7e07f98c8f78fadf639b Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 15:30:38 +1100 Subject: [PATCH 056/555] fixing tests --- .../Web/Mvc/SurfaceControllerTests.cs | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 0ff3662f95..b3ae7e3dd6 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -77,42 +77,15 @@ namespace Umbraco.Tests.Web.Mvc Assert.IsNotNull(ctrl.UmbracoContext); } - - [Test] - public void Umbraco_Helper_Not_Null() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var umbracoContext = UmbracoContext.EnsureContext( - Current.UmbracoContextAccessor, - new Mock().Object, - Mock.Of(), - new Mock(null, null, globalSettings).Object, - TestObjects.GetUmbracoSettings(), - Enumerable.Empty(), - globalSettings, - new TestVariationContextAccessor(), - true); - - var controller = new TestSurfaceController(umbracoContext); - Composition.Register(_ => umbracoContext); - - Assert.IsNotNull(controller.Umbraco); - } - + [Test] public void Can_Lookup_Content() { var publishedSnapshot = new Mock(); publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); - var contentCache = new Mock(); var content = new Mock(); content.Setup(x => x.Id).Returns(2); - contentCache.Setup(x => x.GetById(It.IsAny())).Returns(content.Object); - var mediaCache = new Mock(); - publishedSnapshot.Setup(x => x.Content).Returns(contentCache.Object); - publishedSnapshot.Setup(x => x.Media).Returns(mediaCache.Object); var publishedSnapshotService = new Mock(); - publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot.Object); var globalSettings = TestObjects.GetGlobalSettings(); var umbracoContext = UmbracoContext.EnsureContext( @@ -131,13 +104,14 @@ namespace Umbraco.Tests.Web.Mvc Mock.Of(), Mock.Of(), Mock.Of(), - Mock.Of(), + Mock.Of(query => query.Content(2) == content.Object), new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); var ctrl = new TestSurfaceController(umbracoContext, helper); var result = ctrl.GetContent(2) as PublishedContentResult; Assert.IsNotNull(result); + Assert.IsNotNull(result.Content); Assert.AreEqual(2, result.Content.Id); } From ad5b166f3f48d085e774ac57f8d10b96bc8d5981 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 15:44:32 +1100 Subject: [PATCH 057/555] Fixes tests, simplifies constructors --- .../Routing/RenderRouteHandlerTests.cs | 18 ++++++++++++++++-- .../TestHelpers/Stubs/TestControllerFactory.cs | 10 ++++++++++ src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 14 -------------- .../Editors/BackOfficeController.cs | 4 ++-- src/Umbraco.Web/Mvc/RenderMvcController.cs | 4 ++-- .../Mvc/UmbracoAuthorizedController.cs | 3 ++- src/Umbraco.Web/Mvc/UmbracoController.cs | 5 ++--- 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 3f44c6764e..c7282ee9c8 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Web.Mvc; using System.Web.Routing; +using System.Web.Security; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -17,12 +18,15 @@ using Umbraco.Web.WebApi; using Umbraco.Core.Strings; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Dictionary; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.Testing; using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Runtime; +using Umbraco.Web.Security; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Routing @@ -136,7 +140,16 @@ namespace Umbraco.Tests.Routing var type = new AutoPublishedContentType(22, "CustomDocument", new PublishedPropertyType[] { }); ContentTypesCache.GetPublishedContentTypeByAlias = alias => type; - var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContext, Mock.Of())); + var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContext, Mock.Of(), context => + { + var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); + return new CustomDocumentController(Factory.GetInstance(), + umbracoContext, + Factory.GetInstance(), + Factory.GetInstance(), + Factory.GetInstance(), + new UmbracoHelper(umbracoContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), membershipHelper)); + })); handler.GetHandlerForRoute(umbracoContext.HttpContext.Request.RequestContext, frequest); Assert.AreEqual("CustomDocument", routeData.Values["controller"].ToString()); @@ -172,7 +185,8 @@ namespace Umbraco.Tests.Routing /// public class CustomDocumentController : RenderMvcController { - public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) + public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper) { } diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs index 36c5961b9f..9889b8d0c2 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs @@ -19,6 +19,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs { private readonly UmbracoContext _umbracoContext; private readonly ILogger _logger; + private readonly Func _factory; public TestControllerFactory(UmbracoContext umbracoContext, ILogger logger) { @@ -26,8 +27,17 @@ namespace Umbraco.Tests.TestHelpers.Stubs _logger = logger; } + public TestControllerFactory(UmbracoContext umbracoContext, ILogger logger, Func factory) + { + _umbracoContext = umbracoContext; + _logger = logger; + _factory = factory; + } + public IController CreateController(RequestContext requestContext, string controllerName) { + if (_factory != null) return _factory(requestContext); + var types = TypeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() }); var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase)); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 4294faf4f8..702a99b510 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -231,20 +231,6 @@ namespace Umbraco.Tests.Testing .Append(); Composition.RegisterUnique(); - //TODO: A lot of this is just copied from the WebRuntimeComposer, maybe we should just compose it all? - Composition.Register(factory => - { - var umbCtx = factory.GetInstance(); - return new PublishedContentQuery(umbCtx.UmbracoContext.ContentCache, umbCtx.UmbracoContext.MediaCache, factory.GetInstance()); - }, Lifetime.Request); - Composition.Register(Lifetime.Request); - - Composition.RegisterUnique(); - Composition.RegisterUnique(); - Composition.RegisterUnique(); - - // register the umbraco helper - this is Transient! very important! - Composition.Register(); } protected virtual void ComposeWtf() diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index abe7930693..91a3f6778b 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -49,8 +49,8 @@ namespace Umbraco.Web.Editors private const string TokenPasswordResetCode = "PasswordResetCode"; private static readonly string[] TempDataTokenNames = { TokenExternalSignInError, TokenPasswordResetCode }; - public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) - : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) + public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper) { _manifestParser = manifestParser; _features = features; diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index da7e3b08fc..e67aa3948e 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -23,8 +23,8 @@ namespace Umbraco.Web.Mvc ActionInvoker = new RenderActionInvoker(); } - public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) - : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) + public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper) { ActionInvoker = new RenderActionInvoker(); } diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs index a54958c4f7..ae97f22dbe 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs @@ -21,7 +21,8 @@ namespace Umbraco.Web.Mvc { } - protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger, umbracoHelper) + protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + : base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper) { } } diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs index 61198bd263..79987ab6b4 100644 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoController.cs @@ -73,20 +73,19 @@ namespace Umbraco.Web.Mvc Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance() ) { } - protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) + protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) { GlobalSettings = globalSettings; UmbracoContext = umbracoContext; Services = services; AppCaches = appCaches; - Logger = logger; + Logger = profilingLogger; ProfilingLogger = profilingLogger; Umbraco = umbracoHelper; } From bb64141207356f9082c621d93fb5d16bca34e2bb Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 16:35:10 +1100 Subject: [PATCH 058/555] removes obsolete method --- .../Mvc/MemberAuthorizeAttribute.cs | 46 ++++--------------- src/Umbraco.Web/Security/MembershipHelper.cs | 5 -- src/Umbraco.Web/Security/WebSecurity.cs | 25 +--------- .../WebApi/MemberAuthorizeAttribute.cs | 46 +++---------------- 4 files changed, 16 insertions(+), 106 deletions(-) diff --git a/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs index 287edd3bce..5f81ced3f0 100644 --- a/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs @@ -1,10 +1,11 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Web; using System.Web.Mvc; using AuthorizeAttribute = System.Web.Mvc.AuthorizeAttribute; using Umbraco.Core; -using Umbraco.Web.Composing; +using Umbraco.Web.Security; +using Umbraco.Core.Composing; +using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Web.Mvc { @@ -14,35 +15,6 @@ namespace Umbraco.Web.Mvc /// public sealed class MemberAuthorizeAttribute : AuthorizeAttribute { - // see note in HttpInstallAuthorizeAttribute - private readonly UmbracoContext _umbracoContext; - - private UmbracoContext UmbracoContext => _umbracoContext ?? Current.UmbracoContext; - - /// - /// THIS SHOULD BE ONLY USED FOR UNIT TESTS - /// - /// - public MemberAuthorizeAttribute(UmbracoContext umbracoContext) - { - if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); - _umbracoContext = umbracoContext; - } - - public MemberAuthorizeAttribute() - { - - } - - /// - /// Flag for whether to allow all site visitors or just authenticated members - /// - /// - /// This is the same as applying the [AllowAnonymous] attribute - /// - [Obsolete("Use [AllowAnonymous] instead")] - public bool AllowAll { get; set; } - /// /// Comma delimited list of allowed member types /// @@ -70,17 +42,15 @@ namespace Umbraco.Web.Mvc var members = new List(); foreach (var s in AllowMembers.Split(',')) { - int id; - if (int.TryParse(s, out id)) + if (int.TryParse(s, out var id)) { members.Add(id); } } - return UmbracoContext.Security.IsMemberAuthorized(AllowAll, - AllowType.Split(','), - AllowGroup.Split(','), - members); + var helper = Current.Factory.GetInstance(); + return helper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members); + } /// diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index daec4bb1f7..8de42fc12b 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -599,20 +599,15 @@ namespace Umbraco.Web.Security /// /// Returns true or false if the currently logged in member is authorized based on the parameters provided /// - /// /// /// /// /// public virtual bool IsMemberAuthorized( - bool allowAll = false, IEnumerable allowTypes = null, IEnumerable allowGroups = null, IEnumerable allowMembers = null) { - if (allowAll) - return true; - if (allowTypes == null) allowTypes = Enumerable.Empty(); if (allowGroups == null) diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index 54ff1bba3f..ef6193694c 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -33,30 +33,7 @@ namespace Umbraco.Web.Security _userService = userService; _globalSettings = globalSettings; } - - /// - /// Returns true or false if the currently logged in member is authorized based on the parameters provided - /// - /// - /// - /// - /// - /// - [Obsolete("Use MembershipHelper.IsMemberAuthorized instead")] - public bool IsMemberAuthorized( - bool allowAll = false, - IEnumerable allowTypes = null, - IEnumerable allowGroups = null, - IEnumerable allowMembers = null) - { - if (Current.UmbracoContext == null) - { - return false; - } - var helper = Current.Factory.GetInstance(); - return helper.IsMemberAuthorized(allowAll, allowTypes, allowGroups, allowMembers); - } - + private IUser _currentUser; /// diff --git a/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs index 12caa29703..bc1e9a4318 100644 --- a/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs @@ -1,7 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Web.Http; using Umbraco.Core; +using Umbraco.Web.Security; +using Umbraco.Core.Composing; +using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Web.WebApi { @@ -11,37 +13,6 @@ namespace Umbraco.Web.WebApi /// public sealed class MemberAuthorizeAttribute : AuthorizeAttribute { - private readonly UmbracoContext _umbracoContext; - - private UmbracoContext GetUmbracoContext() - { - return _umbracoContext ?? UmbracoContext.Current; - } - - /// - /// THIS SHOULD BE ONLY USED FOR UNIT TESTS - /// - /// - public MemberAuthorizeAttribute(UmbracoContext umbracoContext) - { - if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); - _umbracoContext = umbracoContext; - } - - public MemberAuthorizeAttribute() - { - - } - - /// - /// Flag for whether to allow all site visitors or just authenticated members - /// - /// - /// This is the same as applying the [AllowAnonymous] attribute - /// - [Obsolete("Use [AllowAnonymous] instead")] - public bool AllowAll { get; set; } - /// /// Comma delimited list of allowed member types /// @@ -69,17 +40,14 @@ namespace Umbraco.Web.WebApi var members = new List(); foreach (var s in AllowMembers.Split(',')) { - int id; - if (int.TryParse(s, out id)) + if (int.TryParse(s, out var id)) { members.Add(id); } } - return GetUmbracoContext().Security.IsMemberAuthorized(AllowAll, - AllowType.Split(','), - AllowGroup.Split(','), - members); + var helper = Current.Factory.GetInstance(); + return helper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members); } } From 045020e739f277d016516e34e200018bfcd495b0 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 1 Feb 2019 08:37:06 +0100 Subject: [PATCH 059/555] #4068 - Changed `save` event triggered when save dialog is opened. `save` is still broadcasted on the actual save. Changed the grid event listener to only execute on `save` events --- .../common/directives/components/content/edit.controller.js | 2 +- .../donotpostdollarvariablesrequest.interceptor.js | 2 +- .../src/views/propertyeditors/grid/grid.controller.js | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 5c5b1f933e..4f71fb0686 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -617,7 +617,7 @@ // TODO: Add "..." to save button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant if (isContentCultureVariant()) { //before we launch the dialog we want to execute all client side validations first - if (formHelper.submitForm({ scope: $scope, action: "save" })) { + if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog" })) { var dialog = { parentScope: $scope, diff --git a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js index 0a5f6d837d..1bae002df9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js +++ b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js @@ -26,7 +26,7 @@ //dealing with requests: 'request': function(config) { if(config.method === "POST"){ - config.transformRequest.push(transform); + transform(config.data); } return config; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js index f7e69a2683..b40305f5f5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js @@ -909,9 +909,9 @@ angular.module("umbraco") // needs to be merged in at runtime to ensure that the real config values are used // if they are ever updated. - var unsubscribe = $scope.$on("formSubmitting", function () { - - if ($scope.model.value && $scope.model.value.sections) { + var unsubscribe = $scope.$on("formSubmitting", function (e, args) { + + if (args.action === "save" && $scope.model.value && $scope.model.value.sections) { _.each($scope.model.value.sections, function(section) { if (section.rows) { _.each(section.rows, function (row) { From 979f7b404cc32639392fcf1aa0dbc90584d2a8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 1 Feb 2019 10:51:14 +0100 Subject: [PATCH 060/555] V8: refactoring of layers add and removal methods --- .../components/editor/umbeditors.directive.js | 234 +++++++++--------- .../less/components/editor/umb-editor.less | 16 +- 2 files changed, 130 insertions(+), 120 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js index 0db239c56a..c25dd0a76f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js @@ -13,145 +13,145 @@ function addEditor(editor) { + + if (!editor.style) + editor.style = {}; + editor.animating = true; - + showOverlayOnPrevEditor(); - // start collapsing editors to make room for new ones - $timeout(function() { - - var editorsElement = el[0]; - // only select the editors which are allowed to be - // shown so we don't animate a lot of editors which aren't necessary - var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ allowedNumberOfVisibleEditors +')'); - - // collapse open editors before opening the new one - var collapseEditorAnimation = anime({ - targets: moveEditors, - width: function(el, index, length) { - // we have to resize all small editors when they move to the - // left side so they don't leave a gap - if(el.classList.contains("umb-editor--small")) { - return "100%"; - } - }, - left: function(el, index, length){ - if(length >= allowedNumberOfVisibleEditors) { - return index * editorIndent; - } - return (index + 1) * editorIndent; - }, + var i = allowedNumberOfVisibleEditors; + var len = scope.editors.length; + while(i= allowedNumberOfVisibleEditors) { - indentValue = allowedNumberOfVisibleEditors * editorIndent; } - - // indent all large editors - if(editor.size !== "small") { - lastEditor.style.left = indentValue + "px"; + + if(scope.editors[i].size !== "small") { + animeConfig.width = "100%"; } + + if(len >= allowedNumberOfVisibleEditors) { + animeConfig.left = i * editorIndent; + } else { + animeConfig.left = (i + 1) * editorIndent; + } + + anime(animeConfig); + + i++; + } + + + // push the new editor to the dom + scope.editors.push(editor); + + + + var indentValue = scope.editors.length * editorIndent; - // animation config - var addEditorAnimation = anime({ - targets: lastEditor, - translateX: [100 + '%', 0], - opacity: [0, 1], - easing: 'easeInOutQuint', - duration: 300, - complete: function() { - $timeout(function(){ - editor.animating = false; - }); - } - }); + // don't allow indent larger than what + // fits the max number of visible editors + if(scope.editors.length >= allowedNumberOfVisibleEditors) { + indentValue = allowedNumberOfVisibleEditors * editorIndent; + } + // indent all large editors + if(editor.size !== "small") { + editor.style.left = indentValue + "px"; + } + + editor.style._tx = 100; + //editor.style.opacity = 0; + editor.style.transform = "translateX("+editor.style._tx+"%)"; + + // animation config + anime({ + targets: editor.style, + _tx: [100, 0], + //opacity: [0, 1], + easing: 'easeOutExpo', + duration: 480, + update: () => { + editor.style.transform = "translateX("+editor.style._tx+"%)"; + scope.$digest(); + }, + complete: function() { + //$timeout(function(){ + editor.animating = false; + scope.$digest(); + //}); + } }); + } function removeEditor(editor) { editor.animating = true; - - $timeout(function(){ - - var editorsElement = el[0]; - var lastEditor = editorsElement.querySelector('.umb-editor:last-of-type'); - - var removeEditorAnimation = anime({ - targets: lastEditor, - translateX: [0, 100 + '%'], - opacity: [1, 0], - easing: 'easeInOutQuint', - duration: 300, - complete: function(a) { - $timeout(function(){ - scope.editors.splice(-1,1); - removeOverlayFromPrevEditor(); - }); - } - }); - - expandEditors(); - + + editor.style._tx = 0; + editor.style.transform = "translateX("+editor.style._tx+"%)"; + + // animation config + anime({ + targets: editor.style, + _tx: [0, 100], + //opacity: [1, 0], + easing: 'easeInExpo', + duration: 360, + update: () => { + editor.style.transform = "translateX("+editor.style._tx+"%)"; + scope.$digest(); + }, + complete: function() { + //$timeout(function(){ + scope.editors.splice(-1,1); + removeOverlayFromPrevEditor(); + scope.$digest(); + //}) + } }); - + + + expandEditors(); + + } function expandEditors() { - // expand hidden editors - $timeout(function() { - - var editorsElement = el[0]; - // only select the editors which are allowed to be - // shown so we don't animate a lot of editors which aren't necessary - // as the last element hasn't been removed from the dom yet we have to select the last four and then skip the last child (as it is the one closing). - var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ allowedNumberOfVisibleEditors + 1 +'):not(:last-child)'); - var editorWidth = editorsElement.offsetWidth; - - var expandEditorAnimation = anime({ - targets: moveEditors, - left: function(el, index, length){ - // move the editor all the way to the right if the top one is a small - if(el.classList.contains("umb-editor--small")) { - // only change the size if it is the editor on top - if(index + 1 === length) { - return editorWidth - 500; - } - } else { - return (index + 1) * editorIndent; - } - }, - width: function(el, index, length) { - // set the correct size if the top editor is of type "small" - if(el.classList.contains("umb-editor--small") && index + 1 === length) { - return "500px"; - } - }, + + var i = allowedNumberOfVisibleEditors + 1; + var len = scope.editors.length-1; + while(i Date: Fri, 1 Feb 2019 13:01:42 +0100 Subject: [PATCH 061/555] Fix wrong class name in media picker element selector --- .../infiniteeditors/mediapicker/mediapicker.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js index 7b3d13937f..2d6a2be471 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js @@ -104,7 +104,7 @@ angular.module("umbraco") } $scope.upload = function(v) { - angular.element(".umb-file-dropzone-directive .file-select").trigger("click"); + angular.element(".umb-file-dropzone .file-select").trigger("click"); }; $scope.dragLeave = function(el, event) { From 9acf913872f012e4790315a3dcf1a32c4cc47661 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 1 Feb 2019 14:07:31 +0100 Subject: [PATCH 062/555] #3545 - Added IContentTypeServiceBaseFactory to create a IContentTypeServiceBase (E.g. IContentTypeService or IMediaTypeService) based on the type of the IContentBase --- .../Composing/Composers/ServicesComposer.cs | 1 + src/Umbraco.Core/ContentExtensions.cs | 16 +++++---- .../Services/IContentTypeServiceBase.cs | 7 +++- .../IContentTypeServiceBaseFactory.cs | 10 ++++++ .../ContentTypeServiceBaseFactory.cs | 35 +++++++++++++++++++ ...peServiceBaseOfTRepositoryTItemTService.cs | 7 ++++ src/Umbraco.Core/Services/ServiceContext.cs | 17 +++++++-- src/Umbraco.Core/Umbraco.Core.csproj | 2 ++ .../PublishedContent/NuCacheTests.cs | 5 ++- .../Scoping/ScopedNuCacheTests.cs | 4 +-- .../ContentTypeServiceVariantsTests.cs | 4 +-- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 8 +++-- src/Umbraco.Web/Editors/ContentController.cs | 3 +- .../Editors/ContentTypeController.cs | 9 ++--- src/Umbraco.Web/Editors/MediaController.cs | 8 ++--- .../PublishedContentHashtableConverter.cs | 5 +-- .../Models/Mapping/ContentMapperProfile.cs | 3 +- .../Mapping/ContentTypeBasicResolver.cs | 11 +++--- .../Mapping/ContentTypeMapperProfile.cs | 4 +++ .../Models/Mapping/MediaMapperProfile.cs | 4 +-- .../NuCache/PublishedSnapshotService.cs | 9 ++--- 21 files changed, 130 insertions(+), 42 deletions(-) create mode 100644 src/Umbraco.Core/Services/IContentTypeServiceBaseFactory.cs create mode 100644 src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseFactory.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 0410e72148..1fe5dd7561 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -37,6 +37,7 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 63f9f176ea..d4ec876565 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -166,7 +166,7 @@ namespace Umbraco.Core /// This really is for FileUpload fields only, and should be obsoleted. For anything else, /// you need to store the file by yourself using Store and then figure out /// how to deal with auto-fill properties (if any) and thumbnails (if any) by yourself. - public static void SetValue(this IContentBase content, IContentTypeService contentTypeService, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) + public static void SetValue(this IContentBase content, IContentTypeServiceBaseFactory contentTypeServiceBaseFactory, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) { if (filename == null || filestream == null) return; @@ -175,12 +175,12 @@ namespace Umbraco.Core if (string.IsNullOrWhiteSpace(filename)) return; filename = filename.ToLower(); - SetUploadFile(content,contentTypeService, propertyTypeAlias, filename, filestream, culture, segment); + SetUploadFile(content,contentTypeServiceBaseFactory, propertyTypeAlias, filename, filestream, culture, segment); } - private static void SetUploadFile(this IContentBase content, IContentTypeService contentTypeService, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) + private static void SetUploadFile(this IContentBase content, IContentTypeServiceBaseFactory contentTypeServiceBaseFactory, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) { - var property = GetProperty(content, contentTypeService, propertyTypeAlias); + var property = GetProperty(content, contentTypeServiceBaseFactory, propertyTypeAlias); // Fixes https://github.com/umbraco/Umbraco-CMS/issues/3937 - Assigning a new file to an // existing IMedia with extension SetValue causes exception 'Illegal characters in path' @@ -201,11 +201,12 @@ namespace Umbraco.Core } // gets or creates a property for a content item. - private static Property GetProperty(IContentBase content, IContentTypeService contentTypeService, string propertyTypeAlias) + private static Property GetProperty(IContentBase content, IContentTypeServiceBaseFactory contentTypeServiceBaseFactory, string propertyTypeAlias) { var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); if (property != null) return property; + var contentTypeService = contentTypeServiceBaseFactory.Create(content); var contentType = contentTypeService.Get(content.ContentTypeId); var propertyType = contentType.CompositionPropertyTypes .FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); @@ -233,8 +234,9 @@ namespace Umbraco.Core /// the "folder number" that was assigned to the previous file referenced by the property, /// if any. /// - public static string StoreFile(this IContentBase content, IContentTypeService contentTypeService, string propertyTypeAlias, string filename, Stream filestream, string filepath) + public static string StoreFile(this IContentBase content, IContentTypeServiceBaseFactory contentTypeServiceBaseFactory, string propertyTypeAlias, string filename, Stream filestream, string filepath) { + var contentTypeService = contentTypeServiceBaseFactory.Create(content); var contentType = contentTypeService.Get(content.ContentTypeId); var propertyType = contentType .CompositionPropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); @@ -317,7 +319,7 @@ namespace Umbraco.Core { return serializer.Serialize(content, false, false); } - + /// /// Creates the xml representation for the object diff --git a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs index bc091535d3..cd6f2f4911 100644 --- a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs @@ -4,11 +4,16 @@ using Umbraco.Core.Models; namespace Umbraco.Core.Services { + public interface IContentTypeServiceBase + { + IContentTypeComposition Get(int id); + } + /// /// Provides a common base interface for , and . /// /// The type of the item. - public interface IContentTypeServiceBase : IService + public interface IContentTypeServiceBase : IContentTypeServiceBase, IService where TItem : IContentTypeComposition { TItem Get(int id); diff --git a/src/Umbraco.Core/Services/IContentTypeServiceBaseFactory.cs b/src/Umbraco.Core/Services/IContentTypeServiceBaseFactory.cs new file mode 100644 index 0000000000..c816863128 --- /dev/null +++ b/src/Umbraco.Core/Services/IContentTypeServiceBaseFactory.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.Models; + +namespace Umbraco.Core.Services +{ + public interface IContentTypeServiceBaseFactory + { + IContentTypeServiceBase Create(IContentBase contentBase); + + } +} diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseFactory.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseFactory.cs new file mode 100644 index 0000000000..64395d4e2d --- /dev/null +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseFactory.cs @@ -0,0 +1,35 @@ +using System; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Services.Implement +{ + public class ContentTypeServiceBaseFactory : IContentTypeServiceBaseFactory + { + private readonly IContentTypeService _contentTypeService; + private readonly IMediaTypeService _mediaTypeService; + private readonly IMemberTypeService _memberTypeService; + + public ContentTypeServiceBaseFactory(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService) + { + _contentTypeService = contentTypeService; + _mediaTypeService = mediaTypeService; + _memberTypeService = memberTypeService; + } + + public IContentTypeServiceBase Create(IContentBase contentBase) + { + switch (contentBase) + { + case IContent _: + return _contentTypeService; + case IMedia _: + return _mediaTypeService; + case IMember _: + return _memberTypeService; + default: + throw new ArgumentException($"Invalid contentBase type: {contentBase.GetType().FullName}" , nameof(contentBase)); + } + } + + } +} diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index 78bb9821e4..943d4be536 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -211,6 +211,11 @@ namespace Umbraco.Core.Services.Implement #region Get, Has, Is, Count + IContentTypeComposition IContentTypeServiceBase.Get(int id) + { + return Get(id); + } + public TItem Get(int id) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) @@ -951,5 +956,7 @@ namespace Umbraco.Core.Services.Implement } #endregion + + } } diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index 6d7ac8a5e7..efb4787e65 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core.Services.Implement; namespace Umbraco.Core.Services { @@ -32,11 +33,12 @@ namespace Umbraco.Core.Services private readonly Lazy _externalLoginService; private readonly Lazy _redirectUrlService; private readonly Lazy _consentService; + private readonly Lazy _contentTypeServiceBaseFactory; /// /// Initializes a new instance of the class with lazy services. /// - public ServiceContext(Lazy publicAccessService, Lazy domainService, Lazy auditService, Lazy localizedTextService, Lazy tagService, Lazy contentService, Lazy userService, Lazy memberService, Lazy mediaService, Lazy contentTypeService, Lazy mediaTypeService, Lazy dataTypeService, Lazy fileService, Lazy localizationService, Lazy packagingService, Lazy serverRegistrationService, Lazy entityService, Lazy relationService, Lazy macroService, Lazy memberTypeService, Lazy memberGroupService, Lazy notificationService, Lazy externalLoginService, Lazy redirectUrlService, Lazy consentService) + public ServiceContext(Lazy publicAccessService, Lazy domainService, Lazy auditService, Lazy localizedTextService, Lazy tagService, Lazy contentService, Lazy userService, Lazy memberService, Lazy mediaService, Lazy contentTypeService, Lazy mediaTypeService, Lazy dataTypeService, Lazy fileService, Lazy localizationService, Lazy packagingService, Lazy serverRegistrationService, Lazy entityService, Lazy relationService, Lazy macroService, Lazy memberTypeService, Lazy memberGroupService, Lazy notificationService, Lazy externalLoginService, Lazy redirectUrlService, Lazy consentService, Lazy contentTypeServiceBaseFactory) { _publicAccessService = publicAccessService; _domainService = domainService; @@ -63,6 +65,7 @@ namespace Umbraco.Core.Services _externalLoginService = externalLoginService; _redirectUrlService = redirectUrlService; _consentService = consentService; + _contentTypeServiceBaseFactory = contentTypeServiceBaseFactory; } /// @@ -96,7 +99,8 @@ namespace Umbraco.Core.Services IExternalLoginService externalLoginService = null, IServerRegistrationService serverRegistrationService = null, IRedirectUrlService redirectUrlService = null, - IConsentService consentService = null) + IConsentService consentService = null, + IContentTypeServiceBaseFactory contentTypeServiceBaseFactory = null) { Lazy Lazy(T service) => service == null ? null : new Lazy(() => service); @@ -125,7 +129,9 @@ namespace Umbraco.Core.Services Lazy(notificationService), Lazy(externalLoginService), Lazy(redirectUrlService), - Lazy(consentService)); + Lazy(consentService), + Lazy(contentTypeServiceBaseFactory) + ); } /// @@ -252,5 +258,10 @@ namespace Umbraco.Core.Services /// Gets the ConsentService. /// public IConsentService ConsentService => _consentService.Value; + + /// + /// Gets the ContentTypeServiceBaseFactory. + /// + public IContentTypeServiceBaseFactory ContentTypeServiceBaseFactory => _contentTypeServiceBaseFactory.Value; } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d39247ad9e..ddfa4f9df8 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1346,6 +1346,7 @@ + @@ -1363,6 +1364,7 @@ + diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 8c1caae1e0..73554aec67 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -124,6 +124,9 @@ namespace Umbraco.Tests.PublishedContent Mock.Get(contentTypeService).Setup(x => x.GetAll()).Returns(contentTypes); Mock.Get(contentTypeService).Setup(x => x.GetAll(It.IsAny())).Returns(contentTypes); + var contentTypeServiceBaseFactory = Mock.Of(); + Mock.Get(contentTypeServiceBaseFactory).Setup(x => x.Create(It.IsAny())).Returns(contentTypeService); + var dataTypeService = Mock.Of(); Mock.Get(dataTypeService).Setup(x => x.GetAll()).Returns(dataTypes); @@ -177,7 +180,7 @@ namespace Umbraco.Tests.PublishedContent dataSource, globalSettings, new SiteDomainHelper(), - contentTypeService, + contentTypeServiceBaseFactory, Mock.Of()); // invariant is the current default diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 9333d3be18..d2fd3f90f9 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -80,7 +80,7 @@ namespace Umbraco.Tests.Scoping var documentRepository = Mock.Of(); var mediaRepository = Mock.Of(); var memberRepository = Mock.Of(); - var contentTypeService = Current.Services.ContentTypeService; + var contentTypeServiceBaseFactory = Current.Services.ContentTypeServiceBaseFactory; return new PublishedSnapshotService( options, @@ -97,7 +97,7 @@ namespace Umbraco.Tests.Scoping documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, new DatabaseDataSource(), - Factory.GetInstance(), new SiteDomainHelper(), contentTypeService, + Factory.GetInstance(), new SiteDomainHelper(), contentTypeServiceBaseFactory, Factory.GetInstance()); } diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index 0d0bdcf624..8f567afd65 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Services var documentRepository = Factory.GetInstance(); var mediaRepository = Mock.Of(); var memberRepository = Mock.Of(); - var contentTypeService = Current.Services.ContentTypeService; + var contentTypeServiceBaseFactory = Current.Services.ContentTypeServiceBaseFactory; return new PublishedSnapshotService( options, @@ -70,7 +70,7 @@ namespace Umbraco.Tests.Services documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, new DatabaseDataSource(), - Factory.GetInstance(), new SiteDomainHelper(), contentTypeService, + Factory.GetInstance(), new SiteDomainHelper(), contentTypeServiceBaseFactory, Factory.GetInstance()); } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 7a9702031b..6ab714a68a 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -176,7 +176,7 @@ namespace Umbraco.Tests.TestHelpers var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); var compiledPackageXmlParser = new CompiledPackageXmlParser(new ConflictingPackageData(macroService.Value, fileService.Value)); return new PackagingService( - auditService.Value, + auditService.Value, new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "createdPackages.config"), new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, @@ -188,9 +188,10 @@ namespace Umbraco.Tests.TestHelpers new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); - var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); + var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var redirectUrlService = GetLazyService(factory, c => new RedirectUrlService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var consentService = GetLazyService(factory, c => new ConsentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); + var contentTypeServiceBaseFactory = GetLazyService(factory, c => new ContentTypeServiceBaseFactory(factory.GetInstance(),factory.GetInstance(),factory.GetInstance())); return new ServiceContext( publicAccessService, @@ -217,7 +218,8 @@ namespace Umbraco.Tests.TestHelpers notificationService, externalLoginService, redirectUrlService, - consentService); + consentService, + contentTypeServiceBaseFactory); } private Lazy GetLazyService(IFactory container, Func ctor) diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index b81f68f14e..0dff862d08 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1838,7 +1838,8 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var parentContentType = Services.ContentTypeService.Get(parent.ContentTypeId); + var contentTypeService = Services.ContentTypeServiceBaseFactory.Create(parent); + var parentContentType = contentTypeService.Get(parent.ContentTypeId); //check if the item is allowed under this one if (parentContentType.AllowedContentTypes.Select(x => x.Id).ToArray() .Any(x => x.Value == toMove.ContentType.Id) == false) diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index a559dbe32f..8fc60261a1 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -403,7 +403,8 @@ namespace Umbraco.Web.Editors return Enumerable.Empty(); } - var contentType = Services.ContentTypeService.Get(contentItem.ContentTypeId); + var contentTypeService = Services.ContentTypeServiceBaseFactory.Create(contentItem); + var contentType = contentTypeService.Get(contentItem.ContentTypeId); var ids = contentType.AllowedContentTypes.Select(x => x.Id.Value).ToArray(); if (ids.Any() == false) return Enumerable.Empty(); @@ -498,7 +499,7 @@ namespace Umbraco.Web.Editors { return Request.CreateResponse(HttpStatusCode.NotFound); } - + var dataInstaller = new PackageDataInstallation(Logger, Services.FileService, Services.MacroService, Services.LocalizationService, Services.DataTypeService, Services.EntityService, Services.ContentTypeService, Services.ContentService, _propertyEditors); @@ -544,7 +545,7 @@ namespace Umbraco.Web.Editors } var model = new ContentTypeImportModel(); - + var file = result.FileData[0]; var fileName = file.Headers.ContentDisposition.FileName.Trim('\"'); var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower(); @@ -578,6 +579,6 @@ namespace Umbraco.Web.Editors } - + } } diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index cdef11b6d8..9699bf8a71 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -47,10 +47,10 @@ namespace Umbraco.Web.Editors [MediaControllerControllerConfiguration] public class MediaController : ContentControllerBase { - public MediaController(PropertyEditorCollection propertyEditors, IContentTypeService contentTypeService) + public MediaController(PropertyEditorCollection propertyEditors, IContentTypeServiceBaseFactory contentTypeServiceBaseFactory) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); - _contentTypeService = contentTypeService; + _contentTypeServiceBaseFactory = contentTypeServiceBaseFactory; } /// @@ -234,7 +234,7 @@ namespace Umbraco.Web.Editors private int[] _userStartNodes; private readonly PropertyEditorCollection _propertyEditors; - private readonly IContentTypeService _contentTypeService; + private readonly IContentTypeServiceBaseFactory _contentTypeServiceBaseFactory; protected int[] UserStartNodes { @@ -726,7 +726,7 @@ namespace Umbraco.Web.Editors if (fs == null) throw new InvalidOperationException("Could not acquire file stream"); using (fs) { - f.SetValue(_contentTypeService, Constants.Conventions.Media.File,fileName, fs); + f.SetValue(_contentTypeServiceBaseFactory, Constants.Conventions.Media.File,fileName, fs); } var saveResult = mediaService.Save(f, Security.CurrentUser.Id); diff --git a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs index ece76090d8..1ff38f3d1b 100644 --- a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs +++ b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs @@ -102,7 +102,7 @@ namespace Umbraco.Web.Macros Elements.Add("path", path); Elements.Add("splitpath", path.Split(',')); } - + /// /// Puts the properties of the node into the elements table /// @@ -202,7 +202,8 @@ namespace Umbraco.Web.Macros CreatorName = _inner.GetCreatorProfile().Name; WriterName = _inner.GetWriterProfile().Name; - ContentType = Current.PublishedContentTypeFactory.CreateContentType(_inner.ContentType); + var contentTypeService = Current.Services.ContentTypeServiceBaseFactory.Create(_inner); + ContentType = Current.PublishedContentTypeFactory.CreateContentType(contentTypeService.Get(_inner.ContentTypeId)); _properties = ContentType.PropertyTypes .Select(x => diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs index f6b774dae0..2c13a2ecad 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs @@ -23,6 +23,7 @@ namespace Umbraco.Web.Models.Mapping IUserService userService, IContentService contentService, IContentTypeService contentTypeService, + IContentTypeServiceBaseFactory contentTypeServiceBaseFactory, ILocalizationService localizationService) { // create, capture, cache @@ -30,7 +31,7 @@ namespace Umbraco.Web.Models.Mapping var creatorResolver = new CreatorResolver(userService); var actionButtonsResolver = new ActionButtonsResolver(userService, contentService); var childOfListViewResolver = new ContentChildOfListViewResolver(contentService, contentTypeService); - var contentTypeBasicResolver = new ContentTypeBasicResolver(contentTypeService); + var contentTypeBasicResolver = new ContentTypeBasicResolver(contentTypeServiceBaseFactory); var allowedTemplatesResolver = new AllowedTemplatesResolver(contentTypeService); var defaultTemplateResolver = new DefaultTemplateResolver(); var variantResolver = new ContentVariantResolver(localizationService); diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs index 7b4a936676..0655f4d8cf 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs @@ -16,11 +16,11 @@ namespace Umbraco.Web.Models.Mapping internal class ContentTypeBasicResolver : IValueResolver where TSource : IContentBase { - private readonly IContentTypeService _contentTypeService; + private readonly IContentTypeServiceBaseFactory _contentTypeServiceBaseFactory; - public ContentTypeBasicResolver(IContentTypeService contentTypeService) + public ContentTypeBasicResolver(IContentTypeServiceBaseFactory contentTypeServiceBaseFactory) { - _contentTypeService = contentTypeService; + _contentTypeServiceBaseFactory = contentTypeServiceBaseFactory; } public ContentTypeBasic Resolve(TSource source, TDestination destination, ContentTypeBasic destMember, ResolutionContext context) @@ -30,8 +30,9 @@ namespace Umbraco.Web.Models.Mapping if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { - var contentType = _contentTypeService.Get(source.ContentTypeId); - var contentTypeBasic = Mapper.Map(contentType); + var contentTypeService = _contentTypeServiceBaseFactory.Create(source); + var contentType = contentTypeService.Get(source.ContentTypeId); + var contentTypeBasic = Mapper.Map(contentType); return contentTypeBasic; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs index f70b01a422..88bf409737 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs @@ -134,6 +134,10 @@ namespace Umbraco.Web.Models.Mapping }); + CreateMap() + .ForMember(dest => dest.Udi, opt => opt.MapFrom(source => Udi.Create(Constants.UdiEntityType.MemberType, source.Key))) + .ForMember(dest => dest.Blueprints, opt => opt.Ignore()) + .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); CreateMap() .ForMember(dest => dest.Udi, opt => opt.MapFrom(source => Udi.Create(Constants.UdiEntityType.MemberType, source.Key))) .ForMember(dest => dest.Blueprints, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs index 4dcaaa2a0f..2b575c87da 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs @@ -25,12 +25,12 @@ namespace Umbraco.Web.Models.Mapping IMediaService mediaService, IMediaTypeService mediaTypeService, ILogger logger, - IContentTypeService contentTypeService) + IContentTypeServiceBaseFactory contentTypeServiceBaseFactory) { // create, capture, cache var mediaOwnerResolver = new OwnerResolver(userService); var childOfListViewResolver = new MediaChildOfListViewResolver(mediaService, mediaTypeService); - var mediaTypeBasicResolver = new ContentTypeBasicResolver(contentTypeService); + var mediaTypeBasicResolver = new ContentTypeBasicResolver(contentTypeServiceBaseFactory); //FROM IMedia TO MediaItemDisplay CreateMap() diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 752cfdb5de..e6a7c24f59 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IMemberRepository _memberRepository; private readonly IGlobalSettings _globalSettings; private readonly ISiteDomainHelper _siteDomainHelper; - private readonly IContentTypeService _contentTypeService; + private readonly IContentTypeServiceBaseFactory _contentTypeServiceBaseFactory; private readonly IEntityXmlSerializer _entitySerializer; private readonly IDefaultCultureAccessor _defaultCultureAccessor; @@ -85,7 +85,7 @@ namespace Umbraco.Web.PublishedCache.NuCache IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IScopeProvider scopeProvider, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, - IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IContentTypeService contentTypeService, + IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IContentTypeServiceBaseFactory contentTypeServiceBaseFactory, IEntityXmlSerializer entitySerializer) : base(publishedSnapshotAccessor, variationContextAccessor) { @@ -104,7 +104,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings; _siteDomainHelper = siteDomainHelper; - _contentTypeService = contentTypeService; + _contentTypeServiceBaseFactory = contentTypeServiceBaseFactory; // we need an Xml serializer here so that the member cache can support XPath, // for members this is done by navigating the serialized-to-xml member @@ -1204,7 +1204,8 @@ namespace Umbraco.Web.PublishedCache.NuCache var cultureData = new Dictionary(); // sanitize - names should be ok but ... never knows - var contentType = _contentTypeService.Get(content.ContentTypeId); + var contentTypeService = _contentTypeServiceBaseFactory.Create(content); + var contentType = contentTypeService.Get(content.ContentTypeId); if (contentType.VariesByCulture()) { var infos = content is IContent document From bf87ecb81823dfd4eb0dc15b142c4bda4b17c815 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Fri, 1 Feb 2019 14:32:17 +0100 Subject: [PATCH 063/555] Add descriptions to properties on default media items --- .../Migrations/Install/DatabaseDataCreator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 7e9df321c3..1a4fdd4400 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -211,13 +211,13 @@ namespace Umbraco.Core.Migrations.Install private void CreatePropertyTypeData() { _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = 1043, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 10, UniqueId = 10.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = -90, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 25, UniqueId = 25.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing }); //membership property types _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = -89, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing }); From d4b2ac3f1e02b9ece7bf392b67fa221ed6e448b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 1 Feb 2019 14:54:49 +0100 Subject: [PATCH 064/555] =?UTF-8?q?V8:=20UI=20=E2=80=94=20changed=20color?= =?UTF-8?q?=20for=20focus=20point=20on=20medias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 8d1b70c35d..09cdaf4939 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -547,7 +547,7 @@ height: 14px; text-align: center; border-radius: 20px; - background: @turquoise; + background: @pinkLight; border: 3px solid @white; opacity: 0.8; } From e17d6df02385563b9153ada29c19cc8e003f5505 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 1 Feb 2019 15:13:41 +0000 Subject: [PATCH 065/555] It helps if you put in a valid value - it expects Information and not Info as the loglevel --- src/Umbraco.Web.UI/config/serilog.config | 3 ++- src/Umbraco.Web.UI/config/serilog.user.config | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/config/serilog.config b/src/Umbraco.Web.UI/config/serilog.config index 9638d285ce..1b76cba302 100644 --- a/src/Umbraco.Web.UI/config/serilog.config +++ b/src/Umbraco.Web.UI/config/serilog.config @@ -5,7 +5,8 @@ - + + diff --git a/src/Umbraco.Web.UI/config/serilog.user.config b/src/Umbraco.Web.UI/config/serilog.user.config index 374657795e..24e5e4e4be 100644 --- a/src/Umbraco.Web.UI/config/serilog.user.config +++ b/src/Umbraco.Web.UI/config/serilog.user.config @@ -3,7 +3,8 @@ - + + - + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index e0660f8f12..02e24ddbb6 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -105,7 +105,7 @@ - 8.0.0-alpha.34 + 8.0.0-alpha.35 From 80165c3c0f816a5c38ba2110621f28e7db7e92c7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Feb 2019 19:52:04 +1100 Subject: [PATCH 082/555] Fixes allocations of property selectors, with nameof we save a bunch of both memory and initial reflection lookups --- src/Umbraco.Core/Models/AuditEntry.cs | 31 +--- src/Umbraco.Core/Models/Consent.cs | 29 +--- src/Umbraco.Core/Models/Content.cs | 21 +-- src/Umbraco.Core/Models/ContentBase.cs | 18 +- .../Models/ContentCultureInfos.cs | 15 +- src/Umbraco.Core/Models/ContentType.cs | 20 +-- src/Umbraco.Core/Models/ContentTypeBase.cs | 60 +++---- .../Models/ContentTypeCompositionBase.cs | 15 +- src/Umbraco.Core/Models/DataType.cs | 17 +- src/Umbraco.Core/Models/DictionaryItem.cs | 27 +-- .../Models/DictionaryTranslation.cs | 11 +- .../Models/Entities/BeingDirty.cs | 10 +- .../Models/Entities/BeingDirtyBase.cs | 18 +- .../Models/Entities/EntityBase.cs | 19 +-- .../Models/Entities/TreeEntityBase.cs | 30 +--- src/Umbraco.Core/Models/File.cs | 12 +- .../Models/Identity/BackOfficeIdentityUser.cs | 63 +++---- src/Umbraco.Core/Models/Language.cs | 23 +-- src/Umbraco.Core/Models/Macro.cs | 55 +++--- src/Umbraco.Core/Models/MacroProperty.cs | 41 ++--- src/Umbraco.Core/Models/Member.cs | 41 ++--- src/Umbraco.Core/Models/MemberGroup.cs | 12 +- src/Umbraco.Core/Models/MemberType.cs | 9 +- src/Umbraco.Core/Models/Membership/User.cs | 159 ++++++------------ .../Models/Membership/UserGroup.cs | 35 ++-- src/Umbraco.Core/Models/MigrationEntry.cs | 16 +- src/Umbraco.Core/Models/Property.cs | 9 +- src/Umbraco.Core/Models/PropertyGroup.cs | 17 +- src/Umbraco.Core/Models/PropertyType.cs | 43 ++--- src/Umbraco.Core/Models/PublicAccessEntry.cs | 36 ++-- src/Umbraco.Core/Models/PublicAccessRule.cs | 17 +- src/Umbraco.Core/Models/RedirectUrl.cs | 32 ++-- src/Umbraco.Core/Models/Relation.cs | 33 ++-- src/Umbraco.Core/Models/RelationType.cs | 31 ++-- src/Umbraco.Core/Models/ServerRegistration.cs | 40 +++-- src/Umbraco.Core/Models/StylesheetProperty.cs | 16 +- src/Umbraco.Core/Models/Tag.cs | 6 +- src/Umbraco.Core/Models/Template.cs | 26 +-- src/Umbraco.Core/Models/UmbracoDomain.cs | 28 +-- .../Cache/DeepCloneAppCacheTests.cs | 26 +-- 40 files changed, 358 insertions(+), 809 deletions(-) diff --git a/src/Umbraco.Core/Models/AuditEntry.cs b/src/Umbraco.Core/Models/AuditEntry.cs index 2076e5328c..da56c6c318 100644 --- a/src/Umbraco.Core/Models/AuditEntry.cs +++ b/src/Umbraco.Core/Models/AuditEntry.cs @@ -12,8 +12,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] internal class AuditEntry : EntityBase, IAuditEntry { - private static PropertySelectors _selectors; - private int _performingUserId; private string _performingDetails; private string _performingIp; @@ -21,39 +19,26 @@ namespace Umbraco.Core.Models private string _affectedDetails; private string _eventType; private string _eventDetails; - - private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); - - private class PropertySelectors - { - public readonly PropertyInfo PerformingUserId = ExpressionHelper.GetPropertyInfo(x => x.PerformingUserId); - public readonly PropertyInfo PerformingDetails = ExpressionHelper.GetPropertyInfo(x => x.PerformingDetails); - public readonly PropertyInfo PerformingIp = ExpressionHelper.GetPropertyInfo(x => x.PerformingIp); - public readonly PropertyInfo AffectedUserId = ExpressionHelper.GetPropertyInfo(x => x.AffectedUserId); - public readonly PropertyInfo AffectedDetails = ExpressionHelper.GetPropertyInfo(x => x.AffectedDetails); - public readonly PropertyInfo EventType = ExpressionHelper.GetPropertyInfo(x => x.EventType); - public readonly PropertyInfo EventDetails = ExpressionHelper.GetPropertyInfo(x => x.EventDetails); - } - + /// public int PerformingUserId { get => _performingUserId; - set => SetPropertyValueAndDetectChanges(value, ref _performingUserId, Selectors.PerformingUserId); + set => SetPropertyValueAndDetectChanges(value, ref _performingUserId, nameof(PerformingUserId)); } /// public string PerformingDetails { get => _performingDetails; - set => SetPropertyValueAndDetectChanges(value, ref _performingDetails, Selectors.PerformingDetails); + set => SetPropertyValueAndDetectChanges(value, ref _performingDetails, nameof(PerformingDetails)); } /// public string PerformingIp { get => _performingIp; - set => SetPropertyValueAndDetectChanges(value, ref _performingIp, Selectors.PerformingIp); + set => SetPropertyValueAndDetectChanges(value, ref _performingIp, nameof(PerformingIp)); } /// @@ -67,28 +52,28 @@ namespace Umbraco.Core.Models public int AffectedUserId { get => _affectedUserId; - set => SetPropertyValueAndDetectChanges(value, ref _affectedUserId, Selectors.AffectedUserId); + set => SetPropertyValueAndDetectChanges(value, ref _affectedUserId, nameof(AffectedUserId)); } /// public string AffectedDetails { get => _affectedDetails; - set => SetPropertyValueAndDetectChanges(value, ref _affectedDetails, Selectors.AffectedDetails); + set => SetPropertyValueAndDetectChanges(value, ref _affectedDetails, nameof(AffectedDetails)); } /// public string EventType { get => _eventType; - set => SetPropertyValueAndDetectChanges(value, ref _eventType, Selectors.EventType); + set => SetPropertyValueAndDetectChanges(value, ref _eventType, nameof(EventType)); } /// public string EventDetails { get => _eventDetails; - set => SetPropertyValueAndDetectChanges(value, ref _eventDetails, Selectors.EventDetails); + set => SetPropertyValueAndDetectChanges(value, ref _eventDetails, nameof(EventDetails)); } } } diff --git a/src/Umbraco.Core/Models/Consent.cs b/src/Umbraco.Core/Models/Consent.cs index 87dd9767a0..cca1db41f1 100644 --- a/src/Umbraco.Core/Models/Consent.cs +++ b/src/Umbraco.Core/Models/Consent.cs @@ -13,33 +13,18 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] internal class Consent : EntityBase, IConsent { - private static PropertySelectors _selector; - private bool _current; private string _source; private string _context; private string _action; private ConsentState _state; private string _comment; - - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo Current = ExpressionHelper.GetPropertyInfo(x => x.Current); - public readonly PropertyInfo Source = ExpressionHelper.GetPropertyInfo(x => x.Source); - public readonly PropertyInfo Context = ExpressionHelper.GetPropertyInfo(x => x.Context); - public readonly PropertyInfo Action = ExpressionHelper.GetPropertyInfo(x => x.Action); - public readonly PropertyInfo State = ExpressionHelper.GetPropertyInfo(x => x.State); - public readonly PropertyInfo Comment = ExpressionHelper.GetPropertyInfo(x => x.Comment); - } - - private static PropertySelectors Selectors => _selector ?? (_selector = new PropertySelectors()); - + /// public bool Current { get => _current; - set => SetPropertyValueAndDetectChanges(value, ref _current, Selectors.Current); + set => SetPropertyValueAndDetectChanges(value, ref _current, nameof(Current)); } /// @@ -49,7 +34,7 @@ namespace Umbraco.Core.Models set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(nameof(value)); - SetPropertyValueAndDetectChanges(value, ref _source, Selectors.Source); + SetPropertyValueAndDetectChanges(value, ref _source, nameof(Source)); } } @@ -60,7 +45,7 @@ namespace Umbraco.Core.Models set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(nameof(value)); - SetPropertyValueAndDetectChanges(value, ref _context, Selectors.Context); + SetPropertyValueAndDetectChanges(value, ref _context, nameof(Context)); } } @@ -71,7 +56,7 @@ namespace Umbraco.Core.Models set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(nameof(value)); - SetPropertyValueAndDetectChanges(value, ref _action, Selectors.Action); + SetPropertyValueAndDetectChanges(value, ref _action, nameof(Action)); } } @@ -81,14 +66,14 @@ namespace Umbraco.Core.Models get => _state; // note: we probably should validate the state here, but since the // enum is [Flags] with many combinations, this could be expensive - set => SetPropertyValueAndDetectChanges(value, ref _state, Selectors.State); + set => SetPropertyValueAndDetectChanges(value, ref _state, nameof(State)); } /// public string Comment { get => _comment; - set => SetPropertyValueAndDetectChanges(value, ref _comment, Selectors.Comment); + set => SetPropertyValueAndDetectChanges(value, ref _comment, nameof(Comment)); } /// diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 16b28e088a..4fda1ff23d 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -23,8 +23,6 @@ namespace Umbraco.Core.Models private ContentCultureInfosCollection _publishInfosOrig; private HashSet _editedCultures; - private static readonly Lazy Ps = new Lazy(); - /// /// Constructor for creating a Content object /// @@ -81,15 +79,6 @@ namespace Umbraco.Core.Models PublishedVersionId = 0; } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo TemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.TemplateId); - public readonly PropertyInfo PublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.Published); - public readonly PropertyInfo ContentScheduleSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentSchedule); - public readonly PropertyInfo PublishCultureInfosSelector = ExpressionHelper.GetPropertyInfo>(x => x.PublishCultureInfos); - } - /// [DoNotClone] public ContentScheduleCollection ContentSchedule @@ -107,7 +96,7 @@ namespace Umbraco.Core.Models { if(_schedule != null) _schedule.CollectionChanged -= ScheduleCollectionChanged; - SetPropertyValueAndDetectChanges(value, ref _schedule, Ps.Value.ContentScheduleSelector); + SetPropertyValueAndDetectChanges(value, ref _schedule, nameof(ContentSchedule)); if (_schedule != null) _schedule.CollectionChanged += ScheduleCollectionChanged; } @@ -120,7 +109,7 @@ namespace Umbraco.Core.Models /// private void ScheduleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.ContentScheduleSelector); + OnPropertyChanged(nameof(ContentSchedule)); } /// @@ -135,7 +124,7 @@ namespace Umbraco.Core.Models public int? TemplateId { get => _templateId; - set => SetPropertyValueAndDetectChanges(value, ref _templateId, Ps.Value.TemplateSelector); + set => SetPropertyValueAndDetectChanges(value, ref _templateId, nameof(TemplateId)); } /// @@ -151,7 +140,7 @@ namespace Umbraco.Core.Models // - the ContentRepository when updating a content entity internal set { - SetPropertyValueAndDetectChanges(value, ref _published, Ps.Value.PublishedSelector); + SetPropertyValueAndDetectChanges(value, ref _published, nameof(Published)); _publishedState = _published ? PublishedState.Published : PublishedState.Unpublished; } } @@ -332,7 +321,7 @@ namespace Umbraco.Core.Models /// private void PublishNamesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PublishCultureInfosSelector); + OnPropertyChanged(nameof(PublishCultureInfos)); } [IgnoreDataMember] diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index ca1152a9a4..705fa2cfb0 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -19,7 +19,6 @@ namespace Umbraco.Core.Models public abstract class ContentBase : TreeEntityBase, IContentBase { protected static readonly ContentCultureInfosCollection NoInfos = new ContentCultureInfosCollection(); - private static readonly Lazy Ps = new Lazy(); private int _contentTypeId; protected IContentTypeComposition ContentTypeBase; @@ -62,18 +61,9 @@ namespace Umbraco.Core.Models _properties.EnsurePropertyTypes(PropertyTypes); } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeId); - public readonly PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.Properties); - public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo(x => x.WriterId); - public readonly PropertyInfo CultureInfosSelector = ExpressionHelper.GetPropertyInfo>(x => x.CultureInfos); - } - protected void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PropertyCollectionSelector); + OnPropertyChanged(nameof(Properties)); } /// @@ -83,7 +73,7 @@ namespace Umbraco.Core.Models public virtual int WriterId { get => _writerId; - set => SetPropertyValueAndDetectChanges(value, ref _writerId, Ps.Value.WriterSelector); + set => SetPropertyValueAndDetectChanges(value, ref _writerId, nameof(WriterId)); } [IgnoreDataMember] @@ -105,7 +95,7 @@ namespace Umbraco.Core.Models } return _contentTypeId; } - protected set => SetPropertyValueAndDetectChanges(value, ref _contentTypeId, Ps.Value.DefaultContentTypeIdSelector); + protected set => SetPropertyValueAndDetectChanges(value, ref _contentTypeId, nameof(ContentTypeId)); } /// @@ -251,7 +241,7 @@ namespace Umbraco.Core.Models /// private void CultureInfosCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.CultureInfosSelector); + OnPropertyChanged(nameof(CultureInfos)); } #endregion diff --git a/src/Umbraco.Core/Models/ContentCultureInfos.cs b/src/Umbraco.Core/Models/ContentCultureInfos.cs index f51e3a275a..a0a4a7c472 100644 --- a/src/Umbraco.Core/Models/ContentCultureInfos.cs +++ b/src/Umbraco.Core/Models/ContentCultureInfos.cs @@ -13,8 +13,7 @@ namespace Umbraco.Core.Models { private DateTime _date; private string _name; - private static readonly Lazy Ps = new Lazy(); - + /// /// Initializes a new instance of the class. /// @@ -46,7 +45,7 @@ namespace Umbraco.Core.Models public string Name { get => _name; - set => SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -55,7 +54,7 @@ namespace Umbraco.Core.Models public DateTime Date { get => _date; - set => SetPropertyValueAndDetectChanges(value, ref _date, Ps.Value.DateSelector); + set => SetPropertyValueAndDetectChanges(value, ref _date, nameof(Date)); } /// @@ -102,12 +101,6 @@ namespace Umbraco.Core.Models Deconstruct(out culture, out name); date = Date; } - - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo DateSelector = ExpressionHelper.GetPropertyInfo(x => x.Date); - } + } } diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs index 4b9831682c..97534835d1 100644 --- a/src/Umbraco.Core/Models/ContentType.cs +++ b/src/Umbraco.Core/Models/ContentType.cs @@ -13,7 +13,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class ContentType : ContentTypeCompositionBase, IContentType { - private static readonly Lazy Ps = new Lazy(); public const bool IsPublishingConst = true; private int _defaultTemplate; @@ -45,17 +44,10 @@ namespace Umbraco.Core.Models /// public override bool IsPublishing => IsPublishingConst; - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultTemplateId); - public readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedTemplates); - - //Custom comparer for enumerable - public readonly DelegateEqualityComparer> TemplateComparer = new DelegateEqualityComparer>( - (templates, enumerable) => templates.UnsortedSequenceEqual(enumerable), - templates => templates.GetHashCode()); - } + //Custom comparer for enumerable + private static readonly DelegateEqualityComparer> TemplateComparer = new DelegateEqualityComparer>( + (templates, enumerable) => templates.UnsortedSequenceEqual(enumerable), + templates => templates.GetHashCode()); /// /// Gets or sets the alias of the default Template. @@ -76,7 +68,7 @@ namespace Umbraco.Core.Models internal int DefaultTemplateId { get { return _defaultTemplate; } - set { SetPropertyValueAndDetectChanges(value, ref _defaultTemplate, Ps.Value.DefaultTemplateSelector); } + set { SetPropertyValueAndDetectChanges(value, ref _defaultTemplate, nameof(DefaultTemplateId)); } } /// @@ -91,7 +83,7 @@ namespace Umbraco.Core.Models get => _allowedTemplates; set { - SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector, Ps.Value.TemplateComparer); + SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, nameof(AllowedTemplates), TemplateComparer); if (_allowedTemplates.Any(x => x.Id == _defaultTemplate) == false) DefaultTemplateId = 0; diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 3da2838d0e..3f45f424da 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -18,7 +18,6 @@ namespace Umbraco.Core.Models [DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")] public abstract class ContentTypeBase : TreeEntityBase, IContentTypeBase { - private static readonly Lazy Ps = new Lazy(); private string _alias; private string _description; @@ -83,37 +82,20 @@ namespace Umbraco.Core.Models /// public abstract bool IsPublishing { get; } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo(x => x.Description); - public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon); - public readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.Thumbnail); - public readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot); - public readonly PropertyInfo IsElementSelector = ExpressionHelper.GetPropertyInfo(x => x.IsElement); - public readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer); - public readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes); - public readonly PropertyInfo PropertyGroupsSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups); - public readonly PropertyInfo PropertyTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.PropertyTypes); - public readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPropertyTypeBeenRemoved); - public readonly PropertyInfo VaryBy = ExpressionHelper.GetPropertyInfo(x => x.Variations); - - //Custom comparer for enumerable - public readonly DelegateEqualityComparer> ContentTypeSortComparer = - new DelegateEqualityComparer>( - (sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable), - sorts => sorts.GetHashCode()); - } + //Custom comparer for enumerable + private static readonly DelegateEqualityComparer> ContentTypeSortComparer = + new DelegateEqualityComparer>( + (sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable), + sorts => sorts.GetHashCode()); protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PropertyGroupsSelector); + OnPropertyChanged(nameof(PropertyGroups)); } protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PropertyTypesSelector); + OnPropertyChanged(nameof(PropertyTypes)); } /// @@ -126,7 +108,7 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges( value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase), ref _alias, - Ps.Value.AliasSelector); + nameof(Alias)); } /// @@ -136,7 +118,7 @@ namespace Umbraco.Core.Models public string Description { get => _description; - set => SetPropertyValueAndDetectChanges(value, ref _description, Ps.Value.DescriptionSelector); + set => SetPropertyValueAndDetectChanges(value, ref _description, nameof(Description)); } /// @@ -146,7 +128,7 @@ namespace Umbraco.Core.Models public string Icon { get => _icon; - set => SetPropertyValueAndDetectChanges(value, ref _icon, Ps.Value.IconSelector); + set => SetPropertyValueAndDetectChanges(value, ref _icon, nameof(Icon)); } /// @@ -156,7 +138,7 @@ namespace Umbraco.Core.Models public string Thumbnail { get => _thumbnail; - set => SetPropertyValueAndDetectChanges(value, ref _thumbnail, Ps.Value.ThumbnailSelector); + set => SetPropertyValueAndDetectChanges(value, ref _thumbnail, nameof(Thumbnail)); } /// @@ -166,7 +148,7 @@ namespace Umbraco.Core.Models public bool AllowedAsRoot { get => _allowedAsRoot; - set => SetPropertyValueAndDetectChanges(value, ref _allowedAsRoot, Ps.Value.AllowedAsRootSelector); + set => SetPropertyValueAndDetectChanges(value, ref _allowedAsRoot, nameof(AllowedAsRoot)); } /// @@ -179,7 +161,7 @@ namespace Umbraco.Core.Models public bool IsContainer { get => _isContainer; - set => SetPropertyValueAndDetectChanges(value, ref _isContainer, Ps.Value.IsContainerSelector); + set => SetPropertyValueAndDetectChanges(value, ref _isContainer, nameof(IsContainer)); } /// @@ -187,7 +169,7 @@ namespace Umbraco.Core.Models public bool IsElement { get => _isElement; - set => SetPropertyValueAndDetectChanges(value, ref _isElement, Ps.Value.IsElementSelector); + set => SetPropertyValueAndDetectChanges(value, ref _isElement, nameof(IsElement)); } /// @@ -197,8 +179,8 @@ namespace Umbraco.Core.Models public IEnumerable AllowedContentTypes { get => _allowedContentTypes; - set => SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, Ps.Value.AllowedContentTypesSelector, - Ps.Value.ContentTypeSortComparer); + set => SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, nameof(AllowedContentTypes), + ContentTypeSortComparer); } /// @@ -207,7 +189,7 @@ namespace Umbraco.Core.Models public virtual ContentVariation Variations { get => _variations; - set => SetPropertyValueAndDetectChanges(value, ref _variations, Ps.Value.VaryBy); + set => SetPropertyValueAndDetectChanges(value, ref _variations, nameof(Variations)); } /// @@ -295,7 +277,7 @@ namespace Umbraco.Core.Models private set { _hasPropertyTypeBeenRemoved = value; - OnPropertyChanged(Ps.Value.HasPropertyTypeBeenRemovedSelector); + OnPropertyChanged(nameof(HasPropertyTypeBeenRemoved)); } } @@ -388,7 +370,7 @@ namespace Umbraco.Core.Models if (!HasPropertyTypeBeenRemoved) { HasPropertyTypeBeenRemoved = true; - OnPropertyChanged(Ps.Value.PropertyTypesSelector); + OnPropertyChanged(nameof(PropertyTypes)); } break; } @@ -400,7 +382,7 @@ namespace Umbraco.Core.Models if (!HasPropertyTypeBeenRemoved) { HasPropertyTypeBeenRemoved = true; - OnPropertyChanged(Ps.Value.PropertyTypesSelector); + OnPropertyChanged(nameof(PropertyTypes)); } } } @@ -424,7 +406,7 @@ namespace Umbraco.Core.Models // actually remove the group PropertyGroups.RemoveItem(propertyGroupName); - OnPropertyChanged(Ps.Value.PropertyGroupsSelector); + OnPropertyChanged(nameof(PropertyGroups)); } /// diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs index 08b9f74802..7a8e91845a 100644 --- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs @@ -14,8 +14,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition { - private static readonly Lazy Ps = new Lazy(); - private List _contentTypeComposition = new List(); internal List RemovedContentTypeKeyTracker = new List(); @@ -32,13 +30,6 @@ namespace Umbraco.Core.Models AddContentType(parent); } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo ContentTypeCompositionSelector = - ExpressionHelper.GetPropertyInfo>(x => x.ContentTypeComposition); - } - /// /// Gets or sets the content types that compose this content type. /// @@ -49,7 +40,7 @@ namespace Umbraco.Core.Models set { _contentTypeComposition = value.ToList(); - OnPropertyChanged(Ps.Value.ContentTypeCompositionSelector); + OnPropertyChanged(nameof(ContentTypeComposition)); } } @@ -161,7 +152,7 @@ namespace Umbraco.Core.Models throw new InvalidCompositionException(Alias, contentType.Alias, conflictingPropertyTypeAliases.ToArray()); _contentTypeComposition.Add(contentType); - OnPropertyChanged(Ps.Value.ContentTypeCompositionSelector); + OnPropertyChanged(nameof(ContentTypeComposition)); return true; } return false; @@ -187,7 +178,7 @@ namespace Umbraco.Core.Models if (compositionIdsToRemove.Any()) RemovedContentTypeKeyTracker.AddRange(compositionIdsToRemove); - OnPropertyChanged(Ps.Value.ContentTypeCompositionSelector); + OnPropertyChanged(nameof(ContentTypeComposition)); return _contentTypeComposition.Remove(contentTypeComposition); } return false; diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs index 4f0d0d6c31..423895b475 100644 --- a/src/Umbraco.Core/Models/DataType.cs +++ b/src/Umbraco.Core/Models/DataType.cs @@ -15,8 +15,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class DataType : TreeEntityBase, IDataType { - private static PropertySelectors _selectors; - private IDataEditor _editor; private ValueStorageType _databaseType; private object _configuration; @@ -35,15 +33,6 @@ namespace Umbraco.Core.Models Configuration = _editor.GetConfigurationEditor().DefaultConfigurationObject; } - private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); - - private class PropertySelectors - { - public readonly PropertyInfo Editor = ExpressionHelper.GetPropertyInfo(x => x.Editor); - public readonly PropertyInfo DatabaseType = ExpressionHelper.GetPropertyInfo(x => x.DatabaseType); - public readonly PropertyInfo Configuration = ExpressionHelper.GetPropertyInfo(x => x.Configuration); - } - /// [IgnoreDataMember] public IDataEditor Editor @@ -53,7 +42,7 @@ namespace Umbraco.Core.Models { // ignore if no change if (_editor.Alias == value.Alias) return; - OnPropertyChanged(Selectors.Editor); + OnPropertyChanged(nameof(Editor)); // try to map the existing configuration to the new configuration // simulate saving to db and reloading (ie go via json) @@ -73,7 +62,7 @@ namespace Umbraco.Core.Models public ValueStorageType DatabaseType { get => _databaseType; - set => SetPropertyValueAndDetectChanges(value, ref _databaseType, Selectors.DatabaseType); + set => SetPropertyValueAndDetectChanges(value, ref _databaseType, nameof(DatabaseType)); } /// @@ -124,7 +113,7 @@ namespace Umbraco.Core.Models _configurationJson = null; // it's always a change - OnPropertyChanged(Selectors.Configuration); + OnPropertyChanged(nameof(Configuration)); } } diff --git a/src/Umbraco.Core/Models/DictionaryItem.cs b/src/Umbraco.Core/Models/DictionaryItem.cs index 919f1b0a1f..00c4e1a96c 100644 --- a/src/Umbraco.Core/Models/DictionaryItem.cs +++ b/src/Umbraco.Core/Models/DictionaryItem.cs @@ -30,20 +30,11 @@ namespace Umbraco.Core.Models _translations = new List(); } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId); - public readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ItemKey); - public readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Translations); - - //Custom comparer for enumerable - public readonly DelegateEqualityComparer> DictionaryTranslationComparer = - new DelegateEqualityComparer>( - (enumerable, translations) => enumerable.UnsortedSequenceEqual(translations), - enumerable => enumerable.GetHashCode()); - } + //Custom comparer for enumerable + private static readonly DelegateEqualityComparer> DictionaryTranslationComparer = + new DelegateEqualityComparer>( + (enumerable, translations) => enumerable.UnsortedSequenceEqual(translations), + enumerable => enumerable.GetHashCode()); /// /// Gets or Sets the Parent Id of the Dictionary Item @@ -52,7 +43,7 @@ namespace Umbraco.Core.Models public Guid? ParentId { get { return _parentId; } - set { SetPropertyValueAndDetectChanges(value, ref _parentId, Ps.Value.ParentIdSelector); } + set { SetPropertyValueAndDetectChanges(value, ref _parentId, nameof(ParentId)); } } /// @@ -62,7 +53,7 @@ namespace Umbraco.Core.Models public string ItemKey { get { return _itemKey; } - set { SetPropertyValueAndDetectChanges(value, ref _itemKey, Ps.Value.ItemKeySelector); } + set { SetPropertyValueAndDetectChanges(value, ref _itemKey, nameof(ItemKey)); } } /// @@ -84,8 +75,8 @@ namespace Umbraco.Core.Models } } - SetPropertyValueAndDetectChanges(asArray, ref _translations, Ps.Value.TranslationsSelector, - Ps.Value.DictionaryTranslationComparer); + SetPropertyValueAndDetectChanges(asArray, ref _translations, nameof(Translations), + DictionaryTranslationComparer); } } } diff --git a/src/Umbraco.Core/Models/DictionaryTranslation.cs b/src/Umbraco.Core/Models/DictionaryTranslation.cs index c3b5a8a3b2..51c7ff2800 100644 --- a/src/Umbraco.Core/Models/DictionaryTranslation.cs +++ b/src/Umbraco.Core/Models/DictionaryTranslation.cs @@ -50,13 +50,6 @@ namespace Umbraco.Core.Models Key = uniqueId; } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language); - public readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo(x => x.Value); - } /// /// Gets or sets the for the translation @@ -84,7 +77,7 @@ namespace Umbraco.Core.Models } set { - SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector); + SetPropertyValueAndDetectChanges(value, ref _language, nameof(Language)); _languageId = _language == null ? -1 : _language.Id; } } @@ -101,7 +94,7 @@ namespace Umbraco.Core.Models public string Value { get { return _value; } - set { SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector); } + set { SetPropertyValueAndDetectChanges(value, ref _value, nameof(Value)); } } protected override void PerformDeepClone(object clone) diff --git a/src/Umbraco.Core/Models/Entities/BeingDirty.cs b/src/Umbraco.Core/Models/Entities/BeingDirty.cs index ec447a62dc..4e6d0cf5e3 100644 --- a/src/Umbraco.Core/Models/Entities/BeingDirty.cs +++ b/src/Umbraco.Core/Models/Entities/BeingDirty.cs @@ -19,19 +19,19 @@ namespace Umbraco.Core.Models.Entities /// The type of the value. /// The new value. /// A reference to the value to set. - /// The property selector. + /// The property selector. /// A comparer to compare property values. - public new void SetPropertyValueAndDetectChanges(T value, ref T valueRef, PropertyInfo propertySelector, IEqualityComparer comparer = null) + public new void SetPropertyValueAndDetectChanges(T value, ref T valueRef, string propertyName, IEqualityComparer comparer = null) { - base.SetPropertyValueAndDetectChanges(value, ref valueRef, propertySelector, comparer); + base.SetPropertyValueAndDetectChanges(value, ref valueRef, propertyName, comparer); } /// /// Registers that a property has changed. /// - public new void OnPropertyChanged(PropertyInfo propertySelector) + public new void OnPropertyChanged(string propertyName) { - base.OnPropertyChanged(propertySelector); + base.OnPropertyChanged(propertyName); } } } diff --git a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs index 711b7c9b9f..d9db433217 100644 --- a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs +++ b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs @@ -108,7 +108,7 @@ namespace Umbraco.Core.Models.Entities /// /// Registers that a property has changed. /// - protected virtual void OnPropertyChanged(PropertyInfo propertyInfo) + protected virtual void OnPropertyChanged(string propertyName) { if (_withChanges == false) return; @@ -116,9 +116,9 @@ namespace Umbraco.Core.Models.Entities if (_currentChanges == null) _currentChanges = new Dictionary(); - _currentChanges[propertyInfo.Name] = true; + _currentChanges[propertyName] = true; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyInfo.Name)); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } /// @@ -143,9 +143,9 @@ namespace Umbraco.Core.Models.Entities /// The type of the value. /// The new value. /// A reference to the value to set. - /// The property selector. + /// The property selector. /// A comparer to compare property values. - protected void SetPropertyValueAndDetectChanges(T value, ref T valueRef, PropertyInfo propertySelector, IEqualityComparer comparer = null) + protected void SetPropertyValueAndDetectChanges(T value, ref T valueRef, string propertyName, IEqualityComparer comparer = null) { if (comparer == null) { @@ -165,7 +165,7 @@ namespace Umbraco.Core.Models.Entities // handle change if (changed) - OnPropertyChanged(propertySelector); + OnPropertyChanged(propertyName); } /// @@ -174,17 +174,17 @@ namespace Umbraco.Core.Models.Entities /// The type of the value. /// The new value. /// The original value. - /// The property selector. + /// The property name. /// A comparer to compare property values. /// A value indicating whether we know values have changed and no comparison is required. - protected void DetectChanges(T value, T orig, PropertyInfo propertySelector, IEqualityComparer comparer, bool changed) + protected void DetectChanges(T value, T orig, string propertyName, IEqualityComparer comparer, bool changed) { // compare values changed = _withChanges && (changed || !comparer.Equals(orig, value)); // handle change if (changed) - OnPropertyChanged(propertySelector); + OnPropertyChanged(propertyName); } #endregion diff --git a/src/Umbraco.Core/Models/Entities/EntityBase.cs b/src/Umbraco.Core/Models/Entities/EntityBase.cs index 6c9bf3d711..ef90f5e28d 100644 --- a/src/Umbraco.Core/Models/Entities/EntityBase.cs +++ b/src/Umbraco.Core/Models/Entities/EntityBase.cs @@ -17,23 +17,12 @@ namespace Umbraco.Core.Models.Entities public Guid InstanceId = Guid.NewGuid(); #endif - private static readonly Lazy Ps = new Lazy(); - private bool _hasIdentity; private int _id; private Guid _key; private DateTime _createDate; private DateTime _updateDate; - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo(x => x.Id); - public readonly PropertyInfo KeySelector = ExpressionHelper.GetPropertyInfo(x => x.Key); - public readonly PropertyInfo CreateDateSelector = ExpressionHelper.GetPropertyInfo(x => x.CreateDate); - public readonly PropertyInfo UpdateDateSelector = ExpressionHelper.GetPropertyInfo(x => x.UpdateDate); - } - /// [DataMember] public int Id @@ -41,7 +30,7 @@ namespace Umbraco.Core.Models.Entities get => _id; set { - SetPropertyValueAndDetectChanges(value, ref _id, Ps.Value.IdSelector); + SetPropertyValueAndDetectChanges(value, ref _id, nameof(Id)); _hasIdentity = value != 0; } } @@ -57,7 +46,7 @@ namespace Umbraco.Core.Models.Entities _key = Guid.NewGuid(); return _key; } - set => SetPropertyValueAndDetectChanges(value, ref _key, Ps.Value.KeySelector); + set => SetPropertyValueAndDetectChanges(value, ref _key, nameof(Key)); } /// @@ -65,7 +54,7 @@ namespace Umbraco.Core.Models.Entities public DateTime CreateDate { get => _createDate; - set => SetPropertyValueAndDetectChanges(value, ref _createDate, Ps.Value.CreateDateSelector); + set => SetPropertyValueAndDetectChanges(value, ref _createDate, nameof(CreateDate)); } /// @@ -73,7 +62,7 @@ namespace Umbraco.Core.Models.Entities public DateTime UpdateDate { get => _updateDate; - set => SetPropertyValueAndDetectChanges(value, ref _updateDate, Ps.Value.UpdateDateSelector); + set => SetPropertyValueAndDetectChanges(value, ref _updateDate, nameof(UpdateDate)); } /// diff --git a/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs b/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs index 60e06c4977..b8243ed0a9 100644 --- a/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs +++ b/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs @@ -9,9 +9,6 @@ namespace Umbraco.Core.Models.Entities /// public abstract class TreeEntityBase : EntityBase, ITreeEntity { - private static PropertySelectors _selectors; - private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); - private string _name; private int _creatorId; private int _parentId; @@ -22,23 +19,12 @@ namespace Umbraco.Core.Models.Entities private int _sortOrder; private bool _trashed; - private class PropertySelectors - { - public readonly PropertyInfo Name = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo CreatorId = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); - public readonly PropertyInfo ParentId = ExpressionHelper.GetPropertyInfo(x => x.ParentId); - public readonly PropertyInfo Level = ExpressionHelper.GetPropertyInfo(x => x.Level); - public readonly PropertyInfo Path = ExpressionHelper.GetPropertyInfo(x => x.Path); - public readonly PropertyInfo SortOrder = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); - public readonly PropertyInfo Trashed = ExpressionHelper.GetPropertyInfo(x => x.Trashed); - } - /// [DataMember] public string Name { get => _name; - set => SetPropertyValueAndDetectChanges(value, ref _name, Selectors.Name); + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -46,7 +32,7 @@ namespace Umbraco.Core.Models.Entities public int CreatorId { get => _creatorId; - set => SetPropertyValueAndDetectChanges(value, ref _creatorId, Selectors.CreatorId); + set => SetPropertyValueAndDetectChanges(value, ref _creatorId, nameof(CreatorId)); } /// @@ -72,7 +58,7 @@ namespace Umbraco.Core.Models.Entities { if (value == 0) throw new ArgumentException("Value cannot be zero.", nameof(value)); - SetPropertyValueAndDetectChanges(value, ref _parentId, Selectors.ParentId); + SetPropertyValueAndDetectChanges(value, ref _parentId, nameof(ParentId)); _hasParentId = true; _parent = null; } @@ -83,7 +69,7 @@ namespace Umbraco.Core.Models.Entities { _hasParentId = false; _parent = parent; - OnPropertyChanged(Selectors.ParentId); + OnPropertyChanged(nameof(ParentId)); } /// @@ -91,7 +77,7 @@ namespace Umbraco.Core.Models.Entities public int Level { get => _level; - set => SetPropertyValueAndDetectChanges(value, ref _level, Selectors.Level); + set => SetPropertyValueAndDetectChanges(value, ref _level, nameof(Level)); } /// @@ -99,7 +85,7 @@ namespace Umbraco.Core.Models.Entities public string Path { get => _path; - set => SetPropertyValueAndDetectChanges(value, ref _path, Selectors.Path); + set => SetPropertyValueAndDetectChanges(value, ref _path, nameof(Path)); } /// @@ -107,7 +93,7 @@ namespace Umbraco.Core.Models.Entities public int SortOrder { get => _sortOrder; - set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, Selectors.SortOrder); + set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, nameof(SortOrder)); } /// @@ -115,7 +101,7 @@ namespace Umbraco.Core.Models.Entities public bool Trashed { get => _trashed; - set => SetPropertyValueAndDetectChanges(value, ref _trashed, Selectors.Trashed); + set => SetPropertyValueAndDetectChanges(value, ref _trashed, nameof(Trashed)); } } } diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs index 2f8e021f4c..494dcbe6fc 100644 --- a/src/Umbraco.Core/Models/File.cs +++ b/src/Umbraco.Core/Models/File.cs @@ -33,14 +33,6 @@ namespace Umbraco.Core.Models _content = getFileContent != null ? null : string.Empty; } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo(x => x.Content); - public readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path); - } - private string _alias; private string _name; @@ -96,7 +88,7 @@ namespace Umbraco.Core.Models _alias = null; _name = null; - SetPropertyValueAndDetectChanges(SanitizePath(value), ref _path, Ps.Value.PathSelector); + SetPropertyValueAndDetectChanges(SanitizePath(value), ref _path, nameof(Path)); } } @@ -138,7 +130,7 @@ namespace Umbraco.Core.Models { SetPropertyValueAndDetectChanges( value ?? string.Empty, // cannot set to null - ref _content, Ps.Value.ContentSelector); + ref _content, nameof(Content)); } } diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index f5c21a3a74..084db81f11 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -16,7 +16,6 @@ namespace Umbraco.Core.Models.Identity { public class BackOfficeIdentityUser : IdentityUser, IdentityUserClaim>, IRememberBeingDirty { - private static readonly Lazy Ps = new Lazy(); private string _email; private string _userName; @@ -118,7 +117,7 @@ namespace Umbraco.Core.Models.Identity public override string Email { get => _email; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _email, nameof(Email)); } /// @@ -127,7 +126,7 @@ namespace Umbraco.Core.Models.Identity public override string UserName { get => _userName; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _userName, Ps.Value.UserNameSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _userName, nameof(UserName)); } /// @@ -136,7 +135,7 @@ namespace Umbraco.Core.Models.Identity public override DateTime? LastPasswordChangeDateUtc { get { return _lastPasswordChangeDateUtc; } - set { _beingDirty.SetPropertyValueAndDetectChanges(value, ref _lastPasswordChangeDateUtc, Ps.Value.LastPasswordChangeDateUtcSelector); } + set { _beingDirty.SetPropertyValueAndDetectChanges(value, ref _lastPasswordChangeDateUtc, nameof(LastPasswordChangeDateUtc)); } } /// @@ -145,7 +144,7 @@ namespace Umbraco.Core.Models.Identity public override DateTime? LastLoginDateUtc { get => _lastLoginDateUtc; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _lastLoginDateUtc, Ps.Value.LastLoginDateUtcSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _lastLoginDateUtc, nameof(LastLoginDateUtc)); } /// @@ -154,7 +153,7 @@ namespace Umbraco.Core.Models.Identity public override bool EmailConfirmed { get => _emailConfirmed; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _emailConfirmed, Ps.Value.EmailConfirmedSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _emailConfirmed, nameof(EmailConfirmed)); } /// @@ -163,7 +162,7 @@ namespace Umbraco.Core.Models.Identity public string Name { get => _name; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -172,7 +171,7 @@ namespace Umbraco.Core.Models.Identity public override int AccessFailedCount { get => _accessFailedCount; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _accessFailedCount, Ps.Value.AccessFailedCountSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _accessFailedCount, nameof(AccessFailedCount)); } /// @@ -181,7 +180,7 @@ namespace Umbraco.Core.Models.Identity public override string PasswordHash { get => _passwordHash; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _passwordHash, Ps.Value.PasswordHashSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _passwordHash, nameof(PasswordHash)); } @@ -194,7 +193,7 @@ namespace Umbraco.Core.Models.Identity set { if (value == null) value = new int[0]; - _beingDirty.SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdsSelector, Ps.Value.StartIdsComparer); + _beingDirty.SetPropertyValueAndDetectChanges(value, ref _startContentIds, nameof(StartContentIds), StartIdsComparer); } } @@ -207,7 +206,7 @@ namespace Umbraco.Core.Models.Identity set { if (value == null) value = new int[0]; - _beingDirty.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdsSelector, Ps.Value.StartIdsComparer); + _beingDirty.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, nameof(StartMediaIds), StartIdsComparer); } } @@ -222,7 +221,7 @@ namespace Umbraco.Core.Models.Identity public string Culture { get => _culture; - set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _culture, nameof(Culture)); } public IReadOnlyUserGroup[] Groups @@ -246,7 +245,7 @@ namespace Umbraco.Core.Models.Identity } _roles.CollectionChanged += _roles_CollectionChanged; - _beingDirty.SetPropertyValueAndDetectChanges(value, ref _groups, Ps.Value.GroupsSelector, Ps.Value.GroupsComparer); + _beingDirty.SetPropertyValueAndDetectChanges(value, ref _groups, nameof(Groups), GroupsComparer); } } @@ -302,12 +301,12 @@ namespace Umbraco.Core.Models.Identity void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - _beingDirty.OnPropertyChanged(Ps.Value.LoginsSelector); + _beingDirty.OnPropertyChanged(nameof(Logins)); } private void _roles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - _beingDirty.OnPropertyChanged(Ps.Value.RolesSelector); + _beingDirty.OnPropertyChanged(nameof(Roles)); } private readonly ObservableCollection> _roles; @@ -416,33 +415,13 @@ namespace Umbraco.Core.Models.Identity #endregion - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo(x => x.Email); - public readonly PropertyInfo UserNameSelector = ExpressionHelper.GetPropertyInfo(x => x.UserName); - public readonly PropertyInfo LastLoginDateUtcSelector = ExpressionHelper.GetPropertyInfo(x => x.LastLoginDateUtc); - public readonly PropertyInfo LastPasswordChangeDateUtcSelector = ExpressionHelper.GetPropertyInfo(x => x.LastPasswordChangeDateUtc); - public readonly PropertyInfo EmailConfirmedSelector = ExpressionHelper.GetPropertyInfo(x => x.EmailConfirmed); - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo AccessFailedCountSelector = ExpressionHelper.GetPropertyInfo(x => x.AccessFailedCount); - public readonly PropertyInfo PasswordHashSelector = ExpressionHelper.GetPropertyInfo(x => x.PasswordHash); - public readonly PropertyInfo CultureSelector = ExpressionHelper.GetPropertyInfo(x => x.Culture); - public readonly PropertyInfo StartMediaIdsSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaIds); - public readonly PropertyInfo StartContentIdsSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentIds); - public readonly PropertyInfo GroupsSelector = ExpressionHelper.GetPropertyInfo(x => x.Groups); - public readonly PropertyInfo LoginsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Logins); - public readonly PropertyInfo RolesSelector = ExpressionHelper.GetPropertyInfo>>(x => x.Roles); - - //Custom comparer for enumerables - public readonly DelegateEqualityComparer GroupsComparer = new DelegateEqualityComparer( - (groups, enumerable) => groups.Select(x => x.Alias).UnsortedSequenceEqual(enumerable.Select(x => x.Alias)), - groups => groups.GetHashCode()); - public readonly DelegateEqualityComparer StartIdsComparer = new DelegateEqualityComparer( - (groups, enumerable) => groups.UnsortedSequenceEqual(enumerable), - groups => groups.GetHashCode()); - - } + //Custom comparer for enumerables + private static readonly DelegateEqualityComparer GroupsComparer = new DelegateEqualityComparer( + (groups, enumerable) => groups.Select(x => x.Alias).UnsortedSequenceEqual(enumerable.Select(x => x.Alias)), + groups => groups.GetHashCode()); + private static readonly DelegateEqualityComparer StartIdsComparer = new DelegateEqualityComparer( + (groups, enumerable) => groups.UnsortedSequenceEqual(enumerable), + groups => groups.GetHashCode()); } } diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs index b02eb4805c..3e4d189abb 100644 --- a/src/Umbraco.Core/Models/Language.cs +++ b/src/Umbraco.Core/Models/Language.cs @@ -16,7 +16,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class Language : EntityBase, ILanguage { - private static readonly Lazy Ps = new Lazy(); private string _isoCode; private string _cultureName; @@ -28,23 +27,13 @@ namespace Umbraco.Core.Models { IsoCode = isoCode; } - - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo IsoCodeSelector = ExpressionHelper.GetPropertyInfo(x => x.IsoCode); - public readonly PropertyInfo CultureNameSelector = ExpressionHelper.GetPropertyInfo(x => x.CultureName); - public readonly PropertyInfo IsDefaultVariantLanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDefault); - public readonly PropertyInfo MandatorySelector = ExpressionHelper.GetPropertyInfo(x => x.IsMandatory); - public readonly PropertyInfo FallbackLanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.FallbackLanguageId); - } - + /// [DataMember] public string IsoCode { get => _isoCode; - set => SetPropertyValueAndDetectChanges(value, ref _isoCode, Ps.Value.IsoCodeSelector); + set => SetPropertyValueAndDetectChanges(value, ref _isoCode, nameof(IsoCode)); } /// @@ -102,7 +91,7 @@ namespace Umbraco.Core.Models } } - set => SetPropertyValueAndDetectChanges(value, ref _cultureName, Ps.Value.CultureNameSelector); + set => SetPropertyValueAndDetectChanges(value, ref _cultureName, nameof(CultureName)); } /// @@ -113,21 +102,21 @@ namespace Umbraco.Core.Models public bool IsDefault { get => _isDefaultVariantLanguage; - set => SetPropertyValueAndDetectChanges(value, ref _isDefaultVariantLanguage, Ps.Value.IsDefaultVariantLanguageSelector); + set => SetPropertyValueAndDetectChanges(value, ref _isDefaultVariantLanguage, nameof(IsDefault)); } /// public bool IsMandatory { get => _mandatory; - set => SetPropertyValueAndDetectChanges(value, ref _mandatory, Ps.Value.MandatorySelector); + set => SetPropertyValueAndDetectChanges(value, ref _mandatory, nameof(IsMandatory)); } /// public int? FallbackLanguageId { get => _fallbackLanguageId; - set => SetPropertyValueAndDetectChanges(value, ref _fallbackLanguageId, Ps.Value.FallbackLanguageSelector); + set => SetPropertyValueAndDetectChanges(value, ref _fallbackLanguageId, nameof(FallbackLanguageId)); } } } diff --git a/src/Umbraco.Core/Models/Macro.cs b/src/Umbraco.Core/Models/Macro.cs index 5ef49305ac..2f29ddecff 100644 --- a/src/Umbraco.Core/Models/Macro.cs +++ b/src/Umbraco.Core/Models/Macro.cs @@ -117,7 +117,7 @@ namespace Umbraco.Core.Models void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PropertiesSelector); + OnPropertyChanged(nameof(Properties)); if (e.Action == NotifyCollectionChangedAction.Add) { @@ -155,7 +155,7 @@ namespace Umbraco.Core.Models /// void PropertyDataChanged(object sender, PropertyChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PropertiesSelector); + OnPropertyChanged(nameof(Properties)); } public override void ResetDirtyProperties(bool rememberDirty) @@ -172,18 +172,12 @@ namespace Umbraco.Core.Models /// /// Used internally to check if we need to add a section in the repository to the db /// - internal IEnumerable AddedProperties - { - get { return _addedProperties; } - } + internal IEnumerable AddedProperties => _addedProperties; /// /// Used internally to check if we need to remove a section in the repository to the db /// - internal IEnumerable RemovedProperties - { - get { return _removedProperties; } - } + internal IEnumerable RemovedProperties => _removedProperties; /// /// Gets or sets the alias of the Macro @@ -191,8 +185,8 @@ namespace Umbraco.Core.Models [DataMember] public string Alias { - get { return _alias; } - set { SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.Alias), ref _alias, Ps.Value.AliasSelector); } + get => _alias; + set => SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.Alias), ref _alias, nameof(Alias)); } /// @@ -201,8 +195,8 @@ namespace Umbraco.Core.Models [DataMember] public string Name { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } + get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -211,8 +205,8 @@ namespace Umbraco.Core.Models [DataMember] public bool UseInEditor { - get { return _useInEditor; } - set { SetPropertyValueAndDetectChanges(value, ref _useInEditor, Ps.Value.UseInEditorSelector); } + get => _useInEditor; + set => SetPropertyValueAndDetectChanges(value, ref _useInEditor, nameof(UseInEditor)); } /// @@ -221,8 +215,8 @@ namespace Umbraco.Core.Models [DataMember] public int CacheDuration { - get { return _cacheDuration; } - set { SetPropertyValueAndDetectChanges(value, ref _cacheDuration, Ps.Value.CacheDurationSelector); } + get => _cacheDuration; + set => SetPropertyValueAndDetectChanges(value, ref _cacheDuration, nameof(CacheDuration)); } /// @@ -231,8 +225,8 @@ namespace Umbraco.Core.Models [DataMember] public bool CacheByPage { - get { return _cacheByPage; } - set { SetPropertyValueAndDetectChanges(value, ref _cacheByPage, Ps.Value.CacheByPageSelector); } + get => _cacheByPage; + set => SetPropertyValueAndDetectChanges(value, ref _cacheByPage, nameof(CacheByPage)); } /// @@ -241,8 +235,8 @@ namespace Umbraco.Core.Models [DataMember] public bool CacheByMember { - get { return _cacheByMember; } - set { SetPropertyValueAndDetectChanges(value, ref _cacheByMember, Ps.Value.CacheByMemberSelector); } + get => _cacheByMember; + set => SetPropertyValueAndDetectChanges(value, ref _cacheByMember, nameof(CacheByMember)); } /// @@ -251,8 +245,8 @@ namespace Umbraco.Core.Models [DataMember] public bool DontRender { - get { return _dontRender; } - set { SetPropertyValueAndDetectChanges(value, ref _dontRender, Ps.Value.DontRenderSelector); } + get => _dontRender; + set => SetPropertyValueAndDetectChanges(value, ref _dontRender, nameof(DontRender)); } /// @@ -261,8 +255,8 @@ namespace Umbraco.Core.Models [DataMember] public string MacroSource { - get { return _macroSource; } - set { SetPropertyValueAndDetectChanges(value, ref _macroSource, Ps.Value.ScriptPathSelector); } + get => _macroSource; + set => SetPropertyValueAndDetectChanges(value, ref _macroSource, nameof(MacroSource)); } /// @@ -271,18 +265,15 @@ namespace Umbraco.Core.Models [DataMember] public MacroTypes MacroType { - get { return _macroType; } - set { SetPropertyValueAndDetectChanges(value, ref _macroType, Ps.Value.MacroTypeSelector); } + get => _macroType; + set => SetPropertyValueAndDetectChanges(value, ref _macroType, nameof(MacroType)); } /// /// Gets or sets a list of Macro Properties /// [DataMember] - public MacroPropertyCollection Properties - { - get { return _properties; } - } + public MacroPropertyCollection Properties => _properties; protected override void PerformDeepClone(object clone) { diff --git a/src/Umbraco.Core/Models/MacroProperty.cs b/src/Umbraco.Core/Models/MacroProperty.cs index 380705b3d5..7e269ba635 100644 --- a/src/Umbraco.Core/Models/MacroProperty.cs +++ b/src/Umbraco.Core/Models/MacroProperty.cs @@ -59,27 +59,15 @@ namespace Umbraco.Core.Models private int _sortOrder; private int _id; private string _editorAlias; - - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo KeySelector = ExpressionHelper.GetPropertyInfo(x => x.Key); - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); - public readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo(x => x.Id); - public readonly PropertyInfo PropertyTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.EditorAlias); - } - + /// /// Gets or sets the Key of the Property /// [DataMember] public Guid Key { - get { return _key; } - set { SetPropertyValueAndDetectChanges(value, ref _key, Ps.Value.KeySelector); } + get => _key; + set => SetPropertyValueAndDetectChanges(value, ref _key, nameof(Key)); } /// @@ -88,8 +76,8 @@ namespace Umbraco.Core.Models [DataMember] public int Id { - get { return _id; } - set { SetPropertyValueAndDetectChanges(value, ref _id, Ps.Value.IdSelector); } + get => _id; + set => SetPropertyValueAndDetectChanges(value, ref _id, nameof(Id)); } /// @@ -98,8 +86,8 @@ namespace Umbraco.Core.Models [DataMember] public string Alias { - get { return _alias; } - set { SetPropertyValueAndDetectChanges(value, ref _alias, Ps.Value.AliasSelector); } + get => _alias; + set => SetPropertyValueAndDetectChanges(value, ref _alias, nameof(Alias)); } /// @@ -108,8 +96,8 @@ namespace Umbraco.Core.Models [DataMember] public string Name { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } + get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -118,8 +106,8 @@ namespace Umbraco.Core.Models [DataMember] public int SortOrder { - get { return _sortOrder; } - set { SetPropertyValueAndDetectChanges(value, ref _sortOrder, Ps.Value.SortOrderSelector); } + get => _sortOrder; + set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, nameof(SortOrder)); } /// @@ -132,11 +120,8 @@ namespace Umbraco.Core.Models [DataMember] public string EditorAlias { - get { return _editorAlias; } - set - { - SetPropertyValueAndDetectChanges(value, ref _editorAlias, Ps.Value.PropertyTypeSelector); - } + get => _editorAlias; + set => SetPropertyValueAndDetectChanges(value, ref _editorAlias, nameof(EditorAlias)); } public object DeepClone() diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index 0ef15ee413..06f94b85aa 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -130,25 +130,15 @@ namespace Umbraco.Core.Models _rawPasswordValue = rawPasswordValue; IsApproved = isApproved; } - - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo(x => x.Username); - public readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo(x => x.Email); - public readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo(x => x.RawPasswordValue); - public readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ProviderUserKey); - } - + /// /// Gets or sets the Username /// [DataMember] public string Username { - get { return _username; } - set { SetPropertyValueAndDetectChanges(value, ref _username, Ps.Value.UsernameSelector); } + get => _username; + set => SetPropertyValueAndDetectChanges(value, ref _username, nameof(Username)); } /// @@ -157,8 +147,8 @@ namespace Umbraco.Core.Models [DataMember] public string Email { - get { return _email; } - set { SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); } + get => _email; + set => SetPropertyValueAndDetectChanges(value, ref _email, nameof(Email)); } /// @@ -167,7 +157,7 @@ namespace Umbraco.Core.Models [IgnoreDataMember] public string RawPasswordValue { - get { return _rawPasswordValue; } + get => _rawPasswordValue; set { if (value == null) @@ -178,7 +168,7 @@ namespace Umbraco.Core.Models } else { - SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, Ps.Value.PasswordSelector); + SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, nameof(RawPasswordValue)); } } } @@ -487,10 +477,7 @@ namespace Umbraco.Core.Models /// String alias of the default ContentType /// [DataMember] - public virtual string ContentTypeAlias - { - get { return _contentTypeAlias; } - } + public virtual string ContentTypeAlias => _contentTypeAlias; /// /// User key from the Provider. @@ -504,11 +491,8 @@ namespace Umbraco.Core.Models [DataMember] public virtual object ProviderUserKey { - get - { - return _providerUserKey; - } - set { SetPropertyValueAndDetectChanges(value, ref _providerUserKey, Ps.Value.ProviderUserKeySelector); } + get => _providerUserKey; + set => SetPropertyValueAndDetectChanges(value, ref _providerUserKey, nameof(ProviderUserKey)); } @@ -528,10 +512,7 @@ namespace Umbraco.Core.Models /// Gets the ContentType used by this content object /// [IgnoreDataMember] - public IMemberType ContentType - { - get { return _contentType; } - } + public IMemberType ContentType => _contentType; /* Internal experiment - only used for mapping queries. * Adding these to have first level properties instead of the Properties collection. diff --git a/src/Umbraco.Core/Models/MemberGroup.cs b/src/Umbraco.Core/Models/MemberGroup.cs index 0653f75ef7..69e26c1037 100644 --- a/src/Umbraco.Core/Models/MemberGroup.cs +++ b/src/Umbraco.Core/Models/MemberGroup.cs @@ -13,18 +13,10 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class MemberGroup : EntityBase, IMemberGroup { - private static PropertySelectors _selectors; private IDictionary _additionalData; private string _name; private int _creatorId; - private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); - - private class PropertySelectors - { - public readonly PropertyInfo Name = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo CreatorId = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); - } /// [DataMember] @@ -49,7 +41,7 @@ namespace Umbraco.Core.Models AdditionalData["previousName"] = _name; } - SetPropertyValueAndDetectChanges(value, ref _name, Selectors.Name); + SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } } @@ -57,7 +49,7 @@ namespace Umbraco.Core.Models public int CreatorId { get => _creatorId; - set => SetPropertyValueAndDetectChanges(value, ref _creatorId, Selectors.CreatorId); + set => SetPropertyValueAndDetectChanges(value, ref _creatorId, nameof(CreatorId)); } } } diff --git a/src/Umbraco.Core/Models/MemberType.cs b/src/Umbraco.Core/Models/MemberType.cs index 1ce883d9a7..141cb3b63c 100644 --- a/src/Umbraco.Core/Models/MemberType.cs +++ b/src/Umbraco.Core/Models/MemberType.cs @@ -12,7 +12,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class MemberType : ContentTypeCompositionBase, IMemberType { - private static readonly Lazy Ps = new Lazy(); public const bool IsPublishingConst = false; //Dictionary is divided into string: PropertyTypeAlias, Tuple: MemberCanEdit, VisibleOnProfile, PropertyTypeId @@ -46,12 +45,6 @@ namespace Umbraco.Core.Models set => throw new NotSupportedException("Variations are not supported on members."); } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - } - /// /// The Alias of the ContentType /// @@ -74,7 +67,7 @@ namespace Umbraco.Core.Models ? value : (value == null ? string.Empty : value.ToSafeAlias()); - SetPropertyValueAndDetectChanges(newVal, ref _alias, Ps.Value.AliasSelector); + SetPropertyValueAndDetectChanges(newVal, ref _alias, nameof(Alias)); } } diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 7832390b92..2fb293c349 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -1,14 +1,8 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models.Membership @@ -123,123 +117,92 @@ namespace Umbraco.Core.Models.Membership private IDictionary _additionalData; private object _additionalDataLock = new object(); - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo FailedPasswordAttemptsSelector = ExpressionHelper.GetPropertyInfo(x => x.FailedPasswordAttempts); - public readonly PropertyInfo LastLockoutDateSelector = ExpressionHelper.GetPropertyInfo(x => x.LastLockoutDate); - public readonly PropertyInfo LastLoginDateSelector = ExpressionHelper.GetPropertyInfo(x => x.LastLoginDate); - public readonly PropertyInfo LastPasswordChangeDateSelector = ExpressionHelper.GetPropertyInfo(x => x.LastPasswordChangeDate); - - public readonly PropertyInfo SecurityStampSelector = ExpressionHelper.GetPropertyInfo(x => x.SecurityStamp); - public readonly PropertyInfo AvatarSelector = ExpressionHelper.GetPropertyInfo(x => x.Avatar); - public readonly PropertyInfo TourDataSelector = ExpressionHelper.GetPropertyInfo(x => x.TourData); - public readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo(x => x.SessionTimeout); - public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentIds); - public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaIds); - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - - public readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo(x => x.Username); - public readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo(x => x.Email); - public readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo(x => x.RawPasswordValue); - public readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo(x => x.IsLockedOut); - public readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo(x => x.IsApproved); - public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language); - public readonly PropertyInfo EmailConfirmedDateSelector = ExpressionHelper.GetPropertyInfo(x => x.EmailConfirmedDate); - public readonly PropertyInfo InvitedDateSelector = ExpressionHelper.GetPropertyInfo(x => x.InvitedDate); - - public readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultToLiveEditing); - - public readonly PropertyInfo UserGroupsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Groups); - - //Custom comparer for enumerable - public readonly DelegateEqualityComparer> IntegerEnumerableComparer = - new DelegateEqualityComparer>( - (enum1, enum2) => enum1.UnsortedSequenceEqual(enum2), - enum1 => enum1.GetHashCode()); - } + //Custom comparer for enumerable + private static readonly DelegateEqualityComparer> IntegerEnumerableComparer = + new DelegateEqualityComparer>( + (enum1, enum2) => enum1.UnsortedSequenceEqual(enum2), + enum1 => enum1.GetHashCode()); #region Implementation of IMembershipUser [IgnoreDataMember] public object ProviderUserKey { - get { return Id; } - set { throw new NotSupportedException("Cannot set the provider user key for a user"); } + get => Id; + set => throw new NotSupportedException("Cannot set the provider user key for a user"); } [DataMember] public DateTime? EmailConfirmedDate { - get { return _emailConfirmedDate; } - set { SetPropertyValueAndDetectChanges(value, ref _emailConfirmedDate, Ps.Value.EmailConfirmedDateSelector); } + get => _emailConfirmedDate; + set => SetPropertyValueAndDetectChanges(value, ref _emailConfirmedDate, nameof(EmailConfirmedDate)); } [DataMember] public DateTime? InvitedDate { - get { return _invitedDate; } - set { SetPropertyValueAndDetectChanges(value, ref _invitedDate, Ps.Value.InvitedDateSelector); } + get => _invitedDate; + set => SetPropertyValueAndDetectChanges(value, ref _invitedDate, nameof(InvitedDate)); } [DataMember] public string Username { - get { return _username; } - set { SetPropertyValueAndDetectChanges(value, ref _username, Ps.Value.UsernameSelector); } + get => _username; + set => SetPropertyValueAndDetectChanges(value, ref _username, nameof(Username)); } [DataMember] public string Email { - get { return _email; } - set { SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); } + get => _email; + set => SetPropertyValueAndDetectChanges(value, ref _email, nameof(Email)); } [DataMember] public string RawPasswordValue { - get { return _rawPasswordValue; } - set { SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, Ps.Value.PasswordSelector); } + get => _rawPasswordValue; + set => SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, nameof(RawPasswordValue)); } [DataMember] public bool IsApproved { - get { return _isApproved; } - set { SetPropertyValueAndDetectChanges(value, ref _isApproved, Ps.Value.IsApprovedSelector); } + get => _isApproved; + set => SetPropertyValueAndDetectChanges(value, ref _isApproved, nameof(IsApproved)); } [IgnoreDataMember] public bool IsLockedOut { - get { return _isLockedOut; } - set { SetPropertyValueAndDetectChanges(value, ref _isLockedOut, Ps.Value.IsLockedOutSelector); } + get => _isLockedOut; + set => SetPropertyValueAndDetectChanges(value, ref _isLockedOut, nameof(IsLockedOut)); } [IgnoreDataMember] public DateTime LastLoginDate { - get { return _lastLoginDate; } - set { SetPropertyValueAndDetectChanges(value, ref _lastLoginDate, Ps.Value.LastLoginDateSelector); } + get => _lastLoginDate; + set => SetPropertyValueAndDetectChanges(value, ref _lastLoginDate, nameof(LastLoginDate)); } [IgnoreDataMember] public DateTime LastPasswordChangeDate { - get { return _lastPasswordChangedDate; } - set { SetPropertyValueAndDetectChanges(value, ref _lastPasswordChangedDate, Ps.Value.LastPasswordChangeDateSelector); } + get => _lastPasswordChangedDate; + set => SetPropertyValueAndDetectChanges(value, ref _lastPasswordChangedDate, nameof(LastPasswordChangeDate)); } [IgnoreDataMember] public DateTime LastLockoutDate { - get { return _lastLockoutDate; } - set { SetPropertyValueAndDetectChanges(value, ref _lastLockoutDate, Ps.Value.LastLockoutDateSelector); } + get => _lastLockoutDate; + set => SetPropertyValueAndDetectChanges(value, ref _lastLockoutDate, nameof(LastLockoutDate)); } [IgnoreDataMember] public int FailedPasswordAttempts { - get { return _failedLoginAttempts; } - set { SetPropertyValueAndDetectChanges(value, ref _failedLoginAttempts, Ps.Value.FailedPasswordAttemptsSelector); } + get => _failedLoginAttempts; + set => SetPropertyValueAndDetectChanges(value, ref _failedLoginAttempts, nameof(FailedPasswordAttempts)); } // TODO: Figure out how to support all of this! - we cannot have NotImplementedExceptions because these get used by the IMembershipMemberService service so @@ -279,8 +242,8 @@ namespace Umbraco.Core.Models.Membership [DataMember] public string Name { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } + get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } public IEnumerable AllowedSections @@ -295,10 +258,7 @@ namespace Umbraco.Core.Models.Membership [IgnoreDataMember] internal List GroupsToSave = new List(); - public IProfile ProfileData - { - get { return new WrappedUserProfile(this); } - } + public IProfile ProfileData => new WrappedUserProfile(this); /// /// The security stamp used by ASP.Net identity @@ -306,15 +266,15 @@ namespace Umbraco.Core.Models.Membership [IgnoreDataMember] public string SecurityStamp { - get { return _securityStamp; } - set { SetPropertyValueAndDetectChanges(value, ref _securityStamp, Ps.Value.SecurityStampSelector); } + get => _securityStamp; + set => SetPropertyValueAndDetectChanges(value, ref _securityStamp, nameof(SecurityStamp)); } [DataMember] public string Avatar { - get { return _avatar; } - set { SetPropertyValueAndDetectChanges(value, ref _avatar, Ps.Value.AvatarSelector); } + get => _avatar; + set => SetPropertyValueAndDetectChanges(value, ref _avatar, nameof(Avatar)); } /// @@ -323,8 +283,8 @@ namespace Umbraco.Core.Models.Membership [DataMember] public string TourData { - get { return _tourData; } - set { SetPropertyValueAndDetectChanges(value, ref _tourData, Ps.Value.TourDataSelector); } + get => _tourData; + set => SetPropertyValueAndDetectChanges(value, ref _tourData, nameof(TourData)); } /// @@ -336,8 +296,8 @@ namespace Umbraco.Core.Models.Membership [DataMember] public int SessionTimeout { - get { return _sessionTimeout; } - set { SetPropertyValueAndDetectChanges(value, ref _sessionTimeout, Ps.Value.SessionTimeoutSelector); } + get => _sessionTimeout; + set => SetPropertyValueAndDetectChanges(value, ref _sessionTimeout, nameof(SessionTimeout)); } /// @@ -350,8 +310,8 @@ namespace Umbraco.Core.Models.Membership [DoNotClone] public int[] StartContentIds { - get { return _startContentIds; } - set { SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdSelector, Ps.Value.IntegerEnumerableComparer); } + get => _startContentIds; + set => SetPropertyValueAndDetectChanges(value, ref _startContentIds, nameof(StartContentIds), IntegerEnumerableComparer); } /// @@ -364,32 +324,29 @@ namespace Umbraco.Core.Models.Membership [DoNotClone] public int[] StartMediaIds { - get { return _startMediaIds; } - set { SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdSelector, Ps.Value.IntegerEnumerableComparer); } + get => _startMediaIds; + set => SetPropertyValueAndDetectChanges(value, ref _startMediaIds, nameof(StartMediaIds), IntegerEnumerableComparer); } [DataMember] public string Language { - get { return _language; } - set { SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector); } + get => _language; + set => SetPropertyValueAndDetectChanges(value, ref _language, nameof(Language)); } [IgnoreDataMember] internal bool DefaultToLiveEditing { - get { return _defaultToLiveEditing; } - set { SetPropertyValueAndDetectChanges(value, ref _defaultToLiveEditing, Ps.Value.DefaultToLiveEditingSelector); } + get => _defaultToLiveEditing; + set => SetPropertyValueAndDetectChanges(value, ref _defaultToLiveEditing, nameof(DefaultToLiveEditing)); } /// /// Gets the groups that user is part of /// [DataMember] - public IEnumerable Groups - { - get { return _userGroups; } - } + public IEnumerable Groups => _userGroups; public void RemoveGroup(string group) { @@ -400,7 +357,7 @@ namespace Umbraco.Core.Models.Membership _userGroups.Remove(userGroup); //reset this flag so it's rebuilt with the assigned groups _allowedSections = null; - OnPropertyChanged(Ps.Value.UserGroupsSelector); + OnPropertyChanged(nameof(Groups)); } } } @@ -412,7 +369,7 @@ namespace Umbraco.Core.Models.Membership _userGroups.Clear(); //reset this flag so it's rebuilt with the assigned groups _allowedSections = null; - OnPropertyChanged(Ps.Value.UserGroupsSelector); + OnPropertyChanged(nameof(Groups)); } } @@ -422,7 +379,7 @@ namespace Umbraco.Core.Models.Membership { //reset this flag so it's rebuilt with the assigned groups _allowedSections = null; - OnPropertyChanged(Ps.Value.UserGroupsSelector); + OnPropertyChanged(nameof(Groups)); } } @@ -446,7 +403,7 @@ namespace Umbraco.Core.Models.Membership [IgnoreDataMember] [DoNotClone] - internal object AdditionalDataLock { get { return _additionalDataLock; } } + internal object AdditionalDataLock => _additionalDataLock; protected override void PerformDeepClone(object clone) { @@ -498,15 +455,9 @@ namespace Umbraco.Core.Models.Membership _user = user; } - public int Id - { - get { return _user.Id; } - } + public int Id => _user.Id; - public string Name - { - get { return _user.Name; } - } + public string Name => _user.Name; private bool Equals(WrappedUserProfile other) { diff --git a/src/Umbraco.Core/Models/Membership/UserGroup.cs b/src/Umbraco.Core/Models/Membership/UserGroup.cs index e3e812f4c1..0562586af4 100644 --- a/src/Umbraco.Core/Models/Membership/UserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/UserGroup.cs @@ -22,24 +22,11 @@ namespace Umbraco.Core.Models.Membership private IEnumerable _permissions; private readonly List _sectionCollection; - private static readonly Lazy Ps = new Lazy(); - - // ReSharper disable once ClassNeverInstantiated.Local // lazy-instantiated in Ps - private class PropertySelectors - { - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Permissions); - public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon); - public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentId); - public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaId); - - //Custom comparer for enumerable - public readonly DelegateEqualityComparer> StringEnumerableComparer = - new DelegateEqualityComparer>( - (enum1, enum2) => enum1.UnsortedSequenceEqual(enum2), - enum1 => enum1.GetHashCode()); - } + //Custom comparer for enumerable + private static readonly DelegateEqualityComparer> StringEnumerableComparer = + new DelegateEqualityComparer>( + (enum1, enum2) => enum1.UnsortedSequenceEqual(enum2), + enum1 => enum1.GetHashCode()); /// /// Constructor to create a new user group @@ -71,35 +58,35 @@ namespace Umbraco.Core.Models.Membership public int? StartMediaId { get => _startMediaId; - set => SetPropertyValueAndDetectChanges(value, ref _startMediaId, Ps.Value.StartMediaIdSelector); + set => SetPropertyValueAndDetectChanges(value, ref _startMediaId, nameof(StartMediaId)); } [DataMember] public int? StartContentId { get => _startContentId; - set => SetPropertyValueAndDetectChanges(value, ref _startContentId, Ps.Value.StartContentIdSelector); + set => SetPropertyValueAndDetectChanges(value, ref _startContentId, nameof(StartContentId)); } [DataMember] public string Icon { get => _icon; - set => SetPropertyValueAndDetectChanges(value, ref _icon, Ps.Value.IconSelector); + set => SetPropertyValueAndDetectChanges(value, ref _icon, nameof(Icon)); } [DataMember] public string Alias { get => _alias; - set => SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase), ref _alias, Ps.Value.AliasSelector); + set => SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase), ref _alias, nameof(Alias)); } [DataMember] public string Name { get => _name; - set => SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -112,7 +99,7 @@ namespace Umbraco.Core.Models.Membership public IEnumerable Permissions { get => _permissions; - set => SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector, Ps.Value.StringEnumerableComparer); + set => SetPropertyValueAndDetectChanges(value, ref _permissions, nameof(Permissions), StringEnumerableComparer); } public IEnumerable AllowedSections => _sectionCollection; diff --git a/src/Umbraco.Core/Models/MigrationEntry.cs b/src/Umbraco.Core/Models/MigrationEntry.cs index 9ac9ae58a4..1149f6c773 100644 --- a/src/Umbraco.Core/Models/MigrationEntry.cs +++ b/src/Umbraco.Core/Models/MigrationEntry.cs @@ -19,27 +19,19 @@ namespace Umbraco.Core.Models _version = version; } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.MigrationName); - public readonly PropertyInfo VersionSelector = ExpressionHelper.GetPropertyInfo(x => x.Version); - } - private string _migrationName; private SemVersion _version; public string MigrationName { - get { return _migrationName; } - set { SetPropertyValueAndDetectChanges(value, ref _migrationName, Ps.Value.NameSelector); } + get => _migrationName; + set => SetPropertyValueAndDetectChanges(value, ref _migrationName, nameof(MigrationName)); } public SemVersion Version { - get { return _version; } - set { SetPropertyValueAndDetectChanges(value, ref _version, Ps.Value.VersionSelector); } + get => _version; + set => SetPropertyValueAndDetectChanges(value, ref _version, nameof(Version)); } } } diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index 11b5239a70..f7f45d7f5c 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -103,9 +103,6 @@ namespace Umbraco.Core.Models // ReSharper disable once ClassNeverInstantiated.Local private class PropertySelectors { - // TODO: This allows us to track changes for an entire Property, but doesn't allow us to track changes at the variant level - public readonly PropertyInfo ValuesSelector = ExpressionHelper.GetPropertyInfo(x => x.Values); - public readonly DelegateEqualityComparer PropertyValueComparer = new DelegateEqualityComparer( (o, o1) => { @@ -258,7 +255,7 @@ namespace Umbraco.Core.Models throw new NotSupportedException("Property type does not support publishing."); var origValue = pvalue.PublishedValue; pvalue.PublishedValue = PropertyType.ConvertAssignedValue(pvalue.EditedValue); - DetectChanges(pvalue.EditedValue, origValue, Ps.Value.ValuesSelector, Ps.Value.PropertyValueComparer, false); + DetectChanges(pvalue.EditedValue, origValue, nameof(Values), Ps.Value.PropertyValueComparer, false); } private void UnpublishValue(PropertyValue pvalue) @@ -269,7 +266,7 @@ namespace Umbraco.Core.Models throw new NotSupportedException("Property type does not support publishing."); var origValue = pvalue.PublishedValue; pvalue.PublishedValue = PropertyType.ConvertAssignedValue(null); - DetectChanges(pvalue.EditedValue, origValue, Ps.Value.ValuesSelector, Ps.Value.PropertyValueComparer, false); + DetectChanges(pvalue.EditedValue, origValue, nameof(Values), Ps.Value.PropertyValueComparer, false); } /// @@ -290,7 +287,7 @@ namespace Umbraco.Core.Models pvalue.EditedValue = setValue; - DetectChanges(setValue, origValue, Ps.Value.ValuesSelector, Ps.Value.PropertyValueComparer, change); + DetectChanges(setValue, origValue, nameof(Values), Ps.Value.PropertyValueComparer, change); } // bypasses all changes detection and is the *only* way to set the published value diff --git a/src/Umbraco.Core/Models/PropertyGroup.cs b/src/Umbraco.Core/Models/PropertyGroup.cs index 595e8d1d6a..00bc12f584 100644 --- a/src/Umbraco.Core/Models/PropertyGroup.cs +++ b/src/Umbraco.Core/Models/PropertyGroup.cs @@ -15,7 +15,6 @@ namespace Umbraco.Core.Models [DebuggerDisplay("Id: {Id}, Name: {Name}")] public class PropertyGroup : EntityBase, IEquatable { - private static readonly Lazy Ps = new Lazy(); private string _name; private int _sortOrder; @@ -30,17 +29,9 @@ namespace Umbraco.Core.Models PropertyTypes = propertyTypeCollection; } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); - public readonly PropertyInfo PropertyTypes = ExpressionHelper.GetPropertyInfo(x => x.PropertyTypes); - } - private void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.PropertyTypes); + OnPropertyChanged(nameof(PropertyTypes)); } /// @@ -50,7 +41,7 @@ namespace Umbraco.Core.Models public string Name { get => _name; - set => SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -60,7 +51,7 @@ namespace Umbraco.Core.Models public int SortOrder { get => _sortOrder; - set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, Ps.Value.SortOrderSelector); + set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, nameof(SortOrder)); } /// @@ -85,7 +76,7 @@ namespace Umbraco.Core.Models foreach (var propertyType in _propertyTypes) propertyType.PropertyGroupId = new Lazy(() => Id); - OnPropertyChanged(Ps.Value.PropertyTypes); + OnPropertyChanged(nameof(PropertyTypes)); _propertyTypes.CollectionChanged += PropertyTypesChanged; } } diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 107831ebdd..486e22b278 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -20,8 +20,6 @@ namespace Umbraco.Core.Models [DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")] public class PropertyType : EntityBase, IEquatable { - private static PropertySelectors _selectors; - private readonly bool _forceValueStorageType; private string _name; private string _alias; @@ -86,24 +84,7 @@ namespace Umbraco.Core.Models _alias = propertyTypeAlias == null ? null : SanitizeAlias(propertyTypeAlias); _variations = ContentVariation.Nothing; } - - private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); - - private class PropertySelectors - { - public readonly PropertyInfo Name = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo Alias = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo Description = ExpressionHelper.GetPropertyInfo(x => x.Description); - public readonly PropertyInfo DataTypeId = ExpressionHelper.GetPropertyInfo(x => x.DataTypeId); - public readonly PropertyInfo PropertyEditorAlias = ExpressionHelper.GetPropertyInfo(x => x.PropertyEditorAlias); - public readonly PropertyInfo ValueStorageType = ExpressionHelper.GetPropertyInfo(x => x.ValueStorageType); - public readonly PropertyInfo Mandatory = ExpressionHelper.GetPropertyInfo(x => x.Mandatory); - public readonly PropertyInfo SortOrder = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); - public readonly PropertyInfo ValidationRegExp = ExpressionHelper.GetPropertyInfo(x => x.ValidationRegExp); - public readonly PropertyInfo PropertyGroupId = ExpressionHelper.GetPropertyInfo>(x => x.PropertyGroupId); - public readonly PropertyInfo VaryBy = ExpressionHelper.GetPropertyInfo(x => x.Variations); - } - + /// /// Gets a value indicating whether the content type, owning this property type, is publishing. /// @@ -116,7 +97,7 @@ namespace Umbraco.Core.Models public string Name { get => _name; - set => SetPropertyValueAndDetectChanges(value, ref _name, Selectors.Name); + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -126,7 +107,7 @@ namespace Umbraco.Core.Models public string Alias { get => _alias; - set => SetPropertyValueAndDetectChanges(SanitizeAlias(value), ref _alias, Selectors.Alias); + set => SetPropertyValueAndDetectChanges(SanitizeAlias(value), ref _alias, nameof(Alias)); } /// @@ -136,7 +117,7 @@ namespace Umbraco.Core.Models public string Description { get => _description; - set => SetPropertyValueAndDetectChanges(value, ref _description, Selectors.Description); + set => SetPropertyValueAndDetectChanges(value, ref _description, nameof(Description)); } /// @@ -146,7 +127,7 @@ namespace Umbraco.Core.Models public int DataTypeId { get => _dataTypeId; - set => SetPropertyValueAndDetectChanges(value, ref _dataTypeId, Selectors.DataTypeId); + set => SetPropertyValueAndDetectChanges(value, ref _dataTypeId, nameof(DataTypeId)); } /// @@ -156,7 +137,7 @@ namespace Umbraco.Core.Models public string PropertyEditorAlias { get => _propertyEditorAlias; - set => SetPropertyValueAndDetectChanges(value, ref _propertyEditorAlias, Selectors.PropertyEditorAlias); + set => SetPropertyValueAndDetectChanges(value, ref _propertyEditorAlias, nameof(PropertyEditorAlias)); } /// @@ -169,7 +150,7 @@ namespace Umbraco.Core.Models set { if (_forceValueStorageType) return; // ignore changes - SetPropertyValueAndDetectChanges(value, ref _valueStorageType, Selectors.ValueStorageType); + SetPropertyValueAndDetectChanges(value, ref _valueStorageType, nameof(ValueStorageType)); } } @@ -181,7 +162,7 @@ namespace Umbraco.Core.Models internal Lazy PropertyGroupId { get => _propertyGroupId; - set => SetPropertyValueAndDetectChanges(value, ref _propertyGroupId, Selectors.PropertyGroupId); + set => SetPropertyValueAndDetectChanges(value, ref _propertyGroupId, nameof(PropertyGroupId)); } /// @@ -191,7 +172,7 @@ namespace Umbraco.Core.Models public bool Mandatory { get => _mandatory; - set => SetPropertyValueAndDetectChanges(value, ref _mandatory, Selectors.Mandatory); + set => SetPropertyValueAndDetectChanges(value, ref _mandatory, nameof(Mandatory)); } /// @@ -201,7 +182,7 @@ namespace Umbraco.Core.Models public int SortOrder { get => _sortOrder; - set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, Selectors.SortOrder); + set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, nameof(SortOrder)); } /// @@ -211,7 +192,7 @@ namespace Umbraco.Core.Models public string ValidationRegExp { get => _validationRegExp; - set => SetPropertyValueAndDetectChanges(value, ref _validationRegExp, Selectors.ValidationRegExp); + set => SetPropertyValueAndDetectChanges(value, ref _validationRegExp, nameof(ValidationRegExp)); } /// @@ -220,7 +201,7 @@ namespace Umbraco.Core.Models public ContentVariation Variations { get => _variations; - set => SetPropertyValueAndDetectChanges(value, ref _variations, Selectors.VaryBy); + set => SetPropertyValueAndDetectChanges(value, ref _variations, nameof(Variations)); } /// diff --git a/src/Umbraco.Core/Models/PublicAccessEntry.cs b/src/Umbraco.Core/Models/PublicAccessEntry.cs index df2d9f9ddc..58dd53a0c5 100644 --- a/src/Umbraco.Core/Models/PublicAccessEntry.cs +++ b/src/Umbraco.Core/Models/PublicAccessEntry.cs @@ -54,7 +54,7 @@ namespace Umbraco.Core.Models void _ruleCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - OnPropertyChanged(Ps.Value.AllowedSectionsSelector); + OnPropertyChanged(nameof(Rules)); //if (e.Action == NotifyCollectionChangedAction.Add) //{ @@ -77,26 +77,10 @@ namespace Umbraco.Core.Models } } + + internal IEnumerable RemovedRules => _removedRules; - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo ProtectedNodeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ProtectedNodeId); - public readonly PropertyInfo LoginNodeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.LoginNodeId); - public readonly PropertyInfo NoAccessNodeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.NoAccessNodeId); - public readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Rules); - } - - internal IEnumerable RemovedRules - { - get { return _removedRules; } - } - - public IEnumerable Rules - { - get { return _ruleCollection; } - } + public IEnumerable Rules => _ruleCollection; public PublicAccessRule AddRule(string ruleValue, string ruleType) { @@ -129,22 +113,22 @@ namespace Umbraco.Core.Models [DataMember] public int LoginNodeId { - get { return _loginNodeId; } - set { SetPropertyValueAndDetectChanges(value, ref _loginNodeId, Ps.Value.LoginNodeIdSelector); } + get => _loginNodeId; + set => SetPropertyValueAndDetectChanges(value, ref _loginNodeId, nameof(LoginNodeId)); } [DataMember] public int NoAccessNodeId { - get { return _noAccessNodeId; } - set { SetPropertyValueAndDetectChanges(value, ref _noAccessNodeId, Ps.Value.NoAccessNodeIdSelector); } + get => _noAccessNodeId; + set => SetPropertyValueAndDetectChanges(value, ref _noAccessNodeId, nameof(NoAccessNodeId)); } [DataMember] public int ProtectedNodeId { - get { return _protectedNodeId; } - set { SetPropertyValueAndDetectChanges(value, ref _protectedNodeId, Ps.Value.ProtectedNodeIdSelector); } + get => _protectedNodeId; + set => SetPropertyValueAndDetectChanges(value, ref _protectedNodeId, nameof(ProtectedNodeId)); } public override void ResetDirtyProperties(bool rememberDirty) diff --git a/src/Umbraco.Core/Models/PublicAccessRule.cs b/src/Umbraco.Core/Models/PublicAccessRule.cs index 67b9ece2f9..99d24221a2 100644 --- a/src/Umbraco.Core/Models/PublicAccessRule.cs +++ b/src/Umbraco.Core/Models/PublicAccessRule.cs @@ -23,26 +23,19 @@ namespace Umbraco.Core.Models { } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo RuleValueSelector = ExpressionHelper.GetPropertyInfo(x => x.RuleValue); - public readonly PropertyInfo RuleTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.RuleType); - } - + public Guid AccessEntryId { get; internal set; } public string RuleValue { - get { return _ruleValue; } - set { SetPropertyValueAndDetectChanges(value, ref _ruleValue, Ps.Value.RuleValueSelector); } + get => _ruleValue; + set => SetPropertyValueAndDetectChanges(value, ref _ruleValue, nameof(RuleValue)); } public string RuleType { - get { return _ruleType; } - set { SetPropertyValueAndDetectChanges(value, ref _ruleType, Ps.Value.RuleTypeSelector); } + get => _ruleType; + set => SetPropertyValueAndDetectChanges(value, ref _ruleType, nameof(RuleType)); } diff --git a/src/Umbraco.Core/Models/RedirectUrl.cs b/src/Umbraco.Core/Models/RedirectUrl.cs index 55b799244e..84fd631abb 100644 --- a/src/Umbraco.Core/Models/RedirectUrl.cs +++ b/src/Umbraco.Core/Models/RedirectUrl.cs @@ -20,18 +20,6 @@ namespace Umbraco.Core.Models CreateDateUtc = DateTime.UtcNow; } - private static readonly Lazy Ps = new Lazy(); - - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo ContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentId); - public readonly PropertyInfo ContentKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ContentKey); - public readonly PropertyInfo CreateDateUtcSelector = ExpressionHelper.GetPropertyInfo(x => x.CreateDateUtc); - public readonly PropertyInfo CultureSelector = ExpressionHelper.GetPropertyInfo(x => x.Culture); - public readonly PropertyInfo UrlSelector = ExpressionHelper.GetPropertyInfo(x => x.Url); - } - private int _contentId; private Guid _contentKey; private DateTime _createDateUtc; @@ -41,36 +29,36 @@ namespace Umbraco.Core.Models /// public int ContentId { - get { return _contentId; } - set { SetPropertyValueAndDetectChanges(value, ref _contentId, Ps.Value.ContentIdSelector); } + get => _contentId; + set => SetPropertyValueAndDetectChanges(value, ref _contentId, nameof(ContentId)); } /// public Guid ContentKey { - get { return _contentKey; } - set { SetPropertyValueAndDetectChanges(value, ref _contentKey, Ps.Value.ContentKeySelector); } + get => _contentKey; + set => SetPropertyValueAndDetectChanges(value, ref _contentKey, nameof(ContentKey)); } /// public DateTime CreateDateUtc { - get { return _createDateUtc; } - set { SetPropertyValueAndDetectChanges(value, ref _createDateUtc, Ps.Value.CreateDateUtcSelector); } + get => _createDateUtc; + set => SetPropertyValueAndDetectChanges(value, ref _createDateUtc, nameof(CreateDateUtc)); } /// public string Culture { - get { return _culture; } - set { SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); } + get => _culture; + set => SetPropertyValueAndDetectChanges(value, ref _culture, nameof(Culture)); } /// public string Url { - get { return _url; } - set { SetPropertyValueAndDetectChanges(value, ref _url, Ps.Value.UrlSelector); } + get => _url; + set => SetPropertyValueAndDetectChanges(value, ref _url, nameof(Url)); } } } diff --git a/src/Umbraco.Core/Models/Relation.cs b/src/Umbraco.Core/Models/Relation.cs index 2d2b05dbd6..1184561309 100644 --- a/src/Umbraco.Core/Models/Relation.cs +++ b/src/Umbraco.Core/Models/Relation.cs @@ -25,16 +25,7 @@ namespace Umbraco.Core.Models _childId = childId; _relationType = relationType; } - - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId); - public readonly PropertyInfo ChildIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ChildId); - public readonly PropertyInfo RelationTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.RelationType); - public readonly PropertyInfo CommentSelector = ExpressionHelper.GetPropertyInfo(x => x.Comment); - } + /// /// Gets or sets the Parent Id of the Relation (Source) @@ -42,8 +33,8 @@ namespace Umbraco.Core.Models [DataMember] public int ParentId { - get { return _parentId; } - set { SetPropertyValueAndDetectChanges(value, ref _parentId, Ps.Value.ParentIdSelector); } + get => _parentId; + set => SetPropertyValueAndDetectChanges(value, ref _parentId, nameof(ParentId)); } /// @@ -52,8 +43,8 @@ namespace Umbraco.Core.Models [DataMember] public int ChildId { - get { return _childId; } - set { SetPropertyValueAndDetectChanges(value, ref _childId, Ps.Value.ChildIdSelector); } + get => _childId; + set => SetPropertyValueAndDetectChanges(value, ref _childId, nameof(ChildId)); } /// @@ -62,8 +53,8 @@ namespace Umbraco.Core.Models [DataMember] public IRelationType RelationType { - get { return _relationType; } - set { SetPropertyValueAndDetectChanges(value, ref _relationType, Ps.Value.RelationTypeSelector); } + get => _relationType; + set => SetPropertyValueAndDetectChanges(value, ref _relationType, nameof(RelationType)); } /// @@ -72,18 +63,14 @@ namespace Umbraco.Core.Models [DataMember] public string Comment { - get { return _comment; } - set { SetPropertyValueAndDetectChanges(value, ref _comment, Ps.Value.CommentSelector); } + get => _comment; + set => SetPropertyValueAndDetectChanges(value, ref _comment, nameof(Comment)); } /// /// Gets the Id of the that this Relation is based on. /// [IgnoreDataMember] - public int RelationTypeId - { - get { return _relationType.Id; } - } - + public int RelationTypeId => _relationType.Id; } } diff --git a/src/Umbraco.Core/Models/RelationType.cs b/src/Umbraco.Core/Models/RelationType.cs index 5aa2c19ce3..f2941a152d 100644 --- a/src/Umbraco.Core/Models/RelationType.cs +++ b/src/Umbraco.Core/Models/RelationType.cs @@ -36,25 +36,14 @@ namespace Umbraco.Core.Models Name = name; } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo IsBidirectionalSelector = ExpressionHelper.GetPropertyInfo(x => x.IsBidirectional); - public readonly PropertyInfo ParentObjectTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentObjectType); - public readonly PropertyInfo ChildObjectTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.ChildObjectType); - } - /// /// Gets or sets the Name of the RelationType /// [DataMember] public string Name { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } + get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// @@ -63,8 +52,8 @@ namespace Umbraco.Core.Models [DataMember] public string Alias { - get { return _alias; } - set { SetPropertyValueAndDetectChanges(value, ref _alias, Ps.Value.AliasSelector); } + get => _alias; + set => SetPropertyValueAndDetectChanges(value, ref _alias, nameof(Alias)); } /// @@ -73,8 +62,8 @@ namespace Umbraco.Core.Models [DataMember] public bool IsBidirectional { - get { return _isBidrectional; } - set { SetPropertyValueAndDetectChanges(value, ref _isBidrectional, Ps.Value.IsBidirectionalSelector); } + get => _isBidrectional; + set => SetPropertyValueAndDetectChanges(value, ref _isBidrectional, nameof(IsBidirectional)); } /// @@ -84,8 +73,8 @@ namespace Umbraco.Core.Models [DataMember] public Guid ParentObjectType { - get { return _parentObjectType; } - set { SetPropertyValueAndDetectChanges(value, ref _parentObjectType, Ps.Value.ParentObjectTypeSelector); } + get => _parentObjectType; + set => SetPropertyValueAndDetectChanges(value, ref _parentObjectType, nameof(ParentObjectType)); } /// @@ -95,8 +84,8 @@ namespace Umbraco.Core.Models [DataMember] public Guid ChildObjectType { - get { return _childObjectType; } - set { SetPropertyValueAndDetectChanges(value, ref _childObjectType, Ps.Value.ChildObjectTypeSelector); } + get => _childObjectType; + set => SetPropertyValueAndDetectChanges(value, ref _childObjectType, nameof(ChildObjectType)); } } diff --git a/src/Umbraco.Core/Models/ServerRegistration.cs b/src/Umbraco.Core/Models/ServerRegistration.cs index db0e9b8c3b..c85a750500 100644 --- a/src/Umbraco.Core/Models/ServerRegistration.cs +++ b/src/Umbraco.Core/Models/ServerRegistration.cs @@ -14,17 +14,7 @@ namespace Umbraco.Core.Models private string _serverIdentity; private bool _isActive; private bool _isMaster; - - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo ServerAddressSelector = ExpressionHelper.GetPropertyInfo(x => x.ServerAddress); - public readonly PropertyInfo ServerIdentitySelector = ExpressionHelper.GetPropertyInfo(x => x.ServerIdentity); - public readonly PropertyInfo IsActiveSelector = ExpressionHelper.GetPropertyInfo(x => x.IsActive); - public readonly PropertyInfo IsMasterSelector = ExpressionHelper.GetPropertyInfo(x => x.IsMaster); - } - + /// /// Initializes a new instance of the class. /// @@ -73,8 +63,8 @@ namespace Umbraco.Core.Models /// public string ServerAddress { - get { return _serverAddress; } - set { SetPropertyValueAndDetectChanges(value, ref _serverAddress, Ps.Value.ServerAddressSelector); } + get => _serverAddress; + set => SetPropertyValueAndDetectChanges(value, ref _serverAddress, nameof(ServerAddress)); } /// @@ -82,8 +72,8 @@ namespace Umbraco.Core.Models /// public string ServerIdentity { - get { return _serverIdentity; } - set { SetPropertyValueAndDetectChanges(value, ref _serverIdentity, Ps.Value.ServerIdentitySelector); } + get => _serverIdentity; + set => SetPropertyValueAndDetectChanges(value, ref _serverIdentity, nameof(ServerIdentity)); } /// @@ -91,8 +81,8 @@ namespace Umbraco.Core.Models /// public bool IsActive { - get { return _isActive; } - set { SetPropertyValueAndDetectChanges(value, ref _isActive, Ps.Value.IsActiveSelector); } + get => _isActive; + set => SetPropertyValueAndDetectChanges(value, ref _isActive, nameof(IsActive)); } /// @@ -100,19 +90,27 @@ namespace Umbraco.Core.Models /// public bool IsMaster { - get { return _isMaster; } - set { SetPropertyValueAndDetectChanges(value, ref _isMaster, Ps.Value.IsMasterSelector); } + get => _isMaster; + set => SetPropertyValueAndDetectChanges(value, ref _isMaster, nameof(IsMaster)); } /// /// Gets the date and time the registration was created. /// - public DateTime Registered { get { return CreateDate; } set { CreateDate = value; }} + public DateTime Registered + { + get => CreateDate; + set => CreateDate = value; + } /// /// Gets the date and time the registration was last accessed. /// - public DateTime Accessed { get { return UpdateDate; } set { UpdateDate = value; }} + public DateTime Accessed + { + get => UpdateDate; + set => UpdateDate = value; + } /// /// Converts the value of this instance to its equivalent string representation. diff --git a/src/Umbraco.Core/Models/StylesheetProperty.cs b/src/Umbraco.Core/Models/StylesheetProperty.cs index 1601ca3e76..27e9a26074 100644 --- a/src/Umbraco.Core/Models/StylesheetProperty.cs +++ b/src/Umbraco.Core/Models/StylesheetProperty.cs @@ -25,14 +25,6 @@ namespace Umbraco.Core.Models _value = value; } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo(x => x.Value); - } - /// /// The CSS rule name that can be used by Umbraco in the back office /// @@ -43,8 +35,8 @@ namespace Umbraco.Core.Models /// public string Alias { - get { return _alias; } - set { SetPropertyValueAndDetectChanges(value, ref _alias, Ps.Value.AliasSelector); } + get => _alias; + set => SetPropertyValueAndDetectChanges(value, ref _alias, nameof(Alias)); } /// @@ -52,8 +44,8 @@ namespace Umbraco.Core.Models /// public string Value { - get { return _value; } - set { SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector); } + get => _value; + set => SetPropertyValueAndDetectChanges(value, ref _value, nameof(Value)); } } diff --git a/src/Umbraco.Core/Models/Tag.cs b/src/Umbraco.Core/Models/Tag.cs index e9707e587d..e44e26596b 100644 --- a/src/Umbraco.Core/Models/Tag.cs +++ b/src/Umbraco.Core/Models/Tag.cs @@ -48,21 +48,21 @@ namespace Umbraco.Core.Models public string Group { get => _group; - set => SetPropertyValueAndDetectChanges(value, ref _group, Selectors.Group); + set => SetPropertyValueAndDetectChanges(value, ref _group, nameof(Group)); } /// public string Text { get => _text; - set => SetPropertyValueAndDetectChanges(value, ref _text, Selectors.Text); + set => SetPropertyValueAndDetectChanges(value, ref _text, nameof(Text)); } /// public int? LanguageId { get => _languageId; - set => SetPropertyValueAndDetectChanges(value, ref _languageId, Selectors.LanguageId); + set => SetPropertyValueAndDetectChanges(value, ref _languageId, nameof(LanguageId)); } /// diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs index b7e67c45ea..e8c983e224 100644 --- a/src/Umbraco.Core/Models/Template.cs +++ b/src/Umbraco.Core/Models/Template.cs @@ -17,16 +17,6 @@ namespace Umbraco.Core.Models private string _masterTemplateAlias; private Lazy _masterTemplateId; - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo MasterTemplateAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.MasterTemplateAlias); - public readonly PropertyInfo MasterTemplateIdSelector = ExpressionHelper.GetPropertyInfo>(x => x.MasterTemplateId); - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - } - public Template(string name, string alias) : this(name, alias, (Func) null) { } @@ -42,28 +32,28 @@ namespace Umbraco.Core.Models [DataMember] public Lazy MasterTemplateId { - get { return _masterTemplateId; } - set { SetPropertyValueAndDetectChanges(value, ref _masterTemplateId, Ps.Value.MasterTemplateIdSelector); } + get => _masterTemplateId; + set => SetPropertyValueAndDetectChanges(value, ref _masterTemplateId, nameof(MasterTemplateId)); } public string MasterTemplateAlias { - get { return _masterTemplateAlias; } - set { SetPropertyValueAndDetectChanges(value, ref _masterTemplateAlias, Ps.Value.MasterTemplateAliasSelector); } + get => _masterTemplateAlias; + set => SetPropertyValueAndDetectChanges(value, ref _masterTemplateAlias, nameof(MasterTemplateAlias)); } [DataMember] public new string Name { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } + get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } [DataMember] public new string Alias { - get { return _alias; } - set { SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.UnderscoreAlias), ref _alias, Ps.Value.AliasSelector); } + get => _alias; + set => SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.UnderscoreAlias), ref _alias, nameof(Alias)); } /// diff --git a/src/Umbraco.Core/Models/UmbracoDomain.cs b/src/Umbraco.Core/Models/UmbracoDomain.cs index d7266f77fe..9aa2aa3c54 100644 --- a/src/Umbraco.Core/Models/UmbracoDomain.cs +++ b/src/Umbraco.Core/Models/UmbracoDomain.cs @@ -23,41 +23,29 @@ namespace Umbraco.Core.Models private int? _contentId; private int? _languageId; private string _domainName; - - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo(x => x.RootContentId); - public readonly PropertyInfo DefaultLanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.LanguageId); - public readonly PropertyInfo DomainNameSelector = ExpressionHelper.GetPropertyInfo(x => x.DomainName); - } - + [DataMember] public int? LanguageId { - get { return _languageId; } - set { SetPropertyValueAndDetectChanges(value, ref _languageId, Ps.Value.DefaultLanguageSelector); } + get => _languageId; + set => SetPropertyValueAndDetectChanges(value, ref _languageId, nameof(LanguageId)); } [DataMember] public string DomainName { - get { return _domainName; } - set { SetPropertyValueAndDetectChanges(value, ref _domainName, Ps.Value.DomainNameSelector); } + get => _domainName; + set => SetPropertyValueAndDetectChanges(value, ref _domainName, nameof(DomainName)); } [DataMember] public int? RootContentId { - get { return _contentId; } - set { SetPropertyValueAndDetectChanges(value, ref _contentId, Ps.Value.ContentSelector); } + get => _contentId; + set => SetPropertyValueAndDetectChanges(value, ref _contentId, nameof(RootContentId)); } - public bool IsWildcard - { - get { return string.IsNullOrWhiteSpace(DomainName) || DomainName.StartsWith("*"); } - } + public bool IsWildcard => string.IsNullOrWhiteSpace(DomainName) || DomainName.StartsWith("*"); /// /// Readonly value of the language ISO code for the domain diff --git a/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs index 11e2c56873..13fabe5ca2 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs @@ -17,10 +17,7 @@ namespace Umbraco.Tests.Cache { private DeepCloneAppCache _provider; - protected override int GetTotalItemCount - { - get { return HttpRuntime.Cache.Count; } - } + protected override int GetTotalItemCount => HttpRuntime.Cache.Count; public override void Setup() { @@ -28,15 +25,9 @@ namespace Umbraco.Tests.Cache _provider = new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache)); } - internal override IAppCache AppCache - { - get { return _provider; } - } + internal override IAppCache AppCache => _provider; - internal override IAppPolicyCache AppPolicyCache - { - get { return _provider; } - } + internal override IAppPolicyCache AppPolicyCache => _provider; [Test] public void Clones_List() @@ -101,18 +92,11 @@ namespace Umbraco.Tests.Cache CloneId = Guid.NewGuid(); } - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - } - private string _name; public string Name { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.WriterSelector); } + get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } public Guid CloneId { get; set; } From bc987a825ad6110a996010085478b23d8d5d7d89 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 10:09:32 +0100 Subject: [PATCH 083/555] Cleanup --- src/Umbraco.Core/Models/AuditEntry.cs | 11 +++-- src/Umbraco.Core/Models/Consent.cs | 3 +- src/Umbraco.Core/Models/Content.cs | 1 - src/Umbraco.Core/Models/ContentBase.cs | 1 - .../Models/ContentCultureInfos.cs | 4 +- src/Umbraco.Core/Models/ContentType.cs | 4 +- src/Umbraco.Core/Models/ContentTypeBase.cs | 2 - .../Models/ContentTypeCompositionBase.cs | 1 - src/Umbraco.Core/Models/DataType.cs | 1 - src/Umbraco.Core/Models/DictionaryItem.cs | 1 - .../Models/DictionaryTranslation.cs | 3 -- .../Models/Entities/BeingDirty.cs | 3 +- .../Models/Entities/BeingDirtyBase.cs | 3 +- .../Models/Entities/EntityBase.cs | 1 - .../Models/Entities/TreeEntityBase.cs | 1 - src/Umbraco.Core/Models/File.cs | 4 -- .../Models/Identity/BackOfficeIdentityUser.cs | 8 +--- src/Umbraco.Core/Models/Language.cs | 5 +-- src/Umbraco.Core/Models/Macro.cs | 17 -------- src/Umbraco.Core/Models/MacroProperty.cs | 2 - src/Umbraco.Core/Models/Member.cs | 6 +-- src/Umbraco.Core/Models/MemberGroup.cs | 2 - src/Umbraco.Core/Models/MemberType.cs | 1 - .../Models/Membership/UserGroup.cs | 1 - src/Umbraco.Core/Models/MigrationEntry.cs | 1 - src/Umbraco.Core/Models/Property.cs | 43 ++++++++----------- src/Umbraco.Core/Models/PropertyGroup.cs | 2 - src/Umbraco.Core/Models/PropertyType.cs | 6 +-- src/Umbraco.Core/Models/PublicAccessEntry.cs | 1 - src/Umbraco.Core/Models/PublicAccessRule.cs | 2 - src/Umbraco.Core/Models/RedirectUrl.cs | 1 - src/Umbraco.Core/Models/Relation.cs | 2 - src/Umbraco.Core/Models/RelationType.cs | 2 - src/Umbraco.Core/Models/ServerRegistration.cs | 3 +- src/Umbraco.Core/Models/StylesheetProperty.cs | 1 - src/Umbraco.Core/Models/Tag.cs | 12 ------ src/Umbraco.Core/Models/Template.cs | 1 - src/Umbraco.Core/Models/UmbracoDomain.cs | 3 +- 38 files changed, 35 insertions(+), 131 deletions(-) diff --git a/src/Umbraco.Core/Models/AuditEntry.cs b/src/Umbraco.Core/Models/AuditEntry.cs index da56c6c318..d12163f394 100644 --- a/src/Umbraco.Core/Models/AuditEntry.cs +++ b/src/Umbraco.Core/Models/AuditEntry.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -19,7 +18,7 @@ namespace Umbraco.Core.Models private string _affectedDetails; private string _eventType; private string _eventDetails; - + /// public int PerformingUserId { @@ -49,28 +48,28 @@ namespace Umbraco.Core.Models } /// - public int AffectedUserId + public int AffectedUserId { get => _affectedUserId; set => SetPropertyValueAndDetectChanges(value, ref _affectedUserId, nameof(AffectedUserId)); } /// - public string AffectedDetails + public string AffectedDetails { get => _affectedDetails; set => SetPropertyValueAndDetectChanges(value, ref _affectedDetails, nameof(AffectedDetails)); } /// - public string EventType + public string EventType { get => _eventType; set => SetPropertyValueAndDetectChanges(value, ref _eventType, nameof(EventType)); } /// - public string EventDetails + public string EventDetails { get => _eventDetails; set => SetPropertyValueAndDetectChanges(value, ref _eventDetails, nameof(EventDetails)); diff --git a/src/Umbraco.Core/Models/Consent.cs b/src/Umbraco.Core/Models/Consent.cs index cca1db41f1..4f7543fd59 100644 --- a/src/Umbraco.Core/Models/Consent.cs +++ b/src/Umbraco.Core/Models/Consent.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -19,7 +18,7 @@ namespace Umbraco.Core.Models private string _action; private ConsentState _state; private string _comment; - + /// public bool Current { diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 4fda1ff23d..dd4ba13c33 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Exceptions; diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index 705fa2cfb0..a1fb5da308 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Exceptions; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/ContentCultureInfos.cs b/src/Umbraco.Core/Models/ContentCultureInfos.cs index a0a4a7c472..c8c4bea56a 100644 --- a/src/Umbraco.Core/Models/ContentCultureInfos.cs +++ b/src/Umbraco.Core/Models/ContentCultureInfos.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using Umbraco.Core.Exceptions; using Umbraco.Core.Models.Entities; @@ -13,7 +12,7 @@ namespace Umbraco.Core.Models { private DateTime _date; private string _name; - + /// /// Initializes a new instance of the class. /// @@ -101,6 +100,5 @@ namespace Umbraco.Core.Models Deconstruct(out culture, out name); date = Date; } - } } diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs index 97534835d1..61fabe6fb0 100644 --- a/src/Umbraco.Core/Models/ContentType.cs +++ b/src/Umbraco.Core/Models/ContentType.cs @@ -67,8 +67,8 @@ namespace Umbraco.Core.Models [DataMember] internal int DefaultTemplateId { - get { return _defaultTemplate; } - set { SetPropertyValueAndDetectChanges(value, ref _defaultTemplate, nameof(DefaultTemplateId)); } + get => _defaultTemplate; + set => SetPropertyValueAndDetectChanges(value, ref _defaultTemplate, nameof(DefaultTemplateId)); } /// diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 3f45f424da..2aa114a88f 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; using Umbraco.Core.Strings; @@ -18,7 +17,6 @@ namespace Umbraco.Core.Models [DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")] public abstract class ContentTypeBase : TreeEntityBase, IContentTypeBase { - private string _alias; private string _description; private string _icon = "icon-folder"; diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs index 7a8e91845a..ec6f803107 100644 --- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Exceptions; diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs index 423895b475..8745e6dbec 100644 --- a/src/Umbraco.Core/Models/DataType.cs +++ b/src/Umbraco.Core/Models/DataType.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.Serialization; using Newtonsoft.Json; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/DictionaryItem.cs b/src/Umbraco.Core/Models/DictionaryItem.cs index 00c4e1a96c..c23e8f86a4 100644 --- a/src/Umbraco.Core/Models/DictionaryItem.cs +++ b/src/Umbraco.Core/Models/DictionaryItem.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/DictionaryTranslation.cs b/src/Umbraco.Core/Models/DictionaryTranslation.cs index 51c7ff2800..afb4063b97 100644 --- a/src/Umbraco.Core/Models/DictionaryTranslation.cs +++ b/src/Umbraco.Core/Models/DictionaryTranslation.cs @@ -1,8 +1,6 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.Mappers; namespace Umbraco.Core.Models { @@ -50,7 +48,6 @@ namespace Umbraco.Core.Models Key = uniqueId; } - /// /// Gets or sets the for the translation /// diff --git a/src/Umbraco.Core/Models/Entities/BeingDirty.cs b/src/Umbraco.Core/Models/Entities/BeingDirty.cs index 4e6d0cf5e3..92b4ab5c4b 100644 --- a/src/Umbraco.Core/Models/Entities/BeingDirty.cs +++ b/src/Umbraco.Core/Models/Entities/BeingDirty.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Reflection; namespace Umbraco.Core.Models.Entities { @@ -19,7 +18,7 @@ namespace Umbraco.Core.Models.Entities /// The type of the value. /// The new value. /// A reference to the value to set. - /// The property selector. + /// The property name. /// A comparer to compare property values. public new void SetPropertyValueAndDetectChanges(T value, ref T valueRef, string propertyName, IEqualityComparer comparer = null) { diff --git a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs index d9db433217..a598ba1b3d 100644 --- a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs +++ b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; namespace Umbraco.Core.Models.Entities @@ -143,7 +142,7 @@ namespace Umbraco.Core.Models.Entities /// The type of the value. /// The new value. /// A reference to the value to set. - /// The property selector. + /// The property name. /// A comparer to compare property values. protected void SetPropertyValueAndDetectChanges(T value, ref T valueRef, string propertyName, IEqualityComparer comparer = null) { diff --git a/src/Umbraco.Core/Models/Entities/EntityBase.cs b/src/Umbraco.Core/Models/Entities/EntityBase.cs index ef90f5e28d..43837fa776 100644 --- a/src/Umbraco.Core/Models/Entities/EntityBase.cs +++ b/src/Umbraco.Core/Models/Entities/EntityBase.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Reflection; using System.Runtime.Serialization; namespace Umbraco.Core.Models.Entities diff --git a/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs b/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs index b8243ed0a9..937d7ab0fc 100644 --- a/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs +++ b/src/Umbraco.Core/Models/Entities/TreeEntityBase.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; namespace Umbraco.Core.Models.Entities diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs index 494dcbe6fc..845da4d053 100644 --- a/src/Umbraco.Core/Models/File.cs +++ b/src/Umbraco.Core/Models/File.cs @@ -1,9 +1,5 @@ using System; -using System.IO; -using System.Reflection; using System.Runtime.Serialization; -using System.Text; -using Umbraco.Core.IO; using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index 084db81f11..0eb53428d1 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -3,20 +3,14 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; -using System.Reflection; -using System.Security.Claims; -using System.Threading.Tasks; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; -using Umbraco.Core.Security; namespace Umbraco.Core.Models.Identity { public class BackOfficeIdentityUser : IdentityUser, IdentityUserClaim>, IRememberBeingDirty { - private string _email; private string _userName; private int _id; @@ -419,9 +413,9 @@ namespace Umbraco.Core.Models.Identity private static readonly DelegateEqualityComparer GroupsComparer = new DelegateEqualityComparer( (groups, enumerable) => groups.Select(x => x.Alias).UnsortedSequenceEqual(enumerable.Select(x => x.Alias)), groups => groups.GetHashCode()); + private static readonly DelegateEqualityComparer StartIdsComparer = new DelegateEqualityComparer( (groups, enumerable) => groups.UnsortedSequenceEqual(enumerable), groups => groups.GetHashCode()); - } } diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs index 3e4d189abb..7d5fda3e06 100644 --- a/src/Umbraco.Core/Models/Language.cs +++ b/src/Umbraco.Core/Models/Language.cs @@ -1,7 +1,5 @@ using System; using System.Globalization; -using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using System.Threading; using Umbraco.Core.Configuration; @@ -16,7 +14,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class Language : EntityBase, ILanguage { - private string _isoCode; private string _cultureName; private bool _isDefaultVariantLanguage; @@ -27,7 +24,7 @@ namespace Umbraco.Core.Models { IsoCode = isoCode; } - + /// [DataMember] public string IsoCode diff --git a/src/Umbraco.Core/Models/Macro.cs b/src/Umbraco.Core/Models/Macro.cs index 2f29ddecff..bc71d3dc2b 100644 --- a/src/Umbraco.Core/Models/Macro.cs +++ b/src/Umbraco.Core/Models/Macro.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; using Umbraco.Core.Strings; @@ -99,22 +98,6 @@ namespace Umbraco.Core.Models private List _addedProperties; private List _removedProperties; - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo UseInEditorSelector = ExpressionHelper.GetPropertyInfo(x => x.UseInEditor); - public readonly PropertyInfo CacheDurationSelector = ExpressionHelper.GetPropertyInfo(x => x.CacheDuration); - public readonly PropertyInfo CacheByPageSelector = ExpressionHelper.GetPropertyInfo(x => x.CacheByPage); - public readonly PropertyInfo CacheByMemberSelector = ExpressionHelper.GetPropertyInfo(x => x.CacheByMember); - public readonly PropertyInfo DontRenderSelector = ExpressionHelper.GetPropertyInfo(x => x.DontRender); - public readonly PropertyInfo ScriptPathSelector = ExpressionHelper.GetPropertyInfo(x => x.MacroSource); - public readonly PropertyInfo MacroTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.MacroType); - public readonly PropertyInfo PropertiesSelector = ExpressionHelper.GetPropertyInfo(x => x.Properties); - } - void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e) { OnPropertyChanged(nameof(Properties)); diff --git a/src/Umbraco.Core/Models/MacroProperty.cs b/src/Umbraco.Core/Models/MacroProperty.cs index 7e269ba635..62ba6a7a7d 100644 --- a/src/Umbraco.Core/Models/MacroProperty.cs +++ b/src/Umbraco.Core/Models/MacroProperty.cs @@ -1,8 +1,6 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; -using Umbraco.Core.PropertyEditors; namespace Umbraco.Core.Models { diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index 06f94b85aa..78d1cfafd5 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -1,13 +1,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Composing; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; -using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { @@ -130,7 +126,7 @@ namespace Umbraco.Core.Models _rawPasswordValue = rawPasswordValue; IsApproved = isApproved; } - + /// /// Gets or sets the Username /// diff --git a/src/Umbraco.Core/Models/MemberGroup.cs b/src/Umbraco.Core/Models/MemberGroup.cs index 69e26c1037..8c06da418d 100644 --- a/src/Umbraco.Core/Models/MemberGroup.cs +++ b/src/Umbraco.Core/Models/MemberGroup.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -17,7 +16,6 @@ namespace Umbraco.Core.Models private string _name; private int _creatorId; - /// [DataMember] [DoNotClone] diff --git a/src/Umbraco.Core/Models/MemberType.cs b/src/Umbraco.Core/Models/MemberType.cs index 141cb3b63c..a6c1518446 100644 --- a/src/Umbraco.Core/Models/MemberType.cs +++ b/src/Umbraco.Core/Models/MemberType.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.Serialization; namespace Umbraco.Core.Models diff --git a/src/Umbraco.Core/Models/Membership/UserGroup.cs b/src/Umbraco.Core/Models/Membership/UserGroup.cs index 0562586af4..31421f990d 100644 --- a/src/Umbraco.Core/Models/Membership/UserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/UserGroup.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Core/Models/MigrationEntry.cs b/src/Umbraco.Core/Models/MigrationEntry.cs index 1149f6c773..1af66d2978 100644 --- a/src/Umbraco.Core/Models/MigrationEntry.cs +++ b/src/Umbraco.Core/Models/MigrationEntry.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using Semver; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index f7f45d7f5c..726ddc1cf5 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Collections; using Umbraco.Core.Models.Entities; @@ -25,8 +24,6 @@ namespace Umbraco.Core.Models // _vvalues contains the (indexed) variant property values private Dictionary _vvalues; - private static readonly Lazy Ps = new Lazy(); - /// /// Initializes a new instance of the class. /// @@ -100,29 +97,25 @@ namespace Umbraco.Core.Models => new PropertyValue { _culture = _culture, _segment = _segment, PublishedValue = PublishedValue, EditedValue = EditedValue }; } - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly DelegateEqualityComparer PropertyValueComparer = new DelegateEqualityComparer( - (o, o1) => - { - if (o == null && o1 == null) return true; + private static readonly DelegateEqualityComparer PropertyValueComparer = new DelegateEqualityComparer( + (o, o1) => + { + if (o == null && o1 == null) return true; - // custom comparer for strings. - // if one is null and another is empty then they are the same - if (o is string || o1 is string) - return ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace()) || (o != null && o1 != null && o.Equals(o1)); + // custom comparer for strings. + // if one is null and another is empty then they are the same + if (o is string || o1 is string) + return ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace()) || (o != null && o1 != null && o.Equals(o1)); - if (o == null || o1 == null) return false; + if (o == null || o1 == null) return false; - // custom comparer for enumerable - // ReSharper disable once MergeCastWithTypeCheck - if (o is IEnumerable && o1 is IEnumerable enumerable) - return ((IEnumerable) o).Cast().UnsortedSequenceEqual(enumerable.Cast()); + // custom comparer for enumerable + // ReSharper disable once MergeCastWithTypeCheck + if (o is IEnumerable && o1 is IEnumerable enumerable) + return ((IEnumerable)o).Cast().UnsortedSequenceEqual(enumerable.Cast()); - return o.Equals(o1); - }, o => o.GetHashCode()); - } + return o.Equals(o1); + }, o => o.GetHashCode()); /// /// Returns the PropertyType, which this Property is based on @@ -255,7 +248,7 @@ namespace Umbraco.Core.Models throw new NotSupportedException("Property type does not support publishing."); var origValue = pvalue.PublishedValue; pvalue.PublishedValue = PropertyType.ConvertAssignedValue(pvalue.EditedValue); - DetectChanges(pvalue.EditedValue, origValue, nameof(Values), Ps.Value.PropertyValueComparer, false); + DetectChanges(pvalue.EditedValue, origValue, nameof(Values), PropertyValueComparer, false); } private void UnpublishValue(PropertyValue pvalue) @@ -266,7 +259,7 @@ namespace Umbraco.Core.Models throw new NotSupportedException("Property type does not support publishing."); var origValue = pvalue.PublishedValue; pvalue.PublishedValue = PropertyType.ConvertAssignedValue(null); - DetectChanges(pvalue.EditedValue, origValue, nameof(Values), Ps.Value.PropertyValueComparer, false); + DetectChanges(pvalue.EditedValue, origValue, nameof(Values), PropertyValueComparer, false); } /// @@ -287,7 +280,7 @@ namespace Umbraco.Core.Models pvalue.EditedValue = setValue; - DetectChanges(setValue, origValue, nameof(Values), Ps.Value.PropertyValueComparer, change); + DetectChanges(setValue, origValue, nameof(Values), PropertyValueComparer, change); } // bypasses all changes detection and is the *only* way to set the published value diff --git a/src/Umbraco.Core/Models/PropertyGroup.cs b/src/Umbraco.Core/Models/PropertyGroup.cs index 00bc12f584..2e6da5d837 100644 --- a/src/Umbraco.Core/Models/PropertyGroup.cs +++ b/src/Umbraco.Core/Models/PropertyGroup.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Specialized; using System.Diagnostics; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -15,7 +14,6 @@ namespace Umbraco.Core.Models [DebuggerDisplay("Id: {Id}, Name: {Name}")] public class PropertyGroup : EntityBase, IEquatable { - private string _name; private int _sortOrder; private PropertyTypeCollection _propertyTypes; diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 486e22b278..1d6a3b4fe9 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; -using System.Text.RegularExpressions; using Umbraco.Core.Composing; using Umbraco.Core.Models.Entities; using Umbraco.Core.Strings; @@ -84,7 +80,7 @@ namespace Umbraco.Core.Models _alias = propertyTypeAlias == null ? null : SanitizeAlias(propertyTypeAlias); _variations = ContentVariation.Nothing; } - + /// /// Gets a value indicating whether the content type, owning this property type, is publishing. /// diff --git a/src/Umbraco.Core/Models/PublicAccessEntry.cs b/src/Umbraco.Core/Models/PublicAccessEntry.cs index 58dd53a0c5..cfb30de147 100644 --- a/src/Umbraco.Core/Models/PublicAccessEntry.cs +++ b/src/Umbraco.Core/Models/PublicAccessEntry.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/PublicAccessRule.cs b/src/Umbraco.Core/Models/PublicAccessRule.cs index 99d24221a2..bb6c1cdea2 100644 --- a/src/Umbraco.Core/Models/PublicAccessRule.cs +++ b/src/Umbraco.Core/Models/PublicAccessRule.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -23,7 +22,6 @@ namespace Umbraco.Core.Models { } - public Guid AccessEntryId { get; internal set; } public string RuleValue diff --git a/src/Umbraco.Core/Models/RedirectUrl.cs b/src/Umbraco.Core/Models/RedirectUrl.cs index 84fd631abb..f4eb955c64 100644 --- a/src/Umbraco.Core/Models/RedirectUrl.cs +++ b/src/Umbraco.Core/Models/RedirectUrl.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/Relation.cs b/src/Umbraco.Core/Models/Relation.cs index 1184561309..f5d13c70c4 100644 --- a/src/Umbraco.Core/Models/Relation.cs +++ b/src/Umbraco.Core/Models/Relation.cs @@ -1,8 +1,6 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.Mappers; namespace Umbraco.Core.Models { diff --git a/src/Umbraco.Core/Models/RelationType.cs b/src/Umbraco.Core/Models/RelationType.cs index f2941a152d..259b7bc4ef 100644 --- a/src/Umbraco.Core/Models/RelationType.cs +++ b/src/Umbraco.Core/Models/RelationType.cs @@ -1,9 +1,7 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Exceptions; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.Mappers; namespace Umbraco.Core.Models { diff --git a/src/Umbraco.Core/Models/ServerRegistration.cs b/src/Umbraco.Core/Models/ServerRegistration.cs index c85a750500..7dae5d5393 100644 --- a/src/Umbraco.Core/Models/ServerRegistration.cs +++ b/src/Umbraco.Core/Models/ServerRegistration.cs @@ -1,6 +1,5 @@ using System; using System.Globalization; -using System.Reflection; using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models @@ -14,7 +13,7 @@ namespace Umbraco.Core.Models private string _serverIdentity; private bool _isActive; private bool _isMaster; - + /// /// Initializes a new instance of the class. /// diff --git a/src/Umbraco.Core/Models/StylesheetProperty.cs b/src/Umbraco.Core/Models/StylesheetProperty.cs index 27e9a26074..089f89deb6 100644 --- a/src/Umbraco.Core/Models/StylesheetProperty.cs +++ b/src/Umbraco.Core/Models/StylesheetProperty.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Core/Models/Tag.cs b/src/Umbraco.Core/Models/Tag.cs index e44e26596b..315904493e 100644 --- a/src/Umbraco.Core/Models/Tag.cs +++ b/src/Umbraco.Core/Models/Tag.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -12,8 +11,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class Tag : EntityBase, ITag { - private static PropertySelectors _selectors; - private string _group; private string _text; private int? _languageId; @@ -35,15 +32,6 @@ namespace Umbraco.Core.Models LanguageId = languageId; } - private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); - - private class PropertySelectors - { - public readonly PropertyInfo Group = ExpressionHelper.GetPropertyInfo(x => x.Group); - public readonly PropertyInfo Text = ExpressionHelper.GetPropertyInfo(x => x.Text); - public readonly PropertyInfo LanguageId = ExpressionHelper.GetPropertyInfo(x => x.LanguageId); - } - /// public string Group { diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs index e8c983e224..db473972e3 100644 --- a/src/Umbraco.Core/Models/Template.cs +++ b/src/Umbraco.Core/Models/Template.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Core/Models/UmbracoDomain.cs b/src/Umbraco.Core/Models/UmbracoDomain.cs index 9aa2aa3c54..093acef5b5 100644 --- a/src/Umbraco.Core/Models/UmbracoDomain.cs +++ b/src/Umbraco.Core/Models/UmbracoDomain.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; @@ -23,7 +22,7 @@ namespace Umbraco.Core.Models private int? _contentId; private int? _languageId; private string _domainName; - + [DataMember] public int? LanguageId { From 3c3b9e39464bc0721f7661ad0b0d9d7f58e8aa34 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 12:55:04 +0100 Subject: [PATCH 084/555] Fixes --- src/Umbraco.Core/Models/ContentBase.cs | 29 +++++++++++----------- src/Umbraco.Tests/Models/ContentTests.cs | 15 +++++++++++ src/Umbraco.Tests/Models/VariationTests.cs | 13 ++++------ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index 1389f01fc8..51730c3b4d 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -367,25 +367,26 @@ namespace Umbraco.Core.Models /// public virtual Property[] ValidateProperties(string culture = "*") { - var alsoInvariant = culture != null && culture != "*"; - + // select invalid properties return Properties.Where(x => - { - var supportVariation = x.PropertyType.SupportsVariation(culture, "*", true); + { + // if culture is null, we validate invariant properties only + // if culture is '*' we validate both variant and invariant properties, automatically + // if culture is specific eg 'en-US' we both too, but explicitly - if (supportVariation) - { - // If the property support variation then we report an error - // when property is invalid for current culture OR property is invalid for invariant - return !x.IsValid(culture) || (alsoInvariant && !x.IsValid(null)); - } + var varies = x.PropertyType.VariesByCulture(); - // Else we report error if the property is invalid for the default language - return !x.IsValid(); + if (culture == null) + return !(varies || x.IsValid(null)); // validate invariant property, invariant culture + if (culture == "*") + return !x.IsValid(culture); // validate property, all cultures - }) - .ToArray(); + return varies + ? !x.IsValid(culture) // validate variant property, explicit culture + : !x.IsValid(null); // validate invariant property, explicit culture + }) + .ToArray(); } #endregion diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 862925db2c..160428b5e4 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -8,16 +8,19 @@ using Moq; using Umbraco.Core; using NUnit.Framework; using Umbraco.Core.Cache; +using Umbraco.Core.Composing; using Umbraco.Core.Composing.Composers; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; +using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.Models { @@ -34,6 +37,18 @@ namespace Umbraco.Tests.Models Composition.Register(_ => Mock.Of()); Composition.Register(_ => Mock.Of()); + + // all this is required so we can validate properties... + var editor = new TextboxPropertyEditor(Mock.Of()) { Alias = "test" }; + Composition.Register(_ => new DataEditorCollection(new [] { editor })); + Composition.Register(); + var dataType = Mock.Of(); + Mock.Get(dataType).Setup(x => x.Configuration).Returns(() => new object()); + var dataTypeService = Mock.Of(); + Mock.Get(dataTypeService) + .Setup(x => x.GetDataType(It.IsAny())) + .Returns(() => dataType); + Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService)); } [Test] diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs index 7c1ef3f580..0ccdabe928 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -382,15 +382,12 @@ namespace Umbraco.Tests.Models Assert.IsFalse(content.PublishCulture(langFr)); // fails because prop1 is mandatory content.SetValue("prop1", "a", langFr); - Assert.IsTrue(content.PublishCulture(langFr)); - Assert.AreEqual("a", content.GetValue("prop1", langFr, published: true)); - //this will be null because we tried to publish values for a specific culture but this property is invariant - Assert.IsNull(content.GetValue("prop2", published: true)); + Assert.IsFalse(content.PublishCulture(langFr)); // fails because prop2 is mandatory and invariant + content.SetValue("prop2", "x"); + Assert.IsTrue(content.PublishCulture(langFr)); // now it's ok - Assert.IsFalse(content.PublishCulture()); // fails because prop2 is mandatory - content.SetValue("prop2", "b"); - Assert.IsTrue(content.PublishCulture()); - Assert.AreEqual("b", content.GetValue("prop2", published: true)); + Assert.AreEqual("a", content.GetValue("prop1", langFr, published: true)); + Assert.AreEqual("x", content.GetValue("prop2", published: true)); } [Test] From 327b820a25684a08d0b6c14d8eade4a1a37a4176 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 4 Feb 2019 12:59:58 +0100 Subject: [PATCH 085/555] Fixed broken test --- .../Repositories/DataTypeDefinitionRepositoryTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index b9724b0770..2d999f00cd 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -192,7 +192,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var repository = CreateRepository(); // Act - var dataTypeDefinition = repository.Get(-42); + var dataTypeDefinition = repository.Get(Constants.DataTypes.DropDownSingle); // Assert Assert.That(dataTypeDefinition, Is.Not.Null); From d3eb48cef9997a838f4272c6d1420d070cae6730 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 4 Feb 2019 13:28:23 +0100 Subject: [PATCH 086/555] Fixes #4388 File uploads no longer has dragover styles --- .../src/views/components/upload/umb-file-dropzone.html | 2 +- .../src/views/packages/views/install-local.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html index c99655b7fc..a379a05829 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html @@ -8,7 +8,7 @@ ng-model="filesHolder" ngf-change="handleFiles($files, $event)" class="dropzone" - ngf-drag-over-class="drag-over" + ngf-drag-over-class="'drag-over'" ngf-multiple="true" ngf-allow-dir="true" ngf-pattern="{{ accept }}" diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html index 6d95bcafa7..718992c25a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html @@ -12,7 +12,7 @@ ng-model="filesHolder" ngf-change="handleFiles($files, $event)" class="umb-upload-local__dropzone" - ngf-drag-over-class="drag-over" + ngf-drag-over-class="'drag-over'" ngf-multiple="false" ngf-allow-dir="false" ngf-pattern="*.zip" From bd4b4620d4d001ac5555f9c573d0bb38dc657236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 4 Feb 2019 13:34:26 +0100 Subject: [PATCH 087/555] First part of refactoring umb-editor-navigation --- .../editor/umbeditornavigation.directive.js | 13 +++--- .../umbeditornavigationitem.directive.js | 40 +++++++++++++++++++ .../src/less/canvas-designer.less | 1 + .../components/umb-editor-navigation.less | 22 +++++----- src/Umbraco.Web.UI.Client/src/less/navs.less | 1 + .../editor/umb-editor-navigation-item.html | 12 ++++++ .../editor/umb-editor-navigation.html | 36 ++++++----------- .../src/views/components/umb-dropdown.html | 2 +- 8 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js index 943d2232c2..6b269ad17e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js @@ -17,14 +17,17 @@ name: "More" }; - scope.clickNavigationItem = function (selectedItem) { + scope.openNavigationItem = function (item) { + + console.log("openNavigationItem", item) + scope.showDropdown = false; - runItemAction(selectedItem); - setItemToActive(selectedItem); + runItemAction(item); + setItemToActive(item); if(scope.onSelect) { - scope.onSelect({"item": selectedItem}); + scope.onSelect({"item": item}); } - eventsService.emit("app.tabChange", selectedItem); + eventsService.emit("app.tabChange", item); }; scope.toggleDropdown = function () { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js new file mode 100644 index 0000000000..60a5a54d0f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js @@ -0,0 +1,40 @@ +/** +@ngdoc directive +@name umbraco.directives.directive:umbTabContent +@restrict E +@scope + +@description +Use this directive to render tab content. For an example see: {@link umbraco.directives.directive:umbTabContent umbTabContent} + +@param {string=} tab The tab. + +**/ +(function () { + 'use strict'; + + function UmbEditorNavigationItemController($scope, $element, $attrs) { + + console.log("LINKKK!") + var vm = this; + + this.callbackOpen = function(item) { + console.log("callbackOpen") + vm.open({item:vm.item}); + }; + } + + angular + .module('umbraco.directives.html') + .component('umbEditorNavigationItem', { + templateUrl: 'views/components/editor/umb-editor-navigation-item.html', + controller: UmbEditorNavigationItemController, + controllerAs: 'vm', + bindings: { + item: '=', + open: '&', + index: '@' + } + }); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less index 7f67d5c3b2..d1492a33c6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less +++ b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less @@ -176,6 +176,7 @@ a, a:hover{ .dropdown-menu { position: absolute; + display: block; top: auto; right: 0; z-index: 1000; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index c1f099c2a5..f4bbeadc3f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -106,29 +106,25 @@ line-height: 1em; } -.umb-sub-views-nav-item__more { +.umb-sub-views-nav-item-more__icon { margin-bottom: 10px; } -.umb-sub-views-nav-item__more i { +.umb-sub-views-nav-item-more__icon i { height: 5px; width: 5px; border-radius: 50%; - background: @gray-3; + background: @ui-active-type;// fallback if browser doesnt support currentColor + background: currentColor; display: inline-block; margin: 0 5px 0 0; } -.umb-sub-views-nav-item__more i:last-of-type { +.umb-sub-views-nav-item-more__icon i:last-of-type { margin-right: 0; } -// make dots green the an item is active -.umb-sub-views-nav-item.is-active .umb-sub-views-nav-item__more i { - background-color: @ui-active; -} - -.umb-sub-views-nav__dropdown.umb-sub-views-nav__dropdown { +.umb-sub-views-nav-item-more__dropdown { left: auto; right: 0; display: grid; @@ -136,3 +132,9 @@ min-width: auto; margin-top: 10px; } +.umb-sub-views-nav-item-more__dropdown > li { + display: flex; +} +.umb-sub-views-nav-item-more__dropdown .umb-sub-views-nav-item:first { + border-left: none; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/navs.less b/src/Umbraco.Web.UI.Client/src/less/navs.less index 0101113670..a2710fab6c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/navs.less +++ b/src/Umbraco.Web.UI.Client/src/less/navs.less @@ -220,6 +220,7 @@ // DROPDOWNS // --------- .dropdown-menu { + display: block; border-radius: @dropdownBorderRadius; box-shadow: 0 5px 20px rgba(0,0,0,.3); padding-top: 0; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html new file mode 100644 index 0000000000..002e9adfc0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html @@ -0,0 +1,12 @@ + + + {{ vm.item.name }} +
{{vm.item.badge.count}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index e278a8c401..1bc7c5ff4a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -3,42 +3,32 @@
  • -
    +
    {{ moreButton.name }}
    - + - - - {{ item.name }} - + + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html index 141793f6b1..2f24186597 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html @@ -1 +1 @@ - \ No newline at end of file + From e636f12459ced0ca91285f45127a4167efb7380f Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 09:03:54 +0100 Subject: [PATCH 088/555] Fix leak in BackgroundTaskRunner --- .../Scheduling/BackgroundTaskRunner.cs | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs index d9e3c3c980..47e97593f0 100644 --- a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs +++ b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs @@ -355,6 +355,8 @@ namespace Umbraco.Web.Scheduling // break latched tasks // stop processing the queue _shutdownTokenSource.Cancel(false); // false is the default + _shutdownTokenSource.Dispose(); + _shutdownTokenSource = null; } // tasks in the queue will be executed... @@ -379,28 +381,38 @@ namespace Umbraco.Web.Scheduling _cancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken); } - // wait for latch should return the task - // if it returns null it's either that the task has been cancelled - // or the whole runner is going down - in both cases, continue, - // and GetNextBackgroundTask will take care of shutdowns - bgTask = await WaitForLatch(bgTask, _cancelTokenSource.Token); - if (bgTask == null) continue; - - // executes & be safe - RunAsync should NOT throw but only raise an event, - // but... just make sure we never ever take everything down try { - await RunAsync(bgTask, _cancelTokenSource.Token).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.Error(ex, "{LogPrefix} Task runner exception", _logPrefix); - } + // wait for latch should return the task + // if it returns null it's either that the task has been cancelled + // or the whole runner is going down - in both cases, continue, + // and GetNextBackgroundTask will take care of shutdowns + bgTask = await WaitForLatch(bgTask, _cancelTokenSource.Token); - // done - lock (_locker) + if (bgTask != null) + { + // executes & be safe - RunAsync should NOT throw but only raise an event, + // but... just make sure we never ever take everything down + try + { + await RunAsync(bgTask, _cancelTokenSource.Token).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.Error(ex, "{LogPrefix} Task runner exception", _logPrefix); + } + } + } + finally { - _cancelTokenSource = null; + // done + lock (_locker) + { + // always dispose CancellationTokenSource when you are done using them + // https://lowleveldesign.org/2015/11/30/catch-in-cancellationtokensource/ + _cancelTokenSource.Dispose(); + _cancelTokenSource = null; + } } } } From 3c65770008578894a00d60366ef1ddd0ff73559d Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 14:08:35 +0100 Subject: [PATCH 089/555] Upgrade ModelsBuilder, cleanup --- build/NuSpecs/UmbracoCms.nuspec | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- src/Umbraco.Web/JavaScript/ServerVariablesParser.cs | 11 ----------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index 05a6f4ca0e..b0f30b9779 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -22,7 +22,7 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 02e24ddbb6..7c3293183d 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -105,7 +105,7 @@ - 8.0.0-alpha.35 + 8.0.0-alpha.36 diff --git a/src/Umbraco.Web/JavaScript/ServerVariablesParser.cs b/src/Umbraco.Web/JavaScript/ServerVariablesParser.cs index 6824d02d18..8f27f58143 100644 --- a/src/Umbraco.Web/JavaScript/ServerVariablesParser.cs +++ b/src/Umbraco.Web/JavaScript/ServerVariablesParser.cs @@ -2,19 +2,10 @@ using System.Collections.Generic; using Newtonsoft.Json.Linq; -namespace Umbraco.Web.UI.JavaScript -{ - //fixme delete this when Models Builder is updated - public sealed class ServerVariablesParser : global::Umbraco.Web.JavaScript.ServerVariablesParser - { - } -} - namespace Umbraco.Web.JavaScript { public class ServerVariablesParser { - /// /// Allows developers to add custom variables on parsing /// @@ -31,8 +22,6 @@ namespace Umbraco.Web.JavaScript var json = JObject.FromObject(items); return vars.Replace(Token, json.ToString()); - } - } } From 09255019b22d4dc8d3c0ea3d29793db18b001b34 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 5 Feb 2019 01:22:52 +1100 Subject: [PATCH 090/555] removes CommitDocumentChanges from the public interface --- src/Umbraco.Core/Services/IContentService.cs | 15 --------------- .../Services/Implement/ContentService.cs | 17 +++++++++++++++-- .../Services/ContentServiceTests.cs | 12 ++++++++---- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index ad97ba2ddc..600921ee78 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -363,21 +363,6 @@ namespace Umbraco.Core.Services /// PublishResult SaveAndPublish(IContent content, string[] cultures, int userId = 0, bool raiseEvents = true); - /// - /// Expert: Saves a document and publishes/unpublishes any pending publishing changes made to the document. - /// - /// - /// Pending publishing/unpublishing changes on a document are made with calls to and - /// . - /// When publishing or unpublishing a single culture, or all cultures, use - /// and . But if the flexibility to both publish and unpublish in a single operation is required - /// then this method needs to be used in combination with and - /// on the content itself - this prepares the content, but does not commit anything - and then, invoke - /// to actually commit the changes to the database. - /// The document is *always* saved, even when publishing fails. - /// - PublishResult CommitDocumentChanges(IContent content, int userId = 0, bool raiseEvents = true); - /// /// Saves and publishes a document branch. /// diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index 404adeea72..adc6c919f1 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -965,8 +965,21 @@ namespace Umbraco.Core.Services.Implement return CommitDocumentChanges(content, userId); } - /// - public PublishResult CommitDocumentChanges(IContent content, int userId = 0, bool raiseEvents = true) + /// + /// Saves a document and publishes/unpublishes any pending publishing changes made to the document. + /// + /// + /// This is the underlying logic for both publishing and unpublishing any document + /// Pending publishing/unpublishing changes on a document are made with calls to and + /// . + /// When publishing or unpublishing a single culture, or all cultures, use + /// and . But if the flexibility to both publish and unpublish in a single operation is required + /// then this method needs to be used in combination with and + /// on the content itself - this prepares the content, but does not commit anything - and then, invoke + /// to actually commit the changes to the database. + /// The document is *always* saved, even when publishing fails. + /// + internal PublishResult CommitDocumentChanges(IContent content, int userId = 0, bool raiseEvents = true) { using (var scope = ScopeProvider.CreateScope()) { diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 3e21768f97..7dd6c7ba03 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -1035,6 +1035,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_Publish_And_Unpublish_Cultures_In_Single_Operation() { + //TODO: This is using an internal API - we aren't exposing this publicly (at least for now) but we'll keep the test around + var langFr = new Language("fr"); var langDa = new Language("da"); ServiceContext.LocalizationService.Save(langFr); @@ -1049,7 +1051,7 @@ namespace Umbraco.Tests.Services content.SetCultureName("name-da", langDa.IsoCode); content.PublishCulture(langFr.IsoCode); - var result = ServiceContext.ContentService.CommitDocumentChanges(content); + var result = ((ContentService)ServiceContext.ContentService).CommitDocumentChanges(content); Assert.IsTrue(result.Success); content = ServiceContext.ContentService.GetById(content.Id); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); @@ -1058,7 +1060,7 @@ namespace Umbraco.Tests.Services content.UnpublishCulture(langFr.IsoCode); content.PublishCulture(langDa.IsoCode); - result = ServiceContext.ContentService.CommitDocumentChanges(content); + result = ((ContentService)ServiceContext.ContentService).CommitDocumentChanges(content); Assert.IsTrue(result.Success); Assert.AreEqual(PublishResultType.SuccessMixedCulture, result.Result); @@ -2893,8 +2895,10 @@ namespace Umbraco.Tests.Services // act // that HAS to be SavePublishing, because SaveAndPublish would just republish everything! - - contentService.CommitDocumentChanges(content); + //TODO: This is using an internal API - the test can't pass without this but we want to keep the test here + // will need stephane to have a look at this test at some stage since there is a lot of logic here that we + // want to keep on testing but don't need the public API to do these more complicated things. + ((ContentService)contentService).CommitDocumentChanges(content); // content has been re-published, // everything is back to what it was before being unpublished From a5947356e756bab88beccd2f13fb164146ad5578 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 5 Feb 2019 01:58:18 +1100 Subject: [PATCH 091/555] Removes WasCulturePublished from IContent --- src/Umbraco.Core/ContentExtensions.cs | 10 ++++++++-- src/Umbraco.Core/Models/Content.cs | 17 ++--------------- src/Umbraco.Core/Models/IContent.cs | 8 -------- .../Repositories/IDocumentRepository.cs | 2 ++ .../Implement/DocumentRepository.cs | 3 ++- .../Services/Implement/ContentService.cs | 15 ++++++++++++--- .../Services/ContentServiceTests.cs | 17 +++++------------ 7 files changed, 31 insertions(+), 41 deletions(-) diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 9fcc12bc10..44e9907210 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -56,15 +56,21 @@ namespace Umbraco.Core /// Gets the cultures that have been flagged for unpublishing. ///
  • /// Gets cultures for which content.UnpublishCulture() has been invoked. - internal static IReadOnlyList GetCulturesUnpublishing(this IContent content) + internal static IReadOnlyList GetCulturesUnpublishing(this IContent content, IContent persisted) { + //TODO: The reason we need a ref to the original persisted IContent is to check if it is published + // however, for performance reasons we could pass in a ContentCultureInfosCollection which could be + // resolved from the database much more quickly than resolving an entire IContent object. + // That said, the GetById on the IContentService will return from cache so might not be something to worry about. + + if (!content.Published || !content.ContentType.VariesByCulture() || !content.IsPropertyDirty("PublishCultureInfos")) return Array.Empty(); var culturesChanging = content.CultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key); return culturesChanging .Where(x => !content.IsCulturePublished(x) && // is not published anymore - content.WasCulturePublished(x)) // but was published before + persisted != null && persisted.IsCulturePublished(x)) // but was published before .ToList(); } diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 84ccc42a77..63ab65b8fe 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -19,7 +19,6 @@ namespace Umbraco.Core.Models private bool _published; private PublishedState _publishedState; private ContentCultureInfosCollection _publishInfos; - private ContentCultureInfosCollection _publishInfosOrig; private HashSet _editedCultures; /// @@ -201,11 +200,6 @@ namespace Umbraco.Core.Models // a non-available culture could not become published anyways => _publishInfos != null && _publishInfos.ContainsKey(culture); - /// - public bool WasCulturePublished(string culture) - // just check _publishInfosOrig - a copy of _publishInfos - // a non-available culture could not become published anyways - => _publishInfosOrig != null && _publishInfosOrig.ContainsKey(culture); // adjust dates to sync between version, cultures etc // used by the repo when persisting @@ -216,9 +210,8 @@ namespace Umbraco.Core.Models if (_publishInfos == null || !_publishInfos.TryGetValue(culture, out var publishInfos)) continue; - if (_publishInfosOrig != null && _publishInfosOrig.TryGetValue(culture, out var publishInfosOrig) - && publishInfosOrig.Date == publishInfos.Date) - continue; + //fixme: Removing the logic here for the old WasCulturePublished and the _publishInfosOrig has broken + // the test Can_Rollback_Version_On_Multilingual, but we need to understand what it's doing since I don't _publishInfos.AddOrUpdate(culture, publishInfos.Name, date); @@ -449,12 +442,6 @@ namespace Umbraco.Core.Models // take care of the published state _publishedState = _published ? PublishedState.Published : PublishedState.Unpublished; - // Make a copy of the _publishInfos, this is purely so that we can detect - // if this entity's previous culture publish state (regardless of the rememberDirty flag) - _publishInfosOrig = _publishInfos == null - ? null - : new ContentCultureInfosCollection(_publishInfos); - if (_publishInfos == null) return; foreach (var infos in _publishInfos) diff --git a/src/Umbraco.Core/Models/IContent.cs b/src/Umbraco.Core/Models/IContent.cs index 1d85a735b5..f468df59ab 100644 --- a/src/Umbraco.Core/Models/IContent.cs +++ b/src/Umbraco.Core/Models/IContent.cs @@ -84,14 +84,6 @@ namespace Umbraco.Core.Models /// bool IsCulturePublished(string culture); - /// - /// Gets a value indicating whether a culture was published. - /// - /// - /// Mirrors whenever the content item is saved. - /// - bool WasCulturePublished(string culture); - /// /// Gets the date a culture was published. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs index fc5382499f..d49c92f1bf 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs @@ -7,6 +7,8 @@ namespace Umbraco.Core.Persistence.Repositories { public interface IDocumentRepository : IContentRepository, IReadRepository { + + /// /// Clears the publishing schedule for all entries having an a date before (lower than, or equal to) a specified date. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 6af7031883..9b4175b63f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1127,7 +1127,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // TODO: shall we get published properties or not? //var publishedVersionId = dto.Published ? dto.PublishedVersionDto.Id : 0; - var publishedVersionId = dto.PublishedVersionDto != null ? dto.PublishedVersionDto.Id : 0; + var publishedVersionId = dto.PublishedVersionDto?.Id ?? 0; var temp = new TempContent(dto.NodeId, versionId, publishedVersionId, contentType); var ltemp = new List> { temp }; @@ -1424,6 +1424,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } + // ReSharper disable once ClassNeverInstantiated.Local private class CultureNodeName { public int Id { get; set; } diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index adc6c919f1..9c2721cbb4 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -921,6 +921,8 @@ namespace Umbraco.Core.Services.Implement /// public PublishResult Unpublish(IContent content, string culture = "*", int userId = 0) { + if (content == null) throw new ArgumentNullException(nameof(content)); + var evtMsgs = EventMessagesFactory.Get(); culture = culture.NullOrWhiteSpaceAsNull(); @@ -949,12 +951,16 @@ namespace Umbraco.Core.Services.Implement // all cultures = unpublish whole if (culture == "*" || (!content.ContentType.VariesByCulture() && culture == null)) { + //TODO: Stop casting https://github.com/umbraco/Umbraco-CMS/issues/4234 ((Content)content).PublishedState = PublishedState.Unpublishing; } else { - // if the culture we want to unpublish was already unpublished, nothing to do - if (!content.WasCulturePublished(culture)) + // If the culture we want to unpublish was already unpublished, nothing to do. + // To check for that we need to lookup the persisted content item + var persisted = content.HasIdentity ? GetById(content.Id) : null; + + if (persisted != null && !persisted.IsCulturePublished(culture)) return new PublishResult(PublishResultType.SuccessUnpublishAlready, evtMsgs, content); // unpublish the culture @@ -1025,7 +1031,10 @@ namespace Umbraco.Core.Services.Implement if (publishing) { - culturesUnpublishing = content.GetCulturesUnpublishing(); + //to continue, we need to have a reference to the original IContent item that is currently persisted + var persisted = content.HasIdentity ? GetById(content.Id) : null; + + culturesUnpublishing = content.GetCulturesUnpublishing(persisted); culturesPublishing = variesByCulture ? content.PublishCultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key).ToList() : null; diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 7dd6c7ba03..5bd37c0385 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -763,36 +763,29 @@ namespace Umbraco.Tests.Services content.PublishCulture(langFr.IsoCode); content.PublishCulture(langUk.IsoCode); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); - Assert.IsFalse(content.WasCulturePublished(langFr.IsoCode)); //not persisted yet, will be false Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); - Assert.IsFalse(content.WasCulturePublished(langUk.IsoCode)); //not persisted yet, will be false var published = ServiceContext.ContentService.SaveAndPublish(content, new[]{ langFr.IsoCode , langUk.IsoCode }); + Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); + Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); + //re-get content = ServiceContext.ContentService.GetById(content.Id); Assert.IsTrue(published.Success); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); - Assert.IsTrue(content.WasCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); - Assert.IsTrue(content.WasCulturePublished(langUk.IsoCode)); var unpublished = ServiceContext.ContentService.Unpublish(content, langFr.IsoCode); Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishCulture, unpublished.Result); - Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); - //this is slightly confusing but this will be false because this method is used for checking the state of the current model, - //but the state on the model has changed with the above Unpublish call - Assert.IsFalse(content.WasCulturePublished(langFr.IsoCode)); + Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); //re-get content = ServiceContext.ContentService.GetById(content.Id); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); - //this is slightly confusing but this will be false because this method is used for checking the state of a current model, - //but we've re-fetched from the database - Assert.IsFalse(content.WasCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); - Assert.IsTrue(content.WasCulturePublished(langUk.IsoCode)); + } From 2e5967ff9e56c259d2710d87a2bc98e309a9f311 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 17:58:36 +0100 Subject: [PATCH 092/555] Make TypeLoader less verbose --- src/Umbraco.Core/Composing/TypeLoader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index a2d6349ea0..08060ca65d 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -211,7 +211,7 @@ namespace Umbraco.Core.Composing /// file properties (false) or the file contents (true). private static string GetFileHash(IEnumerable> filesAndFolders, IProfilingLogger logger) { - using (logger.TraceDuration("Determining hash of code files on disk", "Hash determined")) + using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined")) { // get the distinct file infos to hash var uniqInfos = new HashSet(); @@ -269,7 +269,7 @@ namespace Umbraco.Core.Composing // internal for tests internal static string GetFileHash(IEnumerable filesAndFolders, IProfilingLogger logger) { - using (logger.TraceDuration("Determining hash of code files on disk", "Hash determined")) + using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined")) { using (var generator = new HashGenerator()) { @@ -666,7 +666,7 @@ namespace Umbraco.Core.Composing var name = GetName(baseType, attributeType); lock (_locko) - using (_logger.TraceDuration( + using (_logger.DebugDuration( "Getting " + name, "Got " + name)) // cannot contain typesFound.Count as it's evaluated before the find { From 1e8b8feee85eac0478470855148adc0d2849cb2b Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 17:59:12 +0100 Subject: [PATCH 093/555] Make ContainerControllerFactory exceptions more explicit --- src/Umbraco.Web/Mvc/ContainerControllerFactory.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Mvc/ContainerControllerFactory.cs b/src/Umbraco.Web/Mvc/ContainerControllerFactory.cs index 9262903355..cb732fdbb9 100644 --- a/src/Umbraco.Web/Mvc/ContainerControllerFactory.cs +++ b/src/Umbraco.Web/Mvc/ContainerControllerFactory.cs @@ -16,7 +16,14 @@ namespace Umbraco.Web.Mvc protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { - return (IController) _container.GetInstance(controllerType); + try + { + return (IController) _container.GetInstance(controllerType); + } + catch (Exception e) + { + throw new Exception($"Failed to create an instance of controller type {controllerType.FullName} (see inner exception).", e); + } } public override void ReleaseController(IController controller) From 0061f997e98763ca0f9376cefda74063caa24416 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 4 Feb 2019 17:12:41 +0000 Subject: [PATCH 094/555] Fix up logviewer - search error/mesage drodpwon button to search on Goggle, GitHub, Our.Umb etc --- .../src/views/logviewer/search.html | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/logviewer/search.html b/src/Umbraco.Web.UI.Client/src/views/logviewer/search.html index dc61f987b2..cccf620de3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logviewer/search.html +++ b/src/Umbraco.Web.UI.Client/src/views/logviewer/search.html @@ -159,18 +159,48 @@ From be881ba9ca7261d9a4a85a95338406025f5682e5 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 4 Feb 2019 20:09:17 +0100 Subject: [PATCH 095/555] Fix the redirect tracking composer --- src/Umbraco.Web/Routing/RedirectTrackingComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs b/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs index 1130f0880f..75ab4ad613 100644 --- a/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs +++ b/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs @@ -12,6 +12,6 @@ namespace Umbraco.Web.Routing /// recycle bin = moving to and from does nothing: to = the node is gone, where would we redirect? from = same /// [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - public class RedirectTrackingComposer : ComponentComposer, ICoreComposer + public class RedirectTrackingComposer : ComponentComposer, ICoreComposer { } } From b9d554908d1eef0afd79ba3706d7a8dbc59361e7 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 4 Feb 2019 21:03:45 +0100 Subject: [PATCH 096/555] Track redirects for invariant content under variant content --- src/Umbraco.Web/Routing/RedirectTrackingComponent.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs index c49dffd6e4..8877ee2884 100644 --- a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs +++ b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs @@ -157,9 +157,14 @@ namespace Umbraco.Web.Routing { var entityContent = contentCache.GetById(entity.Id); if (entityContent == null) continue; + + // get the default affected cultures by going up the tree until we find the first culture variant entity (default to no cultures) + var defaultCultures = entityContent.AncestorsOrSelf()?.FirstOrDefault(a => a.Cultures.Any())?.Cultures.Select(c => c.Key).ToArray() + ?? new[] {(string) null}; foreach (var x in entityContent.DescendantsOrSelf()) { - var cultures = x.Cultures.Any() ? x.Cultures.Select(c => c.Key) : new[] {(string) null}; + // if this entity defines specific cultures, use those instead of the default ones + var cultures = x.Cultures.Any() ? x.Cultures.Select(c => c.Key) : defaultCultures; foreach (var culture in cultures) { From 9f612465cf954eb349acdad06519b1c203dab800 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 5 Feb 2019 14:13:03 +1100 Subject: [PATCH 097/555] Cleans up IContent/IContentBase, no more internal methods or setters, moves manipulation used by the DocumentRepository to ext methods --- src/Umbraco.Core/ContentExtensions.cs | 2 +- src/Umbraco.Core/Models/Content.cs | 207 ++++-------------- src/Umbraco.Core/Models/ContentBase.cs | 75 +++---- .../Models/ContentRepositoryExtensions.cs | 159 ++++++++++++++ src/Umbraco.Core/Models/IContent.cs | 41 +--- src/Umbraco.Core/Models/IContentBase.cs | 6 +- .../Implement/DocumentRepository.cs | 62 +++--- .../Services/Implement/ContentService.cs | 10 +- .../Services/Implement/NotificationService.cs | 8 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Tests/Models/ContentTests.cs | 12 +- .../PublishedContentHashtableConverter.cs | 4 +- .../NuCache/PublishedSnapshotService.cs | 7 +- 13 files changed, 302 insertions(+), 292 deletions(-) create mode 100644 src/Umbraco.Core/Models/ContentRepositoryExtensions.cs diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 44e9907210..b2bf29cc5f 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -67,7 +67,7 @@ namespace Umbraco.Core if (!content.Published || !content.ContentType.VariesByCulture() || !content.IsPropertyDirty("PublishCultureInfos")) return Array.Empty(); - var culturesChanging = content.CultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key); + var culturesChanging = content.CultureInfos.Values.Where(x => x.IsDirty()).Select(x => x.Culture); return culturesChanging .Where(x => !content.IsCulturePublished(x) && // is not published anymore persisted != null && persisted.IsCulturePublished(x)) // but was published before diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 63ab65b8fe..09b0b41839 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -128,15 +128,16 @@ namespace Umbraco.Core.Models /// /// Gets or sets a value indicating whether this content item is published or not. /// + /// + /// the setter is should only be invoked from + /// - the ContentFactory when creating a content entity from a dto + /// - the ContentRepository when updating a content entity + /// [DataMember] public bool Published { get => _published; - - // the setter is internal and should only be invoked from - // - the ContentFactory when creating a content entity from a dto - // - the ContentRepository when updating a content entity - internal set + set { SetPropertyValueAndDetectChanges(value, ref _published, nameof(Published)); _publishedState = _published ? PublishedState.Published : PublishedState.Unpublished; @@ -162,7 +163,7 @@ namespace Umbraco.Core.Models } [IgnoreDataMember] - public bool Edited { get; internal set; } + public bool Edited { get; set; } /// /// Gets the ContentType used by this content object @@ -172,23 +173,27 @@ namespace Umbraco.Core.Models /// [IgnoreDataMember] - public DateTime? PublishDate { get; internal set; } // set by persistence + public DateTime? PublishDate { get; set; } // set by persistence /// [IgnoreDataMember] - public int? PublisherId { get; internal set; } // set by persistence + public int? PublisherId { get; set; } // set by persistence /// [IgnoreDataMember] - public int? PublishTemplateId { get; internal set; } // set by persistence + public int? PublishTemplateId { get; set; } // set by persistence /// [IgnoreDataMember] - public string PublishName { get; internal set; } // set by persistence + public string PublishName { get; set; } // set by persistence /// [IgnoreDataMember] - public IEnumerable EditedCultures => CultureInfos.Keys.Where(IsCultureEdited); + public IEnumerable EditedCultures + { + get => CultureInfos.Keys.Where(IsCultureEdited); + set => _editedCultures = value == null ? null : new HashSet(value, StringComparer.OrdinalIgnoreCase); + } /// [IgnoreDataMember] @@ -199,27 +204,7 @@ namespace Umbraco.Core.Models // just check _publishInfos // a non-available culture could not become published anyways => _publishInfos != null && _publishInfos.ContainsKey(culture); - - - // adjust dates to sync between version, cultures etc - // used by the repo when persisting - internal void AdjustDates(DateTime date) - { - foreach (var culture in PublishedCultures.ToList()) - { - if (_publishInfos == null || !_publishInfos.TryGetValue(culture, out var publishInfos)) - continue; - - //fixme: Removing the logic here for the old WasCulturePublished and the _publishInfosOrig has broken - // the test Can_Rollback_Version_On_Multilingual, but we need to understand what it's doing since I don't - - _publishInfos.AddOrUpdate(culture, publishInfos.Name, date); - - if (CultureInfos.TryGetValue(culture, out var infos)) - SetCultureInfo(culture, infos.Name, date); - } - } - + /// public bool IsCultureEdited(string culture) => IsCultureAvailable(culture) && // is available, and @@ -228,7 +213,23 @@ namespace Umbraco.Core.Models /// [IgnoreDataMember] - public IReadOnlyDictionary PublishCultureInfos => _publishInfos ?? NoInfos; + public ContentCultureInfosCollection PublishCultureInfos + { + get + { + if (_publishInfos != null) return _publishInfos; + _publishInfos = new ContentCultureInfosCollection(); + _publishInfos.CollectionChanged += PublishNamesCollectionChanged; + return _publishInfos; + } + set + { + if (_publishInfos != null) _publishInfos.CollectionChanged -= PublishNamesCollectionChanged; + _publishInfos = value; + if (_publishInfos != null) + _publishInfos.CollectionChanged += PublishNamesCollectionChanged; + } + } /// public string GetPublishName(string culture) @@ -247,67 +248,7 @@ namespace Umbraco.Core.Models if (_publishInfos == null) return null; return _publishInfos.TryGetValue(culture, out var infos) ? infos.Date : (DateTime?) null; } - - // internal for repository - internal void SetPublishInfo(string culture, string name, DateTime date) - { - if (string.IsNullOrWhiteSpace(name)) - throw new ArgumentNullOrEmptyException(nameof(name)); - - if (culture.IsNullOrWhiteSpace()) - throw new ArgumentNullOrEmptyException(nameof(culture)); - - if (_publishInfos == null) - { - _publishInfos = new ContentCultureInfosCollection(); - _publishInfos.CollectionChanged += PublishNamesCollectionChanged; - } - - _publishInfos.AddOrUpdate(culture, name, date); - } - - private void ClearPublishInfos() - { - _publishInfos = null; - } - - private void ClearPublishInfo(string culture) - { - if (culture.IsNullOrWhiteSpace()) - throw new ArgumentNullOrEmptyException(nameof(culture)); - - if (_publishInfos == null) return; - _publishInfos.Remove(culture); - if (_publishInfos.Count == 0) _publishInfos = null; - - // set the culture to be dirty - it's been modified - TouchCultureInfo(culture); - } - - // sets a publish edited - internal void SetCultureEdited(string culture) - { - if (culture.IsNullOrWhiteSpace()) - throw new ArgumentNullOrEmptyException(nameof(culture)); - if (_editedCultures == null) - _editedCultures = new HashSet(StringComparer.OrdinalIgnoreCase); - _editedCultures.Add(culture.ToLowerInvariant()); - } - - // sets all publish edited - internal void SetCultureEdited(IEnumerable cultures) - { - if (cultures == null) - { - _editedCultures = null; - } - else - { - var editedCultures = new HashSet(cultures.Where(x => !x.IsNullOrWhiteSpace()), StringComparer.OrdinalIgnoreCase); - _editedCultures = editedCultures.Count > 0 ? editedCultures : null; - } - } - + /// /// Handles culture infos collection changes. /// @@ -317,84 +258,10 @@ namespace Umbraco.Core.Models } [IgnoreDataMember] - public int PublishedVersionId { get; internal set; } + public int PublishedVersionId { get; set; } [DataMember] - public bool Blueprint { get; internal set; } - - /// - public bool PublishCulture(string culture = "*") - { - culture = culture.NullOrWhiteSpaceAsNull(); - - // the variation should be supported by the content type properties - // if the content type is invariant, only '*' and 'null' is ok - // if the content type varies, everything is ok because some properties may be invariant - if (!ContentType.SupportsPropertyVariation(culture, "*", true)) - throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{ContentType.Alias}\" with variation \"{ContentType.Variations}\"."); - - // the values we want to publish should be valid - if (ValidateProperties(culture).Any()) - return false; - - var alsoInvariant = false; - if (culture == "*") // all cultures - { - foreach (var c in AvailableCultures) - { - var name = GetCultureName(c); - if (string.IsNullOrWhiteSpace(name)) - return false; - SetPublishInfo(c, name, DateTime.Now); - } - } - else if (culture == null) // invariant culture - { - if (string.IsNullOrWhiteSpace(Name)) - return false; - // PublishName set by repository - nothing to do here - } - else // one single culture - { - var name = GetCultureName(culture); - if (string.IsNullOrWhiteSpace(name)) - return false; - SetPublishInfo(culture, name, DateTime.Now); - alsoInvariant = true; // we also want to publish invariant values - } - - // property.PublishValues only publishes what is valid, variation-wise - foreach (var property in Properties) - { - property.PublishValues(culture); - if (alsoInvariant) - property.PublishValues(null); - } - - _publishedState = PublishedState.Publishing; - return true; - } - - /// - public void UnpublishCulture(string culture = "*") - { - culture = culture.NullOrWhiteSpaceAsNull(); - - // the variation should be supported by the content type properties - if (!ContentType.SupportsPropertyVariation(culture, "*", true)) - throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{ContentType.Alias}\" with variation \"{ContentType.Variations}\"."); - - if (culture == "*") // all cultures - ClearPublishInfos(); - else // one single culture - ClearPublishInfo(culture); - - // property.PublishValues only publishes what is valid, variation-wise - foreach (var property in Properties) - property.UnpublishValues(culture); - - _publishedState = PublishedState.Publishing; - } + public bool Blueprint { get; set; } /// /// Changes the for the current content object diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index ad8e179e7a..b9301504c4 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -17,7 +17,6 @@ namespace Umbraco.Core.Models [DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")] public abstract class ContentBase : TreeEntityBase, IContentBase { - protected static readonly ContentCultureInfosCollection NoInfos = new ContentCultureInfosCollection(); private int _contentTypeId; protected IContentTypeComposition ContentTypeBase; @@ -69,20 +68,20 @@ namespace Umbraco.Core.Models /// Id of the user who wrote/updated this entity /// [DataMember] - public virtual int WriterId + public int WriterId { get => _writerId; set => SetPropertyValueAndDetectChanges(value, ref _writerId, nameof(WriterId)); } [IgnoreDataMember] - public int VersionId { get; internal set; } + public int VersionId { get; set; } /// /// Integer Id of the default ContentType /// [DataMember] - public virtual int ContentTypeId + public int ContentTypeId { get { @@ -105,11 +104,12 @@ namespace Umbraco.Core.Models /// [DataMember] [DoNotClone] - public virtual PropertyCollection Properties + public PropertyCollection Properties { get => _properties; set { + if (_properties != null) _properties.CollectionChanged -= PropertiesChanged; _properties = value; _properties.CollectionChanged += PropertiesChanged; } @@ -147,7 +147,23 @@ namespace Umbraco.Core.Models /// [DataMember] - public virtual IReadOnlyDictionary CultureInfos => _cultureInfos ?? NoInfos; + public ContentCultureInfosCollection CultureInfos + { + get + { + if (_cultureInfos != null) return _cultureInfos; + _cultureInfos = new ContentCultureInfosCollection(); + _cultureInfos.CollectionChanged += CultureInfosCollectionChanged; + return _cultureInfos; + } + set + { + if (_cultureInfos != null) _cultureInfos.CollectionChanged -= CultureInfosCollectionChanged; + _cultureInfos = value; + if (_cultureInfos != null) + _cultureInfos.CollectionChanged += CultureInfosCollectionChanged; + } + } /// public string GetCultureName(string culture) @@ -182,7 +198,7 @@ namespace Umbraco.Core.Models } else // set { - SetCultureInfo(culture, name, DateTime.Now); + this.SetCultureInfo(culture, name, DateTime.Now); } } else // set on invariant content type @@ -194,13 +210,13 @@ namespace Umbraco.Core.Models } } - protected void ClearCultureInfos() + private void ClearCultureInfos() { _cultureInfos?.Clear(); _cultureInfos = null; } - protected void ClearCultureInfo(string culture) + private void ClearCultureInfo(string culture) { if (culture.IsNullOrWhiteSpace()) throw new ArgumentNullOrEmptyException(nameof(culture)); @@ -211,30 +227,6 @@ namespace Umbraco.Core.Models _cultureInfos = null; } - protected void TouchCultureInfo(string culture) - { - if (_cultureInfos == null || !_cultureInfos.TryGetValue(culture, out var infos)) return; - _cultureInfos.AddOrUpdate(culture, infos.Name, DateTime.Now); - } - - // internal for repository - internal void SetCultureInfo(string culture, string name, DateTime date) - { - if (name.IsNullOrWhiteSpace()) - throw new ArgumentNullOrEmptyException(nameof(name)); - - if (culture.IsNullOrWhiteSpace()) - throw new ArgumentNullOrEmptyException(nameof(culture)); - - if (_cultureInfos == null) - { - _cultureInfos = new ContentCultureInfosCollection(); - _cultureInfos.CollectionChanged += CultureInfosCollectionChanged; - } - - _cultureInfos.AddOrUpdate(culture, name, date); - } - /// /// Handles culture infos collection changes. /// @@ -248,11 +240,11 @@ namespace Umbraco.Core.Models #region Has, Get, Set, Publish Property Value /// - public virtual bool HasProperty(string propertyTypeAlias) + public bool HasProperty(string propertyTypeAlias) => Properties.Contains(propertyTypeAlias); /// - public virtual object GetValue(string propertyTypeAlias, string culture = null, string segment = null, bool published = false) + public object GetValue(string propertyTypeAlias, string culture = null, string segment = null, bool published = false) { return Properties.TryGetValue(propertyTypeAlias, out var property) ? property.GetValue(culture, segment, published) @@ -260,7 +252,7 @@ namespace Umbraco.Core.Models } /// - public virtual TValue GetValue(string propertyTypeAlias, string culture = null, string segment = null, bool published = false) + public TValue GetValue(string propertyTypeAlias, string culture = null, string segment = null, bool published = false) { if (!Properties.TryGetValue(propertyTypeAlias, out var property)) return default; @@ -270,7 +262,7 @@ namespace Umbraco.Core.Models } /// - public virtual void SetValue(string propertyTypeAlias, object value, string culture = null, string segment = null) + public void SetValue(string propertyTypeAlias, object value, string culture = null, string segment = null) { if (Properties.Contains(propertyTypeAlias)) { @@ -292,7 +284,7 @@ namespace Umbraco.Core.Models #region Copy /// - public virtual void CopyFrom(IContent other, string culture = "*") + public void CopyFrom(IContent other, string culture = "*") { if (other.ContentTypeId != ContentTypeId) throw new InvalidOperationException("Cannot copy values from a different content type."); @@ -353,10 +345,11 @@ namespace Umbraco.Core.Models if (culture == null || culture == "*") Name = other.Name; - foreach (var (otherCulture, otherInfos) in other.CultureInfos) + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in other.CultureInfos) { - if (culture == "*" || culture == otherCulture) - SetCultureName(otherInfos.Name, otherCulture); + if (culture == "*" || culture == cultureInfo.Culture) + SetCultureName(cultureInfo.Name, cultureInfo.Culture); } } diff --git a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs new file mode 100644 index 0000000000..79c3dc3f63 --- /dev/null +++ b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Exceptions; + +namespace Umbraco.Core.Models +{ + /// + /// Extension methods used to manipulate content variations by the document repository + /// + internal static class ContentRepositoryExtensions + { + public static void SetPublishInfo(this IContent content, string culture, string name, DateTime date) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentNullOrEmptyException(nameof(name)); + + if (culture.IsNullOrWhiteSpace()) + throw new ArgumentNullOrEmptyException(nameof(culture)); + + content.PublishCultureInfos.AddOrUpdate(culture, name, date); + } + + // adjust dates to sync between version, cultures etc used by the repo when persisting + public static void AdjustDates(this IContent content, DateTime date) + { + foreach (var culture in content.PublishedCultures.ToList()) + { + if (!content.PublishCultureInfos.TryGetValue(culture, out var publishInfos)) + continue; + + //fixme: Removing the logic here for the old WasCulturePublished and the _publishInfosOrig has broken + // the test Can_Rollback_Version_On_Multilingual, but we need to understand what it's doing since I don't + + content.PublishCultureInfos.AddOrUpdate(culture, publishInfos.Name, date); + + if (content.CultureInfos.TryGetValue(culture, out var infos)) + SetCultureInfo(content, culture, infos.Name, date); + } + } + + // sets the edited cultures on the content + public static void SetCultureEdited(this IContent content, IEnumerable cultures) + { + if (cultures == null) + content.EditedCultures = null; + else + { + var editedCultures = new HashSet(cultures.Where(x => !x.IsNullOrWhiteSpace()), StringComparer.OrdinalIgnoreCase); + content.EditedCultures = editedCultures.Count > 0 ? editedCultures : null; + } + } + + public static void SetCultureInfo(this IContentBase content, string culture, string name, DateTime date) + { + if (name.IsNullOrWhiteSpace()) + throw new ArgumentNullOrEmptyException(nameof(name)); + + if (culture.IsNullOrWhiteSpace()) + throw new ArgumentNullOrEmptyException(nameof(culture)); + + content.CultureInfos.AddOrUpdate(culture, name, date); + } + + public static bool PublishCulture(this IContent content, string culture = "*") + { + culture = culture.NullOrWhiteSpaceAsNull(); + + // the variation should be supported by the content type properties + // if the content type is invariant, only '*' and 'null' is ok + // if the content type varies, everything is ok because some properties may be invariant + if (!content.ContentType.SupportsPropertyVariation(culture, "*", true)) + throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); + + // the values we want to publish should be valid + if (content.ValidateProperties(culture).Any()) + return false; + + var alsoInvariant = false; + if (culture == "*") // all cultures + { + foreach (var c in content.AvailableCultures) + { + var name = content.GetCultureName(c); + if (string.IsNullOrWhiteSpace(name)) + return false; + content.SetPublishInfo(c, name, DateTime.Now); + } + } + else if (culture == null) // invariant culture + { + if (string.IsNullOrWhiteSpace(content.Name)) + return false; + // PublishName set by repository - nothing to do here + } + else // one single culture + { + var name = content.GetCultureName(culture); + if (string.IsNullOrWhiteSpace(name)) + return false; + content.SetPublishInfo(culture, name, DateTime.Now); + alsoInvariant = true; // we also want to publish invariant values + } + + // property.PublishValues only publishes what is valid, variation-wise + foreach (var property in content.Properties) + { + property.PublishValues(culture); + if (alsoInvariant) + property.PublishValues(null); + } + + content.PublishedState = PublishedState.Publishing; + return true; + } + + public static void UnpublishCulture(this IContent content, string culture = "*") + { + culture = culture.NullOrWhiteSpaceAsNull(); + + // the variation should be supported by the content type properties + if (!content.ContentType.SupportsPropertyVariation(culture, "*", true)) + throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); + + if (culture == "*") // all cultures + content.ClearPublishInfos(); + else // one single culture + content.ClearPublishInfo(culture); + + // property.PublishValues only publishes what is valid, variation-wise + foreach (var property in content.Properties) + property.UnpublishValues(culture); + + content.PublishedState = PublishedState.Publishing; + } + + public static void ClearPublishInfos(this IContent content) + { + content.PublishCultureInfos = null; + } + + public static void ClearPublishInfo(this IContent content, string culture) + { + if (culture.IsNullOrWhiteSpace()) + throw new ArgumentNullOrEmptyException(nameof(culture)); + + content.PublishCultureInfos.Remove(culture); + + // set the culture to be dirty - it's been modified + content.TouchCultureInfo(culture); + } + + public static void TouchCultureInfo(this IContent content, string culture) + { + if (!content.CultureInfos.TryGetValue(culture, out var infos)) return; + content.CultureInfos.AddOrUpdate(culture, infos.Name, DateTime.Now); + } + } +} diff --git a/src/Umbraco.Core/Models/IContent.cs b/src/Umbraco.Core/Models/IContent.cs index f468df59ab..e953bef1eb 100644 --- a/src/Umbraco.Core/Models/IContent.cs +++ b/src/Umbraco.Core/Models/IContent.cs @@ -25,46 +25,46 @@ namespace Umbraco.Core.Models /// /// Gets a value indicating whether the content is published. /// - bool Published { get; } + bool Published { get; set; } - PublishedState PublishedState { get; } + PublishedState PublishedState { get; set; } /// /// Gets a value indicating whether the content has been edited. /// - bool Edited { get; } + bool Edited { get; set; } /// /// Gets the published version identifier. /// - int PublishedVersionId { get; } + int PublishedVersionId { get; set; } /// /// Gets a value indicating whether the content item is a blueprint. /// - bool Blueprint { get; } + bool Blueprint { get; set; } /// /// Gets the template id used to render the published version of the content. /// /// When editing the content, the template can change, but this will not until the content is published. - int? PublishTemplateId { get; } + int? PublishTemplateId { get; set; } /// /// Gets the name of the published version of the content. /// /// When editing the content, the name can change, but this will not until the content is published. - string PublishName { get; } + string PublishName { get; set; } /// /// Gets the identifier of the user who published the content. /// - int? PublisherId { get; } + int? PublisherId { get; set; } /// /// Gets the date and time the content was published. /// - DateTime? PublishDate { get; } + DateTime? PublishDate { get; set; } /// /// Gets the content type of this content. @@ -117,7 +117,7 @@ namespace Umbraco.Core.Models /// Because a dictionary key cannot be null this cannot get the invariant /// name, which must be get via the property. /// - IReadOnlyDictionary PublishCultureInfos { get; } + ContentCultureInfosCollection PublishCultureInfos { get; set; } /// /// Gets the published cultures. @@ -127,30 +127,13 @@ namespace Umbraco.Core.Models /// /// Gets the edited cultures. /// - IEnumerable EditedCultures { get; } + IEnumerable EditedCultures { get; set; } /// /// Creates a deep clone of the current entity with its identity/alias and it's property identities reset /// /// IContent DeepCloneWithResetIdentities(); - - /// - /// Registers a culture to be published. - /// - /// A value indicating whether the culture can be published. - /// - /// Fails if properties don't pass variant validation rules. - /// Publishing must be finalized via the content service SavePublishing method. - /// - bool PublishCulture(string culture = "*"); - - /// - /// Registers a culture to be unpublished. - /// - /// - /// Unpublishing must be finalized via the content service SavePublishing method. - /// - void UnpublishCulture(string culture = "*"); + } } diff --git a/src/Umbraco.Core/Models/IContentBase.cs b/src/Umbraco.Core/Models/IContentBase.cs index 40a1c57097..b3cc266f0a 100644 --- a/src/Umbraco.Core/Models/IContentBase.cs +++ b/src/Umbraco.Core/Models/IContentBase.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Models /// /// Gets the version identifier. /// - int VersionId { get; } + int VersionId { get; set; } /// /// Sets the name of the content item for a specified culture. @@ -57,8 +57,8 @@ namespace Umbraco.Core.Models /// Because a dictionary key cannot be null this cannot contain the invariant /// culture name, which must be get or set via the property. /// - IReadOnlyDictionary CultureInfos { get; } - + ContentCultureInfosCollection CultureInfos { get; set; } + /// /// Gets the available cultures. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 9b4175b63f..3cf407d304 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -380,9 +380,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement content.AdjustDates(contentVersionDto.VersionDate); // names also impact 'edited' - foreach (var (culture, infos) in content.CultureInfos) - if (infos.Name != content.GetPublishName(culture)) - (editedCultures ?? (editedCultures = new HashSet(StringComparer.OrdinalIgnoreCase))).Add(culture); + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in content.CultureInfos) + if (cultureInfo.Name != content.GetPublishName(cultureInfo.Culture)) + (editedCultures ?? (editedCultures = new HashSet(StringComparer.OrdinalIgnoreCase))).Add(cultureInfo.Culture); // insert content variations Database.BulkInsertRecords(GetContentVariationDtos(content, publishing)); @@ -541,11 +542,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement content.AdjustDates(contentVersionDto.VersionDate); // names also impact 'edited' - foreach (var (culture, infos) in content.CultureInfos) - if (infos.Name != content.GetPublishName(culture)) + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in content.CultureInfos) + if (cultureInfo.Name != content.GetPublishName(cultureInfo.Culture)) { edited = true; - (editedCultures ?? (editedCultures = new HashSet(StringComparer.OrdinalIgnoreCase))).Add(culture); + (editedCultures ?? (editedCultures = new HashSet(StringComparer.OrdinalIgnoreCase))).Add(cultureInfo.Culture); // TODO: change tracking // at the moment, we don't do any dirty tracking on property values, so we don't know whether the @@ -951,6 +953,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion + + protected override string ApplySystemOrdering(ref Sql sql, Ordering ordering) { // note: 'updater' is the user who created the latest draft version, @@ -1182,6 +1186,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return result; } + private void SetVariations(Content content, IDictionary> contentVariations, IDictionary> documentVariations) { if (contentVariations.TryGetValue(content.VersionId, out var contentVariation)) @@ -1191,8 +1196,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var v in contentVariation) content.SetPublishInfo(v.Culture, v.Name, v.Date); if (documentVariations.TryGetValue(content.Id, out var documentVariation)) - foreach (var v in documentVariation.Where(x => x.Edited)) - content.SetCultureEdited(v.Culture); + content.SetCultureEdited(documentVariation.Where(x => x.Edited).Select(x => x.Culture)); } private IDictionary> GetContentVariations(List> temps) @@ -1262,14 +1266,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private IEnumerable GetContentVariationDtos(IContent content, bool publishing) { // create dtos for the 'current' (non-published) version, all cultures - foreach (var (culture, name) in content.CultureInfos) + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in content.CultureInfos) yield return new ContentVersionCultureVariationDto { VersionId = content.VersionId, - LanguageId = LanguageRepository.GetIdByIsoCode(culture) ?? throw new InvalidOperationException("Not a valid culture."), - Culture = culture, - Name = name.Name, - UpdateDate = content.GetUpdateDate(culture) ?? DateTime.MinValue // we *know* there is a value + LanguageId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture) ?? throw new InvalidOperationException("Not a valid culture."), + Culture = cultureInfo.Culture, + Name = cultureInfo.Name, + UpdateDate = content.GetUpdateDate(cultureInfo.Culture) ?? DateTime.MinValue // we *know* there is a value }; // if not publishing, we're just updating the 'current' (non-published) version, @@ -1277,14 +1282,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (!publishing) yield break; // create dtos for the 'published' version, for published cultures (those having a name) - foreach (var (culture, name) in content.PublishCultureInfos) + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in content.PublishCultureInfos) yield return new ContentVersionCultureVariationDto { VersionId = content.PublishedVersionId, - LanguageId = LanguageRepository.GetIdByIsoCode(culture) ?? throw new InvalidOperationException("Not a valid culture."), - Culture = culture, - Name = name.Name, - UpdateDate = content.GetPublishDate(culture) ?? DateTime.MinValue // we *know* there is a value + LanguageId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture) ?? throw new InvalidOperationException("Not a valid culture."), + Culture = cultureInfo.Culture, + Name = cultureInfo.Name, + UpdateDate = content.GetPublishDate(cultureInfo.Culture) ?? DateTime.MinValue // we *know* there is a value }; } @@ -1344,7 +1350,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement EnsureVariantNamesAreUnique(content, publishing); } - private void EnsureInvariantNameExists(Content content) + private void EnsureInvariantNameExists(IContent content) { if (content.ContentType.VariesByCulture()) { @@ -1358,7 +1364,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var defaultCulture = LanguageRepository.GetDefaultIsoCode(); content.Name = defaultCulture != null && content.CultureInfos.TryGetValue(defaultCulture, out var cultureName) ? cultureName.Name - : content.CultureInfos.First().Value.Name; + : content.CultureInfos[0].Name; } else { @@ -1368,7 +1374,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } - private void EnsureInvariantNameIsUnique(Content content) + private void EnsureInvariantNameIsUnique(IContent content) { content.Name = EnsureUniqueNodeName(content.ParentId, content.Name, content.Id); } @@ -1405,22 +1411,22 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // of whether the name has changed (ie the culture has been updated) - some saving culture // fr-FR could cause culture en-UK name to change - not sure that is clean - foreach (var (culture, name) in content.CultureInfos) + foreach (var cultureInfo in content.CultureInfos) { - var langId = LanguageRepository.GetIdByIsoCode(culture); + var langId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture); if (!langId.HasValue) continue; if (!names.TryGetValue(langId.Value, out var cultureNames)) continue; // get a unique name var otherNames = cultureNames.Select(x => new SimilarNodeName { Id = x.Id, Name = x.Name }); - var uniqueName = SimilarNodeName.GetUniqueName(otherNames, 0, name.Name); + var uniqueName = SimilarNodeName.GetUniqueName(otherNames, 0, cultureInfo.Name); - if (uniqueName == content.GetCultureName(culture)) continue; + if (uniqueName == content.GetCultureName(cultureInfo.Culture)) continue; // update the name, and the publish name if published - content.SetCultureName(uniqueName, culture); - if (publishing && content.PublishCultureInfos.ContainsKey(culture)) - content.SetPublishInfo(culture, uniqueName, DateTime.Now); + content.SetCultureName(uniqueName, cultureInfo.Culture); + if (publishing && content.PublishCultureInfos.ContainsKey(cultureInfo.Culture)) + content.SetPublishInfo(cultureInfo.Culture, uniqueName, DateTime.Now); //TODO: This is weird, this call will have already been made in the SetCultureName } } diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index 9c2721cbb4..a6ef1b9f36 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -776,7 +776,7 @@ namespace Umbraco.Core.Services.Implement //track the cultures that have changed var culturesChanging = content.ContentType.VariesByCulture() - ? content.CultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key).ToList() + ? content.CultureInfos.Values.Where(x => x.IsDirty()).Select(x => x.Culture).ToList() : null; // TODO: Currently there's no way to change track which variant properties have changed, we only have change // tracking enabled on all values on the Property which doesn't allow us to know which variants have changed. @@ -1017,7 +1017,7 @@ namespace Umbraco.Core.Services.Implement IReadOnlyList culturesPublishing = null; IReadOnlyList culturesUnpublishing = null; IReadOnlyList culturesChanging = variesByCulture - ? content.CultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key).ToList() + ? content.CultureInfos.Values.Where(x => x.IsDirty()).Select(x => x.Culture).ToList() : null; var isNew = !content.HasIdentity; @@ -1036,7 +1036,7 @@ namespace Umbraco.Core.Services.Implement culturesUnpublishing = content.GetCulturesUnpublishing(persisted); culturesPublishing = variesByCulture - ? content.PublishCultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key).ToList() + ? content.PublishCultureInfos.Values.Where(x => x.IsDirty()).Select(x => x.Culture).ToList() : null; // ensure that the document can be published, and publish handling events, business rules, etc @@ -2043,7 +2043,7 @@ namespace Umbraco.Core.Services.Implement //track the cultures changing for auditing var culturesChanging = content.ContentType.VariesByCulture() - ? string.Join(",", content.CultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key)) + ? string.Join(",", content.CultureInfos.Values.Where(x => x.IsDirty()).Select(x => x.Culture)) : null; // TODO: Currently there's no way to change track which variant properties have changed, we only have change @@ -2781,7 +2781,7 @@ namespace Umbraco.Core.Services.Implement content.WriterId = userId; var now = DateTime.Now; - var cultures = blueprint.CultureInfos.Any() ? blueprint.CultureInfos.Select(x=>x.Key) : ArrayOfOneNullString; + var cultures = blueprint.CultureInfos.Count > 0 ? blueprint.CultureInfos.Values.Select(x => x.Culture) : ArrayOfOneNullString; foreach (var culture in cultures) { foreach (var property in blueprint.Properties) diff --git a/src/Umbraco.Core/Services/Implement/NotificationService.cs b/src/Umbraco.Core/Services/Implement/NotificationService.cs index d981809364..2b21945ba8 100644 --- a/src/Umbraco.Core/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Core/Services/Implement/NotificationService.cs @@ -345,8 +345,8 @@ namespace Umbraco.Core.Services.Implement { //Create the HTML based summary (ul of culture names) - var culturesChanged = content.CultureInfos.Where(x => x.Value.WasDirty()) - .Select(x => x.Key) + var culturesChanged = content.CultureInfos.Values.Where(x => x.WasDirty()) + .Select(x => x.Culture) .Select(_localizationService.GetLanguageByIsoCode) .WhereNotNull() .Select(x => x.CultureName); @@ -363,8 +363,8 @@ namespace Umbraco.Core.Services.Implement { //Create the text based summary (csv of culture names) - var culturesChanged = string.Join(", ", content.CultureInfos.Where(x => x.Value.WasDirty()) - .Select(x => x.Key) + var culturesChanged = string.Join(", ", content.CultureInfos.Values.Where(x => x.WasDirty()) + .Select(x => x.Culture) .Select(_localizationService.GetLanguageByIsoCode) .WhereNotNull() .Select(x => x.CultureName)); diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b327a9281d..13db7e2259 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -391,6 +391,7 @@ + diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 2e98b31cca..c5dd8a6aea 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -437,16 +437,16 @@ namespace Umbraco.Tests.Models Assert.IsTrue(content.WasPropertyDirty("CultureInfos")); foreach(var culture in content.CultureInfos) { - Assert.IsTrue(culture.Value.WasDirty()); - Assert.IsTrue(culture.Value.WasPropertyDirty("Name")); - Assert.IsTrue(culture.Value.WasPropertyDirty("Date")); + Assert.IsTrue(culture.WasDirty()); + Assert.IsTrue(culture.WasPropertyDirty("Name")); + Assert.IsTrue(culture.WasPropertyDirty("Date")); } Assert.IsTrue(content.WasPropertyDirty("PublishCultureInfos")); foreach (var culture in content.PublishCultureInfos) { - Assert.IsTrue(culture.Value.WasDirty()); - Assert.IsTrue(culture.Value.WasPropertyDirty("Name")); - Assert.IsTrue(culture.Value.WasPropertyDirty("Date")); + Assert.IsTrue(culture.WasDirty()); + Assert.IsTrue(culture.WasPropertyDirty("Name")); + Assert.IsTrue(culture.WasPropertyDirty("Date")); } } diff --git a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs index f40c8a7d98..9c02fa040d 100644 --- a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs +++ b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs @@ -252,8 +252,8 @@ namespace Umbraco.Web.Macros if (_cultureInfos != null) return _cultureInfos; - return _cultureInfos = _inner.PublishCultureInfos - .ToDictionary(x => x.Key, x => new PublishedCultureInfo(x.Key, x.Value.Name, x.Value.Date)); + return _cultureInfos = _inner.PublishCultureInfos.Values + .ToDictionary(x => x.Culture, x => new PublishedCultureInfo(x.Culture, x.Name, x.Date)); } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index f470e5a65a..c503f382dc 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -1214,10 +1214,11 @@ namespace Umbraco.Web.PublishedCache.NuCache : document.CultureInfos) : content.CultureInfos; - foreach (var (culture, info) in infos) + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in infos) { - var cultureIsDraft = !published && content is IContent d && d.IsCultureEdited(culture); - cultureData[culture] = new CultureVariation { Name = info.Name, Date = content.GetUpdateDate(culture) ?? DateTime.MinValue, IsDraft = cultureIsDraft }; + var cultureIsDraft = !published && content is IContent d && d.IsCultureEdited(cultureInfo.Culture); + cultureData[cultureInfo.Culture] = new CultureVariation { Name = cultureInfo.Name, Date = content.GetUpdateDate(cultureInfo.Culture) ?? DateTime.MinValue, IsDraft = cultureIsDraft }; } } From 3dab68b70d92c71ee4703aa3e1d65c3f149fc026 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 5 Feb 2019 14:15:03 +1100 Subject: [PATCH 098/555] adds note --- .../Persistence/Repositories/Implement/DocumentRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 3cf407d304..5a3a42af27 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -120,6 +120,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement break; case QueryType.Single: case QueryType.Many: + //fixme: Apparently this is ambiguous? sql = sql.Select(r => r.Select(documentDto => documentDto.ContentDto, r1 => r1.Select(contentDto => contentDto.NodeDto)) From c9936058b5112ec8913e7c8746ed87ec08f7ed3d Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 5 Feb 2019 07:54:42 +0100 Subject: [PATCH 099/555] Allow creating any content type at root if none are marked as "AllowAsRoot" --- src/Umbraco.Web/Editors/ContentTypeController.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 0aa7b75143..8df753bfe7 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -393,7 +393,11 @@ namespace Umbraco.Web.Editors IEnumerable types; if (contentId == Constants.System.Root) { - types = Services.ContentTypeService.GetAll().Where(x => x.AllowedAsRoot).ToList(); + var allContentTypes = Services.ContentTypeService.GetAll().ToList(); + bool AllowedAsRoot(IContentType x) => x.AllowedAsRoot; + types = allContentTypes.Any(AllowedAsRoot) + ? allContentTypes.Where(AllowedAsRoot).ToList() + : allContentTypes; } else { From 9579b42330199621c96c472a928ad033936e1d0e Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 5 Feb 2019 07:54:59 +0100 Subject: [PATCH 100/555] Allow copying/moving any content type to root if none are marked as "AllowAsRoot" --- src/Umbraco.Web/Editors/ContentController.cs | 6 ++++-- src/Umbraco.Web/Editors/MediaController.cs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index ee056e38f0..4e8c26b8e1 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1822,8 +1822,10 @@ namespace Umbraco.Web.Editors } if (model.ParentId < 0) { - //cannot move if the content item is not allowed at the root - if (toMove.ContentType.AllowedAsRoot == false) + //cannot move if the content item is not allowed at the root unless there are + //none allowed at root (in which case all should be allowed at root) + var contentTypeService = Services.ContentTypeService; + if (toMove.ContentType.AllowedAsRoot == false && contentTypeService.GetAll().Any(ct => ct.AllowedAsRoot)) { throw new HttpResponseException( Request.CreateNotificationValidationErrorResponse( diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 5662680a8a..5fab734f6c 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -868,8 +868,10 @@ namespace Umbraco.Web.Editors } if (model.ParentId < 0) { - //cannot move if the content item is not allowed at the root - if (toMove.ContentType.AllowedAsRoot == false) + //cannot move if the content item is not allowed at the root unless there are + //none allowed at root (in which case all should be allowed at root) + var mediaTypeService = Services.MediaTypeService; + if (toMove.ContentType.AllowedAsRoot == false && mediaTypeService.GetAll().Any(ct => ct.AllowedAsRoot)) { var notificationModel = new SimpleNotificationModel(); notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedAtRoot"), ""); From f07a2715b42275ae5f68dab2075a4e62984421f8 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 18:49:56 +0100 Subject: [PATCH 101/555] Add assembly-level composer attributes --- src/Umbraco.Core/Components/Composers.cs | 43 +- .../Components/DisableAttribute.cs | 5 +- .../Components/DisableComposerAttribute.cs | 28 ++ .../Components/EnableAttribute.cs | 5 +- .../Components/EnableComposerAttribute.cs | 31 ++ src/Umbraco.Core/Umbraco.Core.csproj | 2 + .../Components/ComponentTests.cs | 55 ++- src/Umbraco.Web.UI.Client/package-lock.json | 466 +++++------------- 8 files changed, 268 insertions(+), 367 deletions(-) create mode 100644 src/Umbraco.Core/Components/DisableComposerAttribute.cs create mode 100644 src/Umbraco.Core/Components/EnableComposerAttribute.cs diff --git a/src/Umbraco.Core/Components/Composers.cs b/src/Umbraco.Core/Components/Composers.cs index 89deed934e..4bbbdf26b0 100644 --- a/src/Umbraco.Core/Components/Composers.cs +++ b/src/Umbraco.Core/Components/Composers.cs @@ -173,27 +173,46 @@ namespace Umbraco.Core.Components // what happens in case of conflicting remote declarations is unspecified. more // precisely, the last declaration to be processed wins, but the order of the // declarations depends on the type finder and is unspecified. + + void UpdateEnableInfo(Type composerType, int weight2, Dictionary enabled2, bool value) + { + if (enabled.TryGetValue(composerType, out var enableInfo) == false) enableInfo = enabled2[composerType] = new EnableInfo(); + if (enableInfo.Weight > weight2) return; + + enableInfo.Enabled = value; + enableInfo.Weight = weight2; + } + + var assemblies = types.Select(x => x.Assembly).Distinct(); + foreach (var assembly in assemblies) + { + foreach (var attr in assembly.GetCustomAttributes()) + { + var type = attr.EnabledType; + UpdateEnableInfo(type, 2, enabled, true); + } + + foreach (var attr in assembly.GetCustomAttributes()) + { + var type = attr.DisabledType; + UpdateEnableInfo(type, 2, enabled, false); + } + } + foreach (var composerType in types) { foreach (var attr in composerType.GetCustomAttributes()) { var type = attr.EnabledType ?? composerType; - if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo(); - var weight = type == composerType ? 1 : 2; - if (enableInfo.Weight > weight) continue; - - enableInfo.Enabled = true; - enableInfo.Weight = weight; + var weight = type == composerType ? 1 : 3; + UpdateEnableInfo(type, weight, enabled, true); } + foreach (var attr in composerType.GetCustomAttributes()) { var type = attr.DisabledType ?? composerType; - if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo(); - var weight = type == composerType ? 1 : 2; - if (enableInfo.Weight > weight) continue; - - enableInfo.Enabled = false; - enableInfo.Weight = weight; + var weight = type == composerType ? 1 : 3; + UpdateEnableInfo(type, weight, enabled, false); } } diff --git a/src/Umbraco.Core/Components/DisableAttribute.cs b/src/Umbraco.Core/Components/DisableAttribute.cs index f9a7249b89..608967d6ae 100644 --- a/src/Umbraco.Core/Components/DisableAttribute.cs +++ b/src/Umbraco.Core/Components/DisableAttribute.cs @@ -9,9 +9,8 @@ namespace Umbraco.Core.Components /// If a type is specified, disables the composer of that type, else disables the composer marked with the attribute. /// This attribute is *not* inherited. /// This attribute applies to classes only, it is not possible to enable/disable interfaces. - /// If a composer ends up being both enabled and disabled: attributes marking the composer itself have lower priority - /// than attributes on *other* composers, eg if a composer declares itself as disabled it is possible to enable it from - /// another composer. Anything else is unspecified. + /// Assembly-level has greater priority than + /// attribute when it is marking the composer itself, but lower priority that when it is referencing another composer. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] public class DisableAttribute : Attribute diff --git a/src/Umbraco.Core/Components/DisableComposerAttribute.cs b/src/Umbraco.Core/Components/DisableComposerAttribute.cs new file mode 100644 index 0000000000..9d90a099df --- /dev/null +++ b/src/Umbraco.Core/Components/DisableComposerAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace Umbraco.Core.Components +{ + /// + /// Indicates that a composer should be disabled. + /// + /// + /// Assembly-level has greater priority than + /// attribute when it is marking the composer itself, but lower priority that when it is referencing another composer. + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] + public class DisableComposerAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DisableComposerAttribute(Type disabledType) + { + DisabledType = disabledType; + } + + /// + /// Gets the disabled type, or null if it is the composer marked with the attribute. + /// + public Type DisabledType { get; } + } +} diff --git a/src/Umbraco.Core/Components/EnableAttribute.cs b/src/Umbraco.Core/Components/EnableAttribute.cs index edf3cbdc2e..2176a4ec23 100644 --- a/src/Umbraco.Core/Components/EnableAttribute.cs +++ b/src/Umbraco.Core/Components/EnableAttribute.cs @@ -9,9 +9,8 @@ namespace Umbraco.Core.Components /// If a type is specified, enables the composer of that type, else enables the composer marked with the attribute. /// This attribute is *not* inherited. /// This attribute applies to classes only, it is not possible to enable/disable interfaces. - /// If a composer ends up being both enabled and disabled: attributes marking the composer itself have lower priority - /// than attributes on *other* composers, eg if a composer declares itself as disabled it is possible to enable it from - /// another composer. Anything else is unspecified. + /// Assembly-level has greater priority than + /// attribute when it is marking the composer itself, but lower priority that when it is referencing another composer. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] public class EnableAttribute : Attribute diff --git a/src/Umbraco.Core/Components/EnableComposerAttribute.cs b/src/Umbraco.Core/Components/EnableComposerAttribute.cs new file mode 100644 index 0000000000..fe57700145 --- /dev/null +++ b/src/Umbraco.Core/Components/EnableComposerAttribute.cs @@ -0,0 +1,31 @@ +using System; + +namespace Umbraco.Core.Components +{ + /// + /// Indicates that a composer should be enabled. + /// + /// + /// If a type is specified, enables the composer of that type, else enables the composer marked with the attribute. + /// This attribute is *not* inherited. + /// This attribute applies to classes only, it is not possible to enable/disable interfaces. + /// Assembly-level has greater priority than + /// attribute when it is marking the composer itself, but lower priority that when it is referencing another composer. + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] + public class EnableComposerAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + public EnableComposerAttribute(Type enabledType) + { + EnabledType = enabledType; + } + + /// + /// Gets the enabled type, or null if it is the composer marked with the attribute. + /// + public Type EnabledType { get; } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b327a9281d..792f1d1223 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -163,7 +163,9 @@ + + diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs index 390bb018da..b35813ce99 100644 --- a/src/Umbraco.Tests/Components/ComponentTests.cs +++ b/src/Umbraco.Tests/Components/ComponentTests.cs @@ -12,6 +12,8 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Scoping; +[assembly:DisableComposer(typeof(Umbraco.Tests.Components.ComponentTests.Composer26))] + namespace Umbraco.Tests.Components { [TestFixture] @@ -104,7 +106,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Run)); var types = TypeArray(); - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); // 2 is Core and requires 4 // 3 is User - stays with RuntimeLevel.Run @@ -120,7 +122,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = TypeArray(); - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); // 21 is required by 20 // => reorder components accordingly @@ -135,7 +137,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = TypeArray(); - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); // i23 requires 22 // 24, 25 implement i23 @@ -152,7 +154,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = TypeArray(); - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); try { @@ -175,7 +177,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = TypeArray(); - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); // 2 is Core and requires 4 // 13 is required by 1 @@ -234,7 +236,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) }; - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); components.Compose(); Assert.AreEqual(2, Composed.Count); @@ -249,7 +251,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); components.Compose(); Assert.AreEqual(2, Composed.Count); @@ -285,24 +287,24 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = new[] { typeof(Composer10) }; - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); components.Compose(); Assert.AreEqual(1, Composed.Count); Assert.AreEqual(typeof(Composer10), Composed[0]); types = new[] { typeof(Composer11) }; - components = new Core.Components.Composers(composition, types, Mock.Of()); + components = new Composers(composition, types, Mock.Of()); Composed.Clear(); Assert.Throws(() => components.Compose()); types = new[] { typeof(Composer2) }; - components = new Core.Components.Composers(composition, types, Mock.Of()); + components = new Composers(composition, types, Mock.Of()); Composed.Clear(); Assert.Throws(() => components.Compose()); types = new[] { typeof(Composer12) }; - components = new Core.Components.Composers(composition, types, Mock.Of()); + components = new Composers(composition, types, Mock.Of()); Composed.Clear(); components.Compose(); Assert.AreEqual(1, Composed.Count); @@ -316,7 +318,7 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var components = new Composers(composition, types, Mock.Of()); Composed.Clear(); components.Compose(); Assert.AreEqual(2, Composed.Count); @@ -324,6 +326,27 @@ namespace Umbraco.Tests.Components Assert.AreEqual(typeof(Composer8), Composed[1]); } + [Test] + public void AttributesPriorities() + { + var register = MockRegister(); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); + + var types = new[] { typeof(Composer26) }; // 26 disabled by assembly attribute + var components = new Composers(composition, types, Mock.Of()); + Composed.Clear(); + components.Compose(); + Assert.AreEqual(0, Composed.Count); // 26 gone + + types = new[] { typeof(Composer26), typeof(Composer27) }; // 26 disabled by assembly attribute, enabled by 27 + components = new Composers(composition, types, Mock.Of()); + Composed.Clear(); + components.Compose(); + Assert.AreEqual(2, Composed.Count); // both + Assert.AreEqual(typeof(Composer26), Composed[0]); + Assert.AreEqual(typeof(Composer27), Composed[1]); + } + #region Components public class TestComposerBase : IComposer @@ -440,6 +463,14 @@ namespace Umbraco.Tests.Components public class Composer25 : TestComposerBase, IComposer23 { } + // disabled by assembly attribute + public class Composer26 : TestComposerBase + { } + + [Enable(typeof(Composer26))] + public class Composer27 : TestComposerBase + { } + #endregion #region TypeArray diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 207eba38c5..4c796ab2a7 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -937,7 +937,7 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { @@ -955,7 +955,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -1104,7 +1104,6 @@ "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.2.0.tgz", "integrity": "sha1-nNnABpV+vpX62tW9YJiUKoE3N/Y=", "dev": true, - "optional": true, "requires": { "file-type": "^3.1.0" }, @@ -1113,8 +1112,7 @@ "version": "3.9.0", "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true, - "optional": true + "dev": true } } }, @@ -1172,7 +1170,7 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", "dev": true }, "array-sort": { @@ -1218,7 +1216,7 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", "dev": true }, "asap": { @@ -1271,7 +1269,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", "dev": true }, "asynckit": { @@ -1525,7 +1523,6 @@ "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -1748,8 +1745,7 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "optional": true + "dev": true }, "buffer-fill": { "version": "1.0.0", @@ -1768,7 +1764,6 @@ "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz", "integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=", "dev": true, - "optional": true, "requires": { "file-type": "^3.1.0", "readable-stream": "^2.0.2", @@ -1780,22 +1775,19 @@ "version": "3.9.0", "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true, - "optional": true + "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1811,7 +1803,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -1820,15 +1811,13 @@ "version": "2.0.3", "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", - "dev": true, - "optional": true + "dev": true }, "vinyl": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, - "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -1949,8 +1938,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true, - "optional": true + "dev": true }, "caseless": { "version": "0.12.0", @@ -1963,7 +1951,6 @@ "resolved": "https://registry.npmjs.org/caw/-/caw-1.2.0.tgz", "integrity": "sha1-/7Im/n78VHKI3GLuPpcHPCEtEDQ=", "dev": true, - "optional": true, "requires": { "get-proxy": "^1.0.1", "is-obj": "^1.0.0", @@ -1975,8 +1962,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true, - "optional": true + "dev": true } } }, @@ -2237,8 +2223,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=", - "dev": true, - "optional": true + "dev": true }, "coa": { "version": "2.0.1", @@ -2334,7 +2319,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, - "optional": true, "requires": { "graceful-readlink": ">= 1.0.0" } @@ -2398,7 +2382,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -2478,7 +2462,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "continuable-cache": { @@ -2521,7 +2505,7 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=", "dev": true }, "core-util-is": { @@ -2547,7 +2531,6 @@ "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, - "optional": true, "requires": { "capture-stack-trace": "^1.0.0" } @@ -2802,7 +2785,6 @@ "resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz", "integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=", "dev": true, - "optional": true, "requires": { "buffer-to-vinyl": "^1.0.0", "concat-stream": "^1.4.6", @@ -2820,7 +2802,6 @@ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, - "optional": true, "requires": { "arr-flatten": "^1.0.1" } @@ -2829,15 +2810,13 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true, - "optional": true + "dev": true }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, - "optional": true, "requires": { "expand-range": "^1.8.1", "preserve": "^0.2.0", @@ -2849,7 +2828,6 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, - "optional": true, "requires": { "is-posix-bracket": "^0.1.0" } @@ -2859,7 +2837,6 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -2869,7 +2846,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, - "optional": true, "requires": { "inflight": "^1.0.4", "inherits": "2", @@ -2883,7 +2859,6 @@ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", "dev": true, - "optional": true, "requires": { "extend": "^3.0.0", "glob": "^5.0.3", @@ -2899,15 +2874,13 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -2919,15 +2892,13 @@ "version": "0.10.31", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true, - "optional": true + "dev": true }, "through2": { "version": "0.6.5", "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, - "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -2939,22 +2910,19 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true, - "optional": true + "dev": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -2963,15 +2931,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -2981,7 +2947,6 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, - "optional": true, "requires": { "arr-diff": "^2.0.0", "array-unique": "^0.2.1", @@ -3002,15 +2967,13 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true }, "ordered-read-streams": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", "dev": true, - "optional": true, "requires": { "is-stream": "^1.0.1", "readable-stream": "^2.0.1" @@ -3021,7 +2984,6 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3037,7 +2999,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3047,7 +3008,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, - "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -3057,7 +3017,6 @@ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", "dev": true, - "optional": true, "requires": { "first-chunk-stream": "^1.0.0", "strip-bom": "^2.0.0" @@ -3068,7 +3027,6 @@ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", "dev": true, - "optional": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", "through2-filter": "^3.0.0" @@ -3079,7 +3037,6 @@ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, - "optional": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" @@ -3092,7 +3049,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, - "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -3104,7 +3060,6 @@ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", "dev": true, - "optional": true, "requires": { "duplexify": "^3.2.0", "glob-stream": "^5.3.2", @@ -3132,7 +3087,6 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz", "integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=", "dev": true, - "optional": true, "requires": { "is-tar": "^1.0.0", "object-assign": "^2.0.0", @@ -3146,22 +3100,19 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3174,7 +3125,6 @@ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, - "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3185,7 +3135,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, - "optional": true, "requires": { "clone": "^0.2.0", "clone-stats": "^0.0.1" @@ -3198,7 +3147,6 @@ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz", "integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=", "dev": true, - "optional": true, "requires": { "is-bzip2": "^1.0.0", "object-assign": "^2.0.0", @@ -3213,22 +3161,19 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3241,7 +3186,6 @@ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, - "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3252,7 +3196,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, - "optional": true, "requires": { "clone": "^0.2.0", "clone-stats": "^0.0.1" @@ -3265,7 +3208,6 @@ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz", "integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=", "dev": true, - "optional": true, "requires": { "is-gzip": "^1.0.0", "object-assign": "^2.0.0", @@ -3279,22 +3221,19 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3307,7 +3246,6 @@ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, - "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3318,7 +3256,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, - "optional": true, "requires": { "clone": "^0.2.0", "clone-stats": "^0.0.1" @@ -3331,7 +3268,6 @@ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz", "integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=", "dev": true, - "optional": true, "requires": { "is-zip": "^1.0.0", "read-all-stream": "^3.0.0", @@ -3347,7 +3283,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, - "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -3360,8 +3295,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true + "dev": true }, "deep-is": { "version": "0.1.3", @@ -3494,7 +3428,7 @@ "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", "dev": true, "requires": { "esutils": "^2.0.2" @@ -3560,7 +3494,6 @@ "resolved": "https://registry.npmjs.org/download/-/download-4.4.3.tgz", "integrity": "sha1-qlX9rTktldS2jowr4D4MKqIbqaw=", "dev": true, - "optional": true, "requires": { "caw": "^1.0.1", "concat-stream": "^1.4.7", @@ -3584,7 +3517,6 @@ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, - "optional": true, "requires": { "arr-flatten": "^1.0.1" } @@ -3593,15 +3525,13 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true, - "optional": true + "dev": true }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, - "optional": true, "requires": { "expand-range": "^1.8.1", "preserve": "^0.2.0", @@ -3613,7 +3543,6 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, - "optional": true, "requires": { "is-posix-bracket": "^0.1.0" } @@ -3623,7 +3552,6 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -3633,7 +3561,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, - "optional": true, "requires": { "inflight": "^1.0.4", "inherits": "2", @@ -3647,7 +3574,6 @@ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", "dev": true, - "optional": true, "requires": { "extend": "^3.0.0", "glob": "^5.0.3", @@ -3663,15 +3589,13 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3683,15 +3607,13 @@ "version": "0.10.31", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true, - "optional": true + "dev": true }, "through2": { "version": "0.6.5", "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, - "optional": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", "xtend": ">=4.0.0 <4.1.0-0" @@ -3703,22 +3625,19 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true, - "optional": true + "dev": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -3727,15 +3646,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -3745,7 +3662,6 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, - "optional": true, "requires": { "arr-diff": "^2.0.0", "array-unique": "^0.2.1", @@ -3766,15 +3682,13 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true }, "ordered-read-streams": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", "dev": true, - "optional": true, "requires": { "is-stream": "^1.0.1", "readable-stream": "^2.0.1" @@ -3785,7 +3699,6 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3801,7 +3714,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3811,7 +3723,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, - "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -3821,7 +3732,6 @@ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", "dev": true, - "optional": true, "requires": { "first-chunk-stream": "^1.0.0", "strip-bom": "^2.0.0" @@ -3832,7 +3742,6 @@ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", "dev": true, - "optional": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", "through2-filter": "^3.0.0" @@ -3843,7 +3752,6 @@ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, - "optional": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" @@ -3856,7 +3764,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, - "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -3868,7 +3775,6 @@ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", "dev": true, - "optional": true, "requires": { "duplexify": "^3.2.0", "glob-stream": "^5.3.2", @@ -3911,7 +3817,6 @@ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", "dev": true, - "optional": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -3924,7 +3829,6 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, - "optional": true, "requires": { "once": "^1.4.0" } @@ -3933,15 +3837,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3951,7 +3853,6 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3967,7 +3868,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3979,7 +3879,6 @@ "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz", "integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=", "dev": true, - "optional": true, "requires": { "onetime": "^1.0.0", "set-immediate-shim": "^1.0.0" @@ -3989,8 +3888,7 @@ "version": "1.1.0", "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true, - "optional": true + "dev": true } } }, @@ -4058,7 +3956,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -4094,7 +3992,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -4258,7 +4156,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true, "optional": true } @@ -4353,7 +4251,7 @@ "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -4363,13 +4261,13 @@ "eslint-utils": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=", "dev": true }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", "dev": true }, "espree": { @@ -4392,7 +4290,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -4401,7 +4299,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -4461,7 +4359,7 @@ "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=", "dev": true }, "exec-buffer": { @@ -4676,7 +4574,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", "dev": true, "requires": { "is-number": "^2.1.0", @@ -4930,7 +4828,6 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, - "optional": true, "requires": { "pend": "~1.2.0" } @@ -4978,15 +4875,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz", "integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=", - "dev": true, - "optional": true + "dev": true }, "filenamify": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz", "integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=", "dev": true, - "optional": true, "requires": { "filename-reserved-regex": "^1.0.0", "strip-outer": "^1.0.0", @@ -5233,8 +5128,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", - "dev": true, - "optional": true + "dev": true }, "fs-extra": { "version": "1.0.0", @@ -5298,8 +5192,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5320,14 +5213,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5342,20 +5233,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5472,8 +5360,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5485,7 +5372,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5500,7 +5386,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5508,14 +5393,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5534,7 +5417,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5615,8 +5497,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5628,7 +5509,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5714,8 +5594,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5751,7 +5630,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5771,7 +5649,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5815,14 +5692,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -5858,7 +5733,6 @@ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz", "integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=", "dev": true, - "optional": true, "requires": { "rc": "^1.1.2" } @@ -6020,7 +5894,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -6165,7 +6039,6 @@ "resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz", "integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=", "dev": true, - "optional": true, "requires": { "create-error-class": "^3.0.1", "duplexer2": "^0.1.4", @@ -6189,7 +6062,6 @@ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.0.2" } @@ -6198,22 +6070,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, - "optional": true, "requires": { "error-ex": "^1.2.0" } @@ -6223,7 +6092,6 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6239,7 +6107,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -6259,8 +6126,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true, - "optional": true + "dev": true }, "growly": { "version": "1.3.0", @@ -6556,7 +6422,6 @@ "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.2.0.tgz", "integrity": "sha1-jutlpeAV+O2FMsr+KEVJYGJvDcc=", "dev": true, - "optional": true, "requires": { "archive-type": "^3.0.0", "decompress": "^3.0.0", @@ -6568,15 +6433,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6592,7 +6455,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -6602,7 +6464,7 @@ "gulp-eslint": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz", - "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", + "integrity": "sha1-KiaECV93Syz3kxAmIHjFbMehK1I=", "dev": true, "requires": { "eslint": "^5.0.1", @@ -7210,7 +7072,6 @@ "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", "dev": true, - "optional": true, "requires": { "convert-source-map": "^1.1.1", "graceful-fs": "^4.1.2", @@ -7223,15 +7084,13 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true, - "optional": true + "dev": true }, "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, - "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -7241,7 +7100,6 @@ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, - "optional": true, "requires": { "clone": "^1.0.0", "clone-stats": "^0.0.1", @@ -7560,7 +7418,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", "dev": true, "requires": { "isarray": "2.0.1" @@ -7711,7 +7569,7 @@ "http-proxy": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", "dev": true, "requires": { "eventemitter3": "^3.0.0", @@ -8005,7 +7863,7 @@ "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -8072,8 +7930,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz", "integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=", - "dev": true, - "optional": true + "dev": true }, "is-callable": { "version": "1.1.4", @@ -8208,8 +8065,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=", - "dev": true, - "optional": true + "dev": true }, "is-jpg": { "version": "1.0.1", @@ -8222,8 +8078,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz", "integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=", - "dev": true, - "optional": true + "dev": true }, "is-number": { "version": "3.0.0", @@ -8289,8 +8144,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true, - "optional": true + "dev": true }, "is-regex": { "version": "1.0.4", @@ -8304,7 +8158,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -8313,15 +8167,14 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", "dev": true }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true, - "optional": true + "dev": true }, "is-stream": { "version": "1.1.0", @@ -8351,8 +8204,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz", "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=", - "dev": true, - "optional": true + "dev": true }, "is-typedarray": { "version": "1.0.0", @@ -8363,7 +8215,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -8373,8 +8225,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true, - "optional": true + "dev": true }, "is-utf8": { "version": "0.2.1", @@ -8386,8 +8237,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=", - "dev": true, - "optional": true + "dev": true }, "is-windows": { "version": "1.0.2", @@ -8405,8 +8255,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=", - "dev": true, - "optional": true + "dev": true }, "isarray": { "version": "0.0.1", @@ -8523,7 +8372,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -8650,7 +8499,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -8727,7 +8576,6 @@ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.0.5" }, @@ -8736,15 +8584,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8760,7 +8606,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -9066,8 +8911,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true, - "optional": true + "dev": true }, "lodash.isobject": { "version": "2.4.1", @@ -9264,8 +9108,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", - "dev": true, - "optional": true + "dev": true }, "lpad-align": { "version": "1.1.2", @@ -9306,7 +9149,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -9487,7 +9330,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", "dev": true }, "minimatch": { @@ -9661,8 +9504,7 @@ "version": "1.0.0", "resolved": "http://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=", - "dev": true, - "optional": true + "dev": true }, "node.extend": { "version": "1.1.8", @@ -12712,8 +12554,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true + "dev": true }, "p-pipe": { "version": "1.2.0", @@ -13017,7 +12858,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", "dev": true }, "posix-character-classes": { @@ -13424,8 +13265,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true, - "optional": true + "dev": true }, "preserve": { "version": "0.2.0", @@ -13508,7 +13348,7 @@ "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", "dev": true }, "qs": { @@ -13557,7 +13397,6 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "optional": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -13570,7 +13409,6 @@ "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", "dev": true, - "optional": true, "requires": { "pinkie-promise": "^2.0.0", "readable-stream": "^2.0.0" @@ -13580,15 +13418,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13604,7 +13440,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13709,7 +13544,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -14207,7 +14042,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", "dev": true }, "sax": { @@ -14221,7 +14056,6 @@ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", "dev": true, - "optional": true, "requires": { "commander": "~2.8.1" } @@ -14367,8 +14201,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true, - "optional": true + "dev": true }, "set-value": { "version": "2.0.0", @@ -14396,7 +14229,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", "dev": true }, "shebang-command": { @@ -14686,7 +14519,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -14873,8 +14706,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=", - "dev": true, - "optional": true + "dev": true }, "static-extend": { "version": "0.1.2", @@ -14918,7 +14750,6 @@ "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, - "optional": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" @@ -14929,7 +14760,6 @@ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.0.2" } @@ -14938,15 +14768,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14962,7 +14790,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -14972,20 +14799,19 @@ "stream-consume": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", + "integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=", "dev": true }, "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", - "dev": true, - "optional": true + "dev": true }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", "dev": true, "requires": { "date-format": "^1.2.0", @@ -15012,7 +14838,7 @@ "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -15027,7 +14853,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -15044,7 +14870,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -15158,7 +14984,6 @@ "resolved": "http://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz", "integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=", "dev": true, - "optional": true, "requires": { "chalk": "^1.0.0", "get-stdin": "^4.0.1", @@ -15172,15 +14997,13 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "optional": true + "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, - "optional": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -15194,7 +15017,6 @@ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=", "dev": true, - "optional": true, "requires": { "is-relative": "^0.1.0" } @@ -15203,15 +15025,13 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=", - "dev": true, - "optional": true + "dev": true }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "optional": true + "dev": true } } }, @@ -15242,7 +15062,6 @@ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15276,7 +15095,6 @@ "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz", "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=", "dev": true, - "optional": true, "requires": { "chalk": "^1.0.0" }, @@ -15285,15 +15103,13 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "optional": true + "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, - "optional": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -15306,8 +15122,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "optional": true + "dev": true } } }, @@ -15369,7 +15184,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, - "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -15385,7 +15199,6 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "dev": true, - "optional": true, "requires": { "once": "^1.4.0" } @@ -15394,15 +15207,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -15412,7 +15223,6 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15428,7 +15238,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15527,7 +15336,6 @@ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", "dev": true, - "optional": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" @@ -15552,8 +15360,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz", "integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=", - "dev": true, - "optional": true + "dev": true }, "timsort": { "version": "0.3.0", @@ -15605,7 +15412,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -15616,7 +15423,6 @@ "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=", "dev": true, - "optional": true, "requires": { "extend-shallow": "^2.0.1" }, @@ -15626,7 +15432,6 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, - "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -15643,8 +15448,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", - "dev": true, - "optional": true + "dev": true }, "to-fast-properties": { "version": "2.0.0", @@ -15723,7 +15527,6 @@ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15773,7 +15576,7 @@ "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", "dev": true, "requires": { "media-typer": "0.3.0", @@ -15815,7 +15618,7 @@ "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=", "dev": true }, "unc-path-regex": { @@ -15972,19 +15775,18 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", - "dev": true, - "optional": true + "dev": true }, "upath": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0=", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", "dev": true, "requires": { "punycode": "^2.1.0" @@ -16001,7 +15803,6 @@ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, - "optional": true, "requires": { "prepend-http": "^1.0.1" } @@ -16087,8 +15888,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", - "dev": true, - "optional": true + "dev": true }, "validate-npm-package-license": { "version": "3.0.4", @@ -16133,7 +15933,6 @@ "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz", "integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=", "dev": true, - "optional": true, "requires": { "object-assign": "^4.0.1", "readable-stream": "^2.0.0" @@ -16143,22 +15942,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16174,7 +15970,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -16314,7 +16109,6 @@ "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz", "integrity": "sha1-0bFPOdLiy0q4xAmPdW/ksWTkc9Q=", "dev": true, - "optional": true, "requires": { "wrap-fn": "^0.1.0" } @@ -16405,7 +16199,6 @@ "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz", "integrity": "sha1-8htuQQFv9KfjFyDbxjoJAWvfmEU=", "dev": true, - "optional": true, "requires": { "co": "3.1.0" } @@ -16428,7 +16221,7 @@ "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", "dev": true, "requires": { "async-limiter": "~1.0.0", @@ -16503,7 +16296,6 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, - "optional": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" From ff497b413e24bb936bc9b4c1d98d993fa0a764b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 5 Feb 2019 11:54:23 +0100 Subject: [PATCH 102/555] V8: UI, refactoring of infinity editing to use CSS to fix issue regarding stacking of layers. --- .../components/editor/umbeditors.directive.js | 190 ++++++------------ .../less/components/editor/umb-editor.less | 69 +++++-- .../application/umb-navigation.html | 5 +- .../views/components/editor/umb-editors.html | 20 +- 4 files changed, 135 insertions(+), 149 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js index 235918735f..4104a663d3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js @@ -7,161 +7,85 @@ var evts = []; var allowedNumberOfVisibleEditors = 3; - var editorIndent = 60; - + scope.editors = []; - + function addEditor(editor) { + editor.inFront = true; + editor.moveRight = true; + editor.level = 0; + editor.styleIndex = 0; - if (!editor.style) - editor.style = {}; - - editor.animating = true; - - showOverlayOnPrevEditor(); - - var i = allowedNumberOfVisibleEditors; - var len = scope.editors.length; - while(i= allowedNumberOfVisibleEditors) { - animeConfig.left = i * editorIndent; - } else { - animeConfig.left = (i + 1) * editorIndent; - } - - anime(animeConfig); - - i++; - } - + editor.infinityMode = true; // push the new editor to the dom scope.editors.push(editor); - - - var indentValue = scope.editors.length * editorIndent; - - // don't allow indent larger than what - // fits the max number of visible editors - if(scope.editors.length >= allowedNumberOfVisibleEditors) { - indentValue = allowedNumberOfVisibleEditors * editorIndent; - } - - // indent all large editors - if(editor.size !== "small") { - editor.style.left = indentValue + "px"; - } - - editor.style._tx = 100; - editor.style.transform = "translateX("+editor.style._tx+"%)"; - - // animation config - anime({ - targets: editor.style, - _tx: [100, 0], - easing: 'easeOutExpo', - duration: 480, - update: () => { - editor.style.transform = "translateX("+editor.style._tx+"%)"; - scope.$digest(); - }, - complete: function() { - editor.animating = false; - scope.$digest(); - } - }); - - - } - - function removeEditor(editor) { + $timeout(() => { + editor.moveRight = false; + }) editor.animating = true; + setTimeout(revealEditorContent.bind(this, editor), 400); - editor.style._tx = 0; - editor.style.transform = "translateX("+editor.style._tx+"%)"; + updateEditors(); + + } + + function removeEditor(editor) { - // animation config - anime({ - targets: editor.style, - _tx: [0, 100], - easing: 'easeInExpo', - duration: 360, - update: () => { - editor.style.transform = "translateX("+editor.style._tx+"%)"; - scope.$digest(); - }, - complete: function() { - scope.editors.splice(-1,1); - removeOverlayFromPrevEditor(); - scope.$digest(); - } - }); + editor.moveRight = true; + editor.animating = true; + setTimeout(removeEditorFromDOM.bind(this, editor), 400); - expandEditors(); - + updateEditors(-1); } - - function expandEditors() { + + function revealEditorContent(editor) { - var i = allowedNumberOfVisibleEditors + 1; - var len = scope.editors.length-1; + editor.animating = false; + + scope.$digest(); + + } + + function removeEditorFromDOM(editor) { + + // push the new editor to the dom + var index = scope.editors.indexOf(editor); + if (index !== -1) { + scope.editors.splice(index, 1); + } + + updateEditors(); + + scope.$digest(); + + } + + /** update layer positions. With ability to offset positions, needed for when an item is moving out, then we dont want it to influence positions */ + function updateEditors(offset) { + + offset = offset || 0;// fallback value. + + var len = scope.editors.length; + var calcLen = len + offset; + var ceiling = Math.min(calcLen, allowedNumberOfVisibleEditors); + var origin = Math.max(calcLen-1, 0)-ceiling; + var i = 0; while(i= ceiling; i++; } - - - } - // show backdrop on previous editor - function showOverlayOnPrevEditor() { - var numberOfEditors = scope.editors.length; - if(numberOfEditors > 0) { - scope.editors[numberOfEditors - 1].showOverlay = true; - } } - - function removeOverlayFromPrevEditor() { - var numberOfEditors = scope.editors.length; - if(numberOfEditors > 0) { - scope.editors[numberOfEditors - 1].showOverlay = false; - } - } - + evts.push(eventsService.on("appState.editors.open", function (name, args) { addEditor(args.editor); })); diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less index 6dd77c56b1..f1fa8245ea 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less @@ -4,6 +4,7 @@ right: 0; bottom: 0; left: 0; + overflow: hidden; } .umb-editor { @@ -17,7 +18,49 @@ } .umb-editor--animating { - will-change: transform, width, left; + //will-change: transform, width, left; +} +.umb-editor--infinityMode { + transform: none; + will-change: transform; + transition: transform 400ms ease-in-out; + &.moveRight { + transform: translateX(110%); + } +} + +.umb-editor--outOfRange { + //left:0; + transform: none; + display: none; + will-change: auto; + transition: display 0s 320ms; +} +.umb-editor--level0 { + //left:0; + transform: none; +} +.umb-editor--level1 { + //left:60px; + transform: translateX(60px); +} +.umb-editor--level2 { + //left:120px; + transform: translateX(120px); +} +.umb-editor--level3 { + //left:180px; + transform: translateX(180px); +} + +.umb-editor--n1 { + right:60px; +} +.umb-editor--n2 { + right:120px; +} +.umb-editor--n3 { + right:180px; } // hide all infinite editors by default @@ -28,20 +71,14 @@ .umb-editor--small { width: 500px; + will-change: transform; left: auto; - + .umb-editor-container { max-width: 500px; } } -@keyframes umb-editor__overlay_fade_opacity { - from { - opacity:0; - } - to { - opacity:1; - } -} + .umb-editor__overlay { position: absolute; top: 0; @@ -50,6 +87,14 @@ left: 0; background: rgba(0,0,0,0.4); z-index: @zIndexEditor; - - animation:umb-editor__overlay_fade_opacity 600ms; + visibility: hidden; + opacity: 0; + transition: opacity 320ms 20ms, visibility 0s 400ms; +} + +#contentcolumn > .umb-editor__overlay, +.--notInFront .umb-editor__overlay { + visibility: visible; + opacity: 1; + transition: opacity 320ms 20ms, visibility 0s; } diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-navigation.html index 275c814761..829582329f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-navigation.html @@ -1,7 +1,8 @@
    -