From a9732cb2334868190cd19abecc7a31885591bae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 6 Feb 2020 14:57:25 +0100 Subject: [PATCH 01/25] corrected button style to match new style --- .../src/views/propertyeditors/listview/listview.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index ee1847b430..55adb18c6e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -21,7 +21,7 @@
- From 312dc1d9a757469daa209fe99f66abc5b0dc2309 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe Date: Tue, 15 Sep 2020 12:54:00 -0400 Subject: [PATCH 02/25] Change wrong URL in KeepAlive XML Comments The XML comments for KeepAlive mention the URL for the KeepAlive.Ping action but incorrectly omits 'umbraco' from the path. The change adds the 'umbraco' section to the path. --- src/Umbraco.Web.UI/config/umbracoSettings.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index 73a5143a20..d723b9c7c0 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -259,7 +259,7 @@ Defaults to "false". @keepAlivePingUrl The url of the KeepAlivePing action. By default, the url will use the umbracoApplicationUrl setting as the basis. - Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/api/keepalive/ping + Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/umbraco/api/keepalive/ping Defaults to "{umbracoApplicationUrl}/api/keepalive/ping". --> From 5a37854dd5d3412cc0ac18dfed003b212ac192c7 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 14 Sep 2020 12:02:26 +0100 Subject: [PATCH 03/25] Merge pull request #7599 from umbraco/v8/feature/ui-media-create-button-style UI: corrected button style to match new style (cherry picked from commit 2e055ca146a7ab1814ce232ccc97fa07571733df) --- .../src/views/propertyeditors/listview/listview.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 05a294cc1c..e72b81b019 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -21,7 +21,7 @@
- From 6d2135edd5b0c92560492ee6417d136740a0d07b Mon Sep 17 00:00:00 2001 From: Niels Swimberghe Date: Tue, 15 Sep 2020 12:54:00 -0400 Subject: [PATCH 04/25] Change wrong URL in KeepAlive XML Comments The XML comments for KeepAlive mention the URL for the KeepAlive.Ping action but incorrectly omits 'umbraco' from the path. The change adds the 'umbraco' section to the path. (cherry picked from commit 312dc1d9a757469daa209fe99f66abc5b0dc2309) --- src/Umbraco.Web.UI/config/umbracoSettings.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index 73a5143a20..d723b9c7c0 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -259,7 +259,7 @@ Defaults to "false". @keepAlivePingUrl The url of the KeepAlivePing action. By default, the url will use the umbracoApplicationUrl setting as the basis. - Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/api/keepalive/ping + Change this setting to specify an alternative url to reach the KeepAlivePing action. eg http://localhost/umbraco/api/keepalive/ping Defaults to "{umbracoApplicationUrl}/api/keepalive/ping". --> From deb03e4d82e48674c6d8bdc7926e820e17454d9e Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Thu, 17 Sep 2020 11:32:52 +0200 Subject: [PATCH 05/25] Eliminates error/no-preview when grid media picker have no crop set (#8620) --- .../mediapicker/overlays/mediacropdetails.controller.js | 5 +++++ .../mediapicker/overlays/mediacropdetails.html | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js index d9ea5a7a09..030200e1e6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js @@ -6,6 +6,7 @@ vm.submit = submit; vm.close = close; + vm.cropSet = cropSet; if (!$scope.model.target.coordinates && !$scope.model.target.focalPoint) { $scope.model.target.focalPoint = { left: .5, top: .5 }; @@ -56,4 +57,8 @@ } } + function cropSet() { + var model = $scope.model; + return (model.cropSize || {}).width && model.target.thumbnail; + } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html index 3814ac851e..cda42043c1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html @@ -26,7 +26,7 @@
-
+
Preview
@@ -34,7 +34,7 @@ {{model.target.name}}
-
+
Crop section
From 6d15a2fce3ba8e0585b5b6df45d1a274daf76a46 Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Thu, 17 Sep 2020 11:32:52 +0200 Subject: [PATCH 06/25] Eliminates error/no-preview when grid media picker have no crop set (#8620) (cherry picked from commit deb03e4d82e48674c6d8bdc7926e820e17454d9e) --- .../mediapicker/overlays/mediacropdetails.controller.js | 5 +++++ .../mediapicker/overlays/mediacropdetails.html | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js index d9ea5a7a09..030200e1e6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.controller.js @@ -6,6 +6,7 @@ vm.submit = submit; vm.close = close; + vm.cropSet = cropSet; if (!$scope.model.target.coordinates && !$scope.model.target.focalPoint) { $scope.model.target.focalPoint = { left: .5, top: .5 }; @@ -56,4 +57,8 @@ } } + function cropSet() { + var model = $scope.model; + return (model.cropSize || {}).width && model.target.thumbnail; + } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html index 3814ac851e..cda42043c1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/overlays/mediacropdetails.html @@ -26,7 +26,7 @@
-
+
Preview
@@ -34,7 +34,7 @@ {{model.target.name}}
-
+
Crop section
From 6b0539fefcf2f7e103a38638c0328f2a418cb520 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 17 Sep 2020 12:19:07 +0200 Subject: [PATCH 07/25] Set version to RC --- src/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 3f512bc65a..26496aa9e6 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("8.8.0")] -[assembly: AssemblyInformationalVersion("8.8.0")] +[assembly: AssemblyInformationalVersion("8.8.0-rc")] From 0506c8c555e5398591afd84277e0f48a69673415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 17 Sep 2020 14:59:12 +0200 Subject: [PATCH 08/25] defineIcon method --- .../src/common/services/iconhelper.service.js | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js index 0d0135fff8..f714cba4ad 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js @@ -31,7 +31,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { { oldIcon: ".sprToPublish", newIcon: "mail-forward" }, { oldIcon: ".sprTranslate", newIcon: "comments" }, { oldIcon: ".sprUpdate", newIcon: "save" }, - + { oldIcon: ".sprTreeSettingDomain", newIcon: "icon-home" }, { oldIcon: ".sprTreeDoc", newIcon: "icon-document" }, { oldIcon: ".sprTreeDoc2", newIcon: "icon-diploma-alt" }, @@ -39,21 +39,21 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { { oldIcon: ".sprTreeDoc4", newIcon: "icon-newspaper-alt" }, { oldIcon: ".sprTreeDoc5", newIcon: "icon-notepad-alt" }, - { oldIcon: ".sprTreeDocPic", newIcon: "icon-picture" }, + { oldIcon: ".sprTreeDocPic", newIcon: "icon-picture" }, { oldIcon: ".sprTreeFolder", newIcon: "icon-folder" }, { oldIcon: ".sprTreeFolder_o", newIcon: "icon-folder" }, { oldIcon: ".sprTreeMediaFile", newIcon: "icon-music" }, { oldIcon: ".sprTreeMediaMovie", newIcon: "icon-movie" }, { oldIcon: ".sprTreeMediaPhoto", newIcon: "icon-picture" }, - + { oldIcon: ".sprTreeMember", newIcon: "icon-user" }, { oldIcon: ".sprTreeMemberGroup", newIcon: "icon-users" }, { oldIcon: ".sprTreeMemberType", newIcon: "icon-users" }, - + { oldIcon: ".sprTreeNewsletter", newIcon: "icon-file-text-alt" }, { oldIcon: ".sprTreePackage", newIcon: "icon-box" }, { oldIcon: ".sprTreeRepository", newIcon: "icon-server-alt" }, - + { oldIcon: ".sprTreeSettingDataType", newIcon: "icon-autofill" }, // TODO: Something needs to be done with the old tree icons that are commented out. @@ -61,7 +61,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { { oldIcon: ".sprTreeSettingAgent", newIcon: "" }, { oldIcon: ".sprTreeSettingCss", newIcon: "" }, { oldIcon: ".sprTreeSettingCssItem", newIcon: "" }, - + { oldIcon: ".sprTreeSettingDataTypeChild", newIcon: "" }, { oldIcon: ".sprTreeSettingDomain", newIcon: "" }, { oldIcon: ".sprTreeSettingLanguage", newIcon: "" }, @@ -94,9 +94,9 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { var iconCache = []; var liveRequests = []; var allIconsRequested = false; - + return { - + /** Used by the create dialogs for content/media types to format the data so that the thumbnails are styled properly */ formatContentTypeThumbnails: function (contentTypes) { for (var i = 0; i < contentTypes.length; i++) { @@ -209,15 +209,11 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { ,'Failed to retrieve icon: ' + iconName) .then(icon => { if(icon) { - var trustedIcon = { - name: icon.Name, - svgString: $sce.trustAsHtml(icon.SvgString) - }; - this._cacheIcon(trustedIcon); + var trustedIcon = this.defineIcon(icon.name, icon.SvgString); - liveRequests = _.filter(liveRequests, iconRequestPath); + liveRequests = _.filter(liveRequests, iconRequestPath); - resolve(trustedIcon); + resolve(trustedIcon); } }) .catch(err => { @@ -240,15 +236,10 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { ,'Failed to retrieve icons') .then(icons => { icons.forEach(icon => { - var trustedIcon = { - name: icon.Name, - svgString: $sce.trustAsHtml(icon.SvgString) - }; - - this._cacheIcon(trustedIcon); + this.defineIcon(icon.Name, icon.SvgString); }); - resolve(iconCache); + resolve(iconCache); }) .catch(err => { console.warn(err); @@ -278,7 +269,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { console.warn("Can't read the css rules of: " + document.styleSheets[i].href, e); continue; } - + if (classes !== null) { for(var x=0;x x.name === name); + if(icon === undefined) { + icon = { + name: name, + svgString: $sce.trustAsHtml(svg) + }; + iconCache.push(icon); + } + return icon; }, /** Returns the cached icon or undefined */ From e2957bb715d797299d5cc65c8d073fd17bb15441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 17 Sep 2020 14:59:49 +0200 Subject: [PATCH 09/25] inject icons to iconHelper to avoid making requests to the icon controller --- .../Umbraco/Views/Default.cshtml | 286 +++++++++--------- 1 file changed, 148 insertions(+), 138 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml index 616763c06f..d0f0fd2cc8 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml @@ -1,138 +1,148 @@ -@using Umbraco.Core -@using ClientDependency.Core -@using ClientDependency.Core.Mvc -@using Umbraco.Core.Composing -@using Umbraco.Core.IO -@using Umbraco.Web -@using Umbraco.Core.Configuration - -@inherits WebViewPage - -@{ - var isDebug = false; - if (Request.RawUrl.IndexOf('?') >= 0) - { - var parsed = HttpUtility.ParseQueryString(Request.RawUrl.Split('?')[1]); - var attempt = parsed["umbDebug"].TryConvertTo(); - if (attempt && attempt.Result) - { - isDebug = true; - } - } - - Html - .RequiresCss("assets/css/umbraco.css", "Umbraco") - .RequiresCss("lib/bootstrap-social/bootstrap-social.css", "Umbraco") - .RequiresCss("lib/font-awesome/css/font-awesome.min.css", "Umbraco"); -} - - - - - - - - - - - - - - Umbraco - - @Html.RenderCssHere( - new BasicPath("Umbraco", IOHelper.ResolveUrl(SystemDirectories.Umbraco))) - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - - - @Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewData.GetUmbracoPath() }), Model.Features, Current.Configs.Global()) - - - - - - - @if (isDebug) - { - @Html.RenderProfiler() - } - - - +@using Umbraco.Core +@using ClientDependency.Core +@using ClientDependency.Core.Mvc +@using Umbraco.Core.Composing +@using Umbraco.Core.IO +@using Umbraco.Web +@using Umbraco.Core.Configuration + +@inherits WebViewPage + +@{ + var isDebug = false; + if (Request.RawUrl.IndexOf('?') >= 0) + { + var parsed = HttpUtility.ParseQueryString(Request.RawUrl.Split('?')[1]); + var attempt = parsed["umbDebug"].TryConvertTo(); + if (attempt && attempt.Result) + { + isDebug = true; + } + } + + Html + .RequiresCss("assets/css/umbraco.css", "Umbraco") + .RequiresCss("lib/bootstrap-social/bootstrap-social.css", "Umbraco") + .RequiresCss("lib/font-awesome/css/font-awesome.min.css", "Umbraco"); +} + + + + + + + + + + + + + + Umbraco + + @Html.RenderCssHere( + new BasicPath("Umbraco", IOHelper.ResolveUrl(SystemDirectories.Umbraco))) + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + @Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewData.GetUmbracoPath() }), Model.Features, Current.Configs.Global()) + + + + + + + @if (isDebug) + { + @Html.RenderProfiler() + } + + + From 0f9595a5b1aeca306820380afa56e30d5720a672 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Thu, 17 Sep 2020 17:58:11 +0200 Subject: [PATCH 10/25] Updates nuget packages versions to latest --- .../Umbraco.Configuration.csproj | 6 ++-- src/Umbraco.Core/Umbraco.Core.csproj | 4 +-- .../Umbraco.Infrastructure.csproj | 32 +++++++++---------- .../Umbraco.Tests.Common.csproj | 8 ++--- .../Umbraco.Tests.Integration.csproj | 12 +++---- .../Umbraco.Tests.UnitTests.csproj | 4 +-- src/Umbraco.Tests/Umbraco.Tests.csproj | 22 ++++++------- .../Umbraco.Web.BackOffice.csproj | 6 ++-- .../Umbraco.Web.Common.csproj | 8 ++--- .../Umbraco.Web.UI.NetCore.csproj | 4 +-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 8 ++--- src/Umbraco.Web/Umbraco.Web.csproj | 22 ++++++------- 12 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/Umbraco.Configuration/Umbraco.Configuration.csproj b/src/Umbraco.Configuration/Umbraco.Configuration.csproj index a4dac22386..21a6dd83af 100644 --- a/src/Umbraco.Configuration/Umbraco.Configuration.csproj +++ b/src/Umbraco.Configuration/Umbraco.Configuration.csproj @@ -26,9 +26,9 @@ - - - + + + diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b5e553a78e..b5a0754a43 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index adb2a95202..ca497c2d6b 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -10,37 +10,37 @@ - - + + - - - + + + - - - - + + + + - + - + - - + + - - + + - + diff --git a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj index 68d3f23ac4..da450c1aff 100644 --- a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj +++ b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj @@ -5,10 +5,10 @@ - - - - + + + + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 072f15bcd1..2cd2a9eaa2 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -15,17 +15,17 @@ - + - - - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj index 6569a49a27..d22ca002a1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj @@ -17,8 +17,8 @@ - + - + diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f1db4b619f..49f80e3755 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -77,14 +77,14 @@ - + 2.0.0-alpha.20200128.15 - 1.8.14 + 1.11.24 - + @@ -95,22 +95,22 @@ - - - - + + + + - - + + - + - + diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj index 1c66edc2ce..8f3a5509fa 100644 --- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj +++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj @@ -15,10 +15,10 @@ - - + + - + diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index ee657e82bb..f14bb189f0 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -21,11 +21,11 @@ - - - + + + - + diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj index 39df6b94ef..0d2ebe967b 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 @@ -71,7 +71,7 @@ - + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index d70118116b..4317056f31 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -91,15 +91,15 @@ - - - + + + 1.0.0 runtime; build; native; contentfiles; analyzers; buildtransitive all - + 3.4.0 diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 8d91f76d8b..0122a29c2a 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -66,14 +66,14 @@ 2.0.0-alpha.20200128.15 - + - 4.0.217 + 5.0.343 2.7.0.100 - + @@ -83,20 +83,20 @@ - + - - - - - + + + + + 1.0.0 runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -104,7 +104,7 @@ runtime; build; native; contentfiles; analyzers all - + 1.0.5 From 66f35f428db5a77361bc65e822306facf37453c9 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Thu, 17 Sep 2020 18:47:24 +0200 Subject: [PATCH 11/25] Updates nuspec files with new nuget packages version --- build/NuSpecs/UmbracoCms.Core.nuspec | 39 ++++++++++++++-------------- build/NuSpecs/UmbracoCms.Web.nuspec | 12 ++++----- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 477bb143f9..6239b0498f 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -23,41 +23,42 @@ the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do not want this to happen as the alpha of the next major is, really, the next major already. --> - - - + + + - - - - + + + + - - - + + + - - - - + + + + - + - + + - - + + - + diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index 765c45e860..7800d05920 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -24,16 +24,16 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - - - - + + + + + - - + From 525ca95acf7a11bc66087c095bf1a25839095f44 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 08:01:04 +0200 Subject: [PATCH 12/25] uncomment SMTP info by default Signed-off-by: Bjarke Berg --- src/Umbraco.Web.UI.NetCore/appsettings.Development.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.Development.json b/src/Umbraco.Web.UI.NetCore/appsettings.Development.json index 9f81927bdc..13f4c95bbd 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.Development.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.Development.json @@ -3,9 +3,9 @@ "CMS": { "Global":{ "Smtp": { - "From": "your@email.here", - "Host": "localhost", - "Port": "25" +// "From": "your@email.here", +// "Host": "localhost", +// "Port": "25" } }, "Hosting":{ From b327399cd2c637a715792dc1d40ac1e6253ae3eb Mon Sep 17 00:00:00 2001 From: Claus Date: Tue, 22 Sep 2020 08:11:58 +0200 Subject: [PATCH 13/25] adding icon svg data from IconController. --- src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml | 8 ++------ src/Umbraco.Web/Editors/BackOfficeModel.cs | 6 ++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml index d0f0fd2cc8..666f7a64f5 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml @@ -4,7 +4,6 @@ @using Umbraco.Core.Composing @using Umbraco.Core.IO @using Umbraco.Web -@using Umbraco.Core.Configuration @inherits WebViewPage @@ -122,12 +121,9 @@ @Html.AngularValueTinyMceAssets() app.run(["iconHelper", function (iconHelper) { - @* We inject icons to the icon helper(service), since icons can only be loaded if user is authorized. By injecting these to the service they will not be requested as they will become cached. *@ - - iconHelper.defineIcon("icon-check", ''); - iconHelper.defineIcon("icon-delete", ''); - + iconHelper.defineIcon("icon-check", '@Html.Raw(Model.IconCheckData)'); + iconHelper.defineIcon("icon-delete", '@Html.Raw(Model.IconDeleteData)'); }]); //required for the noscript trick diff --git a/src/Umbraco.Web/Editors/BackOfficeModel.cs b/src/Umbraco.Web/Editors/BackOfficeModel.cs index 9833121301..b11ea6a5d1 100644 --- a/src/Umbraco.Web/Editors/BackOfficeModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficeModel.cs @@ -6,13 +6,19 @@ namespace Umbraco.Web.Editors public class BackOfficeModel { + private IconController IconController { get; } public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings) { Features = features; GlobalSettings = globalSettings; + IconController = new IconController(); + IconCheckData = IconController.GetIcon("icon-check")?.SvgString; + IconDeleteData = IconController.GetIcon("icon-delete")?.SvgString; } public UmbracoFeatures Features { get; } public IGlobalSettings GlobalSettings { get; } + public string IconCheckData { get; } + public string IconDeleteData { get; } } } From 6e56b16342571935c38f06fcb131694265ea295b Mon Sep 17 00:00:00 2001 From: Claus Date: Tue, 22 Sep 2020 08:57:48 +0200 Subject: [PATCH 14/25] adding IconService --- src/Umbraco.Web/Composing/Current.cs | 3 + .../Editors/BackOfficeController.cs | 23 +++- src/Umbraco.Web/Editors/BackOfficeModel.cs | 8 +- src/Umbraco.Web/Editors/IconController.cs | 81 ++------------ src/Umbraco.Web/Runtime/WebInitialComposer.cs | 2 +- src/Umbraco.Web/Services/IIconService.cs | 29 +++++ src/Umbraco.Web/Services/IconService.cs | 100 ++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 2 + 8 files changed, 166 insertions(+), 82 deletions(-) create mode 100644 src/Umbraco.Web/Services/IIconService.cs create mode 100644 src/Umbraco.Web/Services/IconService.cs diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 2419eaa6d4..14898d0c02 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -146,6 +146,9 @@ namespace Umbraco.Web.Composing public static ISectionService SectionService => Factory.GetInstance(); + public static IIconService IconService + => Factory.GetInstance(); + #endregion #region Web Constants diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index e77a1b70f2..3e16dd9692 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,7 +14,6 @@ using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Models.Identity; @@ -26,6 +24,7 @@ using Umbraco.Web.Composing; using Umbraco.Web.Features; using Umbraco.Web.JavaScript; using Umbraco.Web.Security; +using Umbraco.Web.Services; using Constants = Umbraco.Core.Constants; using JArray = Newtonsoft.Json.Linq.JArray; @@ -42,6 +41,7 @@ namespace Umbraco.Web.Editors private readonly ManifestParser _manifestParser; private readonly UmbracoFeatures _features; private readonly IRuntimeState _runtimeState; + private readonly IIconService _iconService; private BackOfficeUserManager _userManager; private BackOfficeSignInManager _signInManager; @@ -51,6 +51,16 @@ namespace Umbraco.Web.Editors _manifestParser = manifestParser; _features = features; _runtimeState = runtimeState; + _iconService = Current.IconService; + } + + public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper, IIconService iconService) + : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, umbracoHelper) + { + _manifestParser = manifestParser; + _features = features; + _runtimeState = runtimeState; + _iconService = iconService; } protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager()); @@ -65,9 +75,14 @@ namespace Umbraco.Web.Editors /// public async Task Default() { + var backofficeModel = new BackOfficeModel(_features, GlobalSettings) + { + IconCheckData = _iconService.GetIcon("icon-check")?.SvgString, + IconDeleteData = _iconService.GetIcon("icon-delete")?.SvgString + }; return await RenderDefaultOrProcessExternalLoginAsync( - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)), - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings))); + () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", backofficeModel), + () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", backofficeModel)); } [HttpGet] diff --git a/src/Umbraco.Web/Editors/BackOfficeModel.cs b/src/Umbraco.Web/Editors/BackOfficeModel.cs index b11ea6a5d1..ba85a64b42 100644 --- a/src/Umbraco.Web/Editors/BackOfficeModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficeModel.cs @@ -6,19 +6,15 @@ namespace Umbraco.Web.Editors public class BackOfficeModel { - private IconController IconController { get; } public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings) { Features = features; GlobalSettings = globalSettings; - IconController = new IconController(); - IconCheckData = IconController.GetIcon("icon-check")?.SvgString; - IconDeleteData = IconController.GetIcon("icon-delete")?.SvgString; } public UmbracoFeatures Features { get; } public IGlobalSettings GlobalSettings { get; } - public string IconCheckData { get; } - public string IconDeleteData { get; } + public string IconCheckData { get; set; } + public string IconDeleteData { get; set; } } } diff --git a/src/Umbraco.Web/Editors/IconController.cs b/src/Umbraco.Web/Editors/IconController.cs index 72af2194ae..2554f633df 100644 --- a/src/Umbraco.Web/Editors/IconController.cs +++ b/src/Umbraco.Web/Editors/IconController.cs @@ -1,21 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Core.Logging; using Umbraco.Web.Models; -using System.IO; -using Umbraco.Core; -using Umbraco.Core.IO; -using Ganss.XSS; -using Umbraco.Core.Cache; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { [PluginController("UmbracoApi")] public class IconController : UmbracoAuthorizedApiController { + private readonly IIconService _iconService; + + public IconController(IIconService iconService) + { + _iconService = iconService; + } /// /// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path @@ -24,21 +23,7 @@ namespace Umbraco.Web.Editors /// public IconModel GetIcon(string iconName) { - return string.IsNullOrWhiteSpace(iconName) - ? null - : CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{GlobalSettings.IconsPath}/{iconName}.svg")); - } - - /// - /// Gets an IconModel using values from a FileInfo model - /// - /// - /// - public IconModel GetIcon(FileInfo fileInfo) - { - return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name) - ? null - : CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName); + return _iconService.GetIcon(iconName); } /// @@ -47,53 +32,7 @@ namespace Umbraco.Web.Editors /// public List GetAllIcons() { - var icons = new List(); - var directory = new DirectoryInfo(IOHelper.MapPath($"{GlobalSettings.IconsPath}/")); - var iconNames = directory.GetFiles("*.svg"); - - iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo => - { - var icon = GetIcon(iconInfo); - - if (icon != null) - { - icons.Add(icon); - } - }); - - return icons; - } - - /// - /// Gets an IconModel containing the icon name and SvgString - /// - /// - /// - /// - private IconModel CreateIconModel(string iconName, string iconPath) - { - var sanitizer = new HtmlSanitizer(); - sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes); - sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes); - sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags); - - try - { - var svgContent = File.ReadAllText(iconPath); - var sanitizedString = sanitizer.Sanitize(svgContent); - - var svg = new IconModel - { - Name = iconName, - SvgString = sanitizedString - }; - - return svg; - } - catch - { - return null; - } + return _iconService.GetAllIcons(); } } } diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 135d54560b..112910930e 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -137,8 +137,8 @@ namespace Umbraco.Web.Runtime composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); - composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(factory => ExamineManager.Instance); diff --git a/src/Umbraco.Web/Services/IIconService.cs b/src/Umbraco.Web/Services/IIconService.cs new file mode 100644 index 0000000000..cdd75f8d4b --- /dev/null +++ b/src/Umbraco.Web/Services/IIconService.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.IO; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Services +{ + public interface IIconService + { + /// + /// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path + /// + /// + /// + IconModel GetIcon(string iconName); + + /// + /// Gets an IconModel using values from a FileInfo model + /// + /// + /// + IconModel GetIcon(FileInfo fileInfo); + + /// + /// Gets a list of all svg icons found at at the global icons path. + /// + /// + List GetAllIcons(); + } +} diff --git a/src/Umbraco.Web/Services/IconService.cs b/src/Umbraco.Web/Services/IconService.cs new file mode 100644 index 0000000000..4093f69174 --- /dev/null +++ b/src/Umbraco.Web/Services/IconService.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Ganss.XSS; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Services +{ + internal class IconService : IIconService + { + private readonly IGlobalSettings _globalSettings; + + public IconService(IGlobalSettings globalSettings) + { + _globalSettings = globalSettings; + } + + /// + /// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path + /// + /// + /// + public IconModel GetIcon(string iconName) + { + return string.IsNullOrWhiteSpace(iconName) + ? null + : CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{_globalSettings.IconsPath}/{iconName}.svg")); + } + + /// + /// Gets an IconModel using values from a FileInfo model + /// + /// + /// + public IconModel GetIcon(FileInfo fileInfo) + { + return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name) + ? null + : CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName); + } + + /// + /// Gets a list of all svg icons found at at the global icons path. + /// + /// + public List GetAllIcons() + { + var icons = new List(); + var directory = new DirectoryInfo(IOHelper.MapPath($"{_globalSettings.IconsPath}/")); + var iconNames = directory.GetFiles("*.svg"); + + iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo => + { + var icon = GetIcon(iconInfo); + + if (icon != null) + { + icons.Add(icon); + } + }); + + return icons; + } + + /// + /// Gets an IconModel containing the icon name and SvgString + /// + /// + /// + /// + private IconModel CreateIconModel(string iconName, string iconPath) + { + var sanitizer = new HtmlSanitizer(); + sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes); + sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes); + sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags); + + try + { + var svgContent = File.ReadAllText(iconPath); + var sanitizedString = sanitizer.Sanitize(svgContent); + + var svg = new IconModel + { + Name = iconName, + SvgString = sanitizedString + }; + + return svg; + } + catch + { + return null; + } + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 33051671ee..2efc6fdd56 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -284,10 +284,12 @@ + + From ccc0e82579617f7706dd1561ae6b211bcda97de0 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 08:58:16 +0200 Subject: [PATCH 15/25] #8919 - Avoid having fat controller and do not new up a controller in a model --- src/Umbraco.Web/Composing/Current.cs | 3 + .../Editors/BackOfficeController.cs | 48 +++++++++- src/Umbraco.Web/Editors/BackOfficeModel.cs | 22 +++-- .../Editors/BackOfficePreviewModel.cs | 22 ++++- src/Umbraco.Web/Editors/IconController.cs | 83 +++------------- src/Umbraco.Web/Editors/PreviewController.cs | 23 ++++- src/Umbraco.Web/Runtime/WebInitialComposer.cs | 1 + src/Umbraco.Web/Services/IIconService.cs | 21 +++++ src/Umbraco.Web/Services/IconService.cs | 94 +++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 4 +- 10 files changed, 234 insertions(+), 87 deletions(-) create mode 100644 src/Umbraco.Web/Services/IIconService.cs create mode 100644 src/Umbraco.Web/Services/IconService.cs diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 2419eaa6d4..14898d0c02 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -146,6 +146,9 @@ namespace Umbraco.Web.Composing public static ISectionService SectionService => Factory.GetInstance(); + public static IIconService IconService + => Factory.GetInstance(); + #endregion #region Web Constants diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index e77a1b70f2..c9106cffb5 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -26,6 +26,7 @@ using Umbraco.Web.Composing; using Umbraco.Web.Features; using Umbraco.Web.JavaScript; using Umbraco.Web.Security; +using Umbraco.Web.Services; using Constants = Umbraco.Core.Constants; using JArray = Newtonsoft.Json.Linq.JArray; @@ -42,15 +43,54 @@ namespace Umbraco.Web.Editors private readonly ManifestParser _manifestParser; private readonly UmbracoFeatures _features; private readonly IRuntimeState _runtimeState; + private readonly IIconService _iconService; private BackOfficeUserManager _userManager; private BackOfficeSignInManager _signInManager; - public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + [Obsolete("Use the constructor that injects IIconService.")] + public BackOfficeController( + ManifestParser manifestParser, + UmbracoFeatures features, + IGlobalSettings globalSettings, + IUmbracoContextAccessor umbracoContextAccessor, + ServiceContext services, + AppCaches appCaches, + IProfilingLogger profilingLogger, + IRuntimeState runtimeState, + UmbracoHelper umbracoHelper) + : this(manifestParser, + features, + globalSettings, + umbracoContextAccessor, + services, + appCaches, + profilingLogger, + runtimeState, + umbracoHelper, + Current.IconService) + { + _manifestParser = manifestParser; + _features = features; + _runtimeState = runtimeState; + } + + public BackOfficeController( + ManifestParser manifestParser, + UmbracoFeatures features, + IGlobalSettings globalSettings, + IUmbracoContextAccessor umbracoContextAccessor, + ServiceContext services, + AppCaches appCaches, + IProfilingLogger profilingLogger, + IRuntimeState runtimeState, + UmbracoHelper umbracoHelper, + IIconService iconService) : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, umbracoHelper) { _manifestParser = manifestParser; _features = features; _runtimeState = runtimeState; + _iconService = iconService; } protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager()); @@ -66,8 +106,8 @@ namespace Umbraco.Web.Editors public async Task Default() { return await RenderDefaultOrProcessExternalLoginAsync( - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)), - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings))); + () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService)), + () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService))); } [HttpGet] @@ -150,7 +190,7 @@ namespace Umbraco.Web.Editors { return await RenderDefaultOrProcessExternalLoginAsync( //The default view to render when there is no external login info or errors - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings)), + () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService)), //The ActionResult to perform if external login is successful () => Redirect("/")); } diff --git a/src/Umbraco.Web/Editors/BackOfficeModel.cs b/src/Umbraco.Web/Editors/BackOfficeModel.cs index b11ea6a5d1..b620d893e3 100644 --- a/src/Umbraco.Web/Editors/BackOfficeModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficeModel.cs @@ -1,21 +1,29 @@ -using Umbraco.Core.Configuration; +using System; +using Umbraco.Core.Configuration; +using Umbraco.Web.Composing; using Umbraco.Web.Features; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { public class BackOfficeModel { - private IconController IconController { get; } - public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings) + + + [Obsolete("Use the overload that injects IIconService.")] + public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings) : this(features, globalSettings, Current.IconService) + { + + } + public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IIconService iconService) { Features = features; GlobalSettings = globalSettings; - IconController = new IconController(); - IconCheckData = IconController.GetIcon("icon-check")?.SvgString; - IconDeleteData = IconController.GetIcon("icon-delete")?.SvgString; + IconCheckData = iconService.GetIcon("icon-check")?.SvgString; + IconDeleteData = iconService.GetIcon("icon-delete")?.SvgString; } - + public UmbracoFeatures Features { get; } public IGlobalSettings GlobalSettings { get; } public string IconCheckData { get; } diff --git a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs index b66e432699..7239bba8f7 100644 --- a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs @@ -1,7 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; + using Umbraco.Core.Configuration; using Umbraco.Core.Models; +using Umbraco.Web.Composing; using Umbraco.Web.Features; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { @@ -10,7 +14,21 @@ namespace Umbraco.Web.Editors private readonly UmbracoFeatures _features; public IEnumerable Languages { get; } - public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IEnumerable languages) : base(features, globalSettings) + [Obsolete("Use the overload that injects IIconService.")] + public BackOfficePreviewModel( + UmbracoFeatures features, + IGlobalSettings globalSettings, + IEnumerable languages) + : this(features, globalSettings, languages, Current.IconService) + { + } + + public BackOfficePreviewModel( + UmbracoFeatures features, + IGlobalSettings globalSettings, + IEnumerable languages, + IIconService iconService) + : base(features, globalSettings, iconService) { _features = features; Languages = languages; diff --git a/src/Umbraco.Web/Editors/IconController.cs b/src/Umbraco.Web/Editors/IconController.cs index 72af2194ae..b45b0948c8 100644 --- a/src/Umbraco.Web/Editors/IconController.cs +++ b/src/Umbraco.Web/Editors/IconController.cs @@ -1,21 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Core.Logging; using Umbraco.Web.Models; -using System.IO; -using Umbraco.Core; -using Umbraco.Core.IO; -using Ganss.XSS; -using Umbraco.Core.Cache; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { [PluginController("UmbracoApi")] public class IconController : UmbracoAuthorizedApiController { + private readonly IIconService _iconService; + + public IconController(IIconService iconService) + { + _iconService = iconService; + } /// /// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path @@ -24,76 +23,16 @@ namespace Umbraco.Web.Editors /// public IconModel GetIcon(string iconName) { - return string.IsNullOrWhiteSpace(iconName) - ? null - : CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{GlobalSettings.IconsPath}/{iconName}.svg")); - } - - /// - /// Gets an IconModel using values from a FileInfo model - /// - /// - /// - public IconModel GetIcon(FileInfo fileInfo) - { - return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name) - ? null - : CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName); + return _iconService.GetIcon(iconName); } /// /// Gets a list of all svg icons found at at the global icons path. /// /// - public List GetAllIcons() + public IList GetAllIcons() { - var icons = new List(); - var directory = new DirectoryInfo(IOHelper.MapPath($"{GlobalSettings.IconsPath}/")); - var iconNames = directory.GetFiles("*.svg"); - - iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo => - { - var icon = GetIcon(iconInfo); - - if (icon != null) - { - icons.Add(icon); - } - }); - - return icons; - } - - /// - /// Gets an IconModel containing the icon name and SvgString - /// - /// - /// - /// - private IconModel CreateIconModel(string iconName, string iconPath) - { - var sanitizer = new HtmlSanitizer(); - sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes); - sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes); - sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags); - - try - { - var svgContent = File.ReadAllText(iconPath); - var sanitizedString = sanitizer.Sanitize(svgContent); - - var svg = new IconModel - { - Name = iconName, - SvgString = sanitizedString - }; - - return svg; - } - catch - { - return null; - } + return _iconService.GetAllIcons(); } } } diff --git a/src/Umbraco.Web/Editors/PreviewController.cs b/src/Umbraco.Web/Editors/PreviewController.cs index c1848419dc..f148655acd 100644 --- a/src/Umbraco.Web/Editors/PreviewController.cs +++ b/src/Umbraco.Web/Editors/PreviewController.cs @@ -12,6 +12,7 @@ using Umbraco.Web.JavaScript; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; +using Umbraco.Web.Services; using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Editors @@ -24,19 +25,39 @@ namespace Umbraco.Web.Editors private readonly IPublishedSnapshotService _publishedSnapshotService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ILocalizationService _localizationService; + private readonly IIconService _iconService; + [Obsolete("Use the constructor that injects IIconService.")] public PreviewController( UmbracoFeatures features, IGlobalSettings globalSettings, IPublishedSnapshotService publishedSnapshotService, IUmbracoContextAccessor umbracoContextAccessor, ILocalizationService localizationService) + :this(features, + globalSettings, + publishedSnapshotService, + umbracoContextAccessor, + localizationService, + Current.IconService) + { + + } + + public PreviewController( + UmbracoFeatures features, + IGlobalSettings globalSettings, + IPublishedSnapshotService publishedSnapshotService, + IUmbracoContextAccessor umbracoContextAccessor, + ILocalizationService localizationService, + IIconService iconService) { _features = features; _globalSettings = globalSettings; _publishedSnapshotService = publishedSnapshotService; _umbracoContextAccessor = umbracoContextAccessor; _localizationService = localizationService; + _iconService = iconService; } [UmbracoAuthorize(redirectToUmbracoLogin: true)] @@ -45,7 +66,7 @@ namespace Umbraco.Web.Editors { var availableLanguages = _localizationService.GetAllLanguages(); - var model = new BackOfficePreviewModel(_features, _globalSettings, availableLanguages); + var model = new BackOfficePreviewModel(_features, _globalSettings, availableLanguages, _iconService); if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false) { diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 135d54560b..d9a8ee37f2 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -139,6 +139,7 @@ namespace Umbraco.Web.Runtime composition.RegisterUnique(); composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(factory => ExamineManager.Instance); diff --git a/src/Umbraco.Web/Services/IIconService.cs b/src/Umbraco.Web/Services/IIconService.cs new file mode 100644 index 0000000000..177921ceae --- /dev/null +++ b/src/Umbraco.Web/Services/IIconService.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Services +{ + public interface IIconService + { + /// + /// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path + /// + /// + /// + IconModel GetIcon(string iconName); + + /// + /// Gets a list of all svg icons found at at the global icons path. + /// + /// + IList GetAllIcons(); + } +} diff --git a/src/Umbraco.Web/Services/IconService.cs b/src/Umbraco.Web/Services/IconService.cs new file mode 100644 index 0000000000..93389668b6 --- /dev/null +++ b/src/Umbraco.Web/Services/IconService.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Ganss.XSS; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Services +{ + public class IconService : IIconService + { + private readonly IGlobalSettings _globalSettings; + + public IconService(IGlobalSettings globalSettings) + { + _globalSettings = globalSettings; + } + + + /// + public IList GetAllIcons() + { + var icons = new List(); + var directory = new DirectoryInfo(IOHelper.MapPath($"{_globalSettings.IconsPath}/")); + var iconNames = directory.GetFiles("*.svg"); + + iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo => + { + var icon = GetIcon(iconInfo); + + if (icon != null) + { + icons.Add(icon); + } + }); + + return icons; + } + + /// + public IconModel GetIcon(string iconName) + { + return string.IsNullOrWhiteSpace(iconName) + ? null + : CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{_globalSettings.IconsPath}/{iconName}.svg")); + } + + /// + /// Gets an IconModel using values from a FileInfo model + /// + /// + /// + private IconModel GetIcon(FileInfo fileInfo) + { + return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name) + ? null + : CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName); + } + + /// + /// Gets an IconModel containing the icon name and SvgString + /// + /// + /// + /// + private IconModel CreateIconModel(string iconName, string iconPath) + { + var sanitizer = new HtmlSanitizer(); + sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes); + sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes); + sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags); + + try + { + var svgContent = File.ReadAllText(iconPath); + var sanitizedString = sanitizer.Sanitize(svgContent); + + var svg = new IconModel + { + Name = iconName, + SvgString = sanitizedString + }; + + return svg; + } + catch + { + return null; + } + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 33051671ee..ff67493aaa 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -238,8 +238,8 @@ - + @@ -284,10 +284,12 @@ + + From 96facc4d35ce13ebc3c7f43fe51d678494656779 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 10:01:00 +0200 Subject: [PATCH 16/25] Netcore: Introduce BackofficeSecurityAccessor (#8871) * Introduced IWebSecurityAccessor Signed-off-by: Bjarke Berg * Fixed tests Signed-off-by: Bjarke Berg * Renamed WebSecurity to BackofficeSecurity and all related names * Fixes typos Co-authored-by: Elitsa Marinovska --- .../HybridBackofficeSecurityAccessor.cs | 30 ++++++++++ .../IBackofficeSecurityFactory.cs | 15 +++++ src/Umbraco.Core/IUmbracoContext.cs | 4 +- ...IWebSecurity.cs => IBackofficeSecurity.cs} | 2 +- .../Security/IBackofficeSecurityAccessor.cs | 9 +++ .../InstallSteps/StarterKitDownloadStep.cs | 11 ++-- .../InstallSteps/StarterKitInstallStep.cs | 9 +-- .../Mapping/MemberTabsAndPropertiesMapper.cs | 16 +++-- .../UmbracoTestServerTestBase.cs | 2 + .../Testing/UmbracoIntegrationTest.cs | 1 + .../Filters/ContentModelValidatorTests.cs | 7 ++- .../AppendUserModifiedHeaderAttributeTests.cs | 8 +-- ...terAllowedOutgoingContentAttributeTests.cs | 11 ++-- .../Controllers/SurfaceControllerTests.cs | 20 ++++--- .../PublishedContentCacheTests.cs | 2 +- .../PublishedContentSnapshotTestBase.cs | 2 +- .../Scoping/ScopedNuCacheTests.cs | 2 +- .../TestControllerActivatorBase.cs | 10 ++-- .../TestHelpers/TestWithDatabaseBase.cs | 2 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 2 +- .../Web/Mvc/UmbracoViewPageTests.cs | 2 +- .../Web/WebExtensionMethodTests.cs | 6 +- .../Controllers/AuthenticationController.cs | 15 ++--- .../Controllers/BackOfficeController.cs | 11 ++-- .../Controllers/ContentController.cs | 60 +++++++++---------- .../Controllers/ContentTypeController.cs | 17 +++--- .../Controllers/CurrentUserController.cs | 43 ++++++------- .../Controllers/DictionaryController.cs | 15 ++--- .../Controllers/EntityController.cs | 17 +++--- .../Controllers/LogController.cs | 9 +-- .../Controllers/MacrosController.cs | 11 ++-- .../Controllers/MediaController.cs | 31 +++++----- .../Controllers/MediaTypeController.cs | 15 ++--- .../Controllers/MemberController.cs | 14 ++--- .../Controllers/MemberTypeController.cs | 11 ++-- .../Controllers/PackageController.cs | 9 +-- .../Controllers/PackageInstallController.cs | 17 +++--- .../Controllers/PreviewController.cs | 11 ++-- .../RedirectUrlManagementController.cs | 14 +++-- .../Controllers/SectionController.cs | 15 ++--- .../Controllers/TourController.cs | 11 ++-- .../Controllers/UpdateCheckController.cs | 9 +-- .../Controllers/UserGroupsController.cs | 23 +++---- .../Controllers/UsersController.cs | 28 +++++---- .../Filters/AdminUsersAuthorizeAttribute.cs | 9 +-- .../AppendUserModifiedHeaderAttribute.cs | 4 +- .../Filters/ContentModelValidator.cs | 10 ++-- .../Filters/ContentSaveModelValidator.cs | 4 +- .../Filters/ContentSaveValidationAttribute.cs | 18 +++--- ...EnsureUserPermissionForContentAttribute.cs | 26 ++++---- .../EnsureUserPermissionForMediaAttribute.cs | 19 +++--- .../FilterAllowedOutgoingContentAttribute.cs | 5 +- .../FilterAllowedOutgoingMediaAttribute.cs | 8 +-- .../IsCurrentUserModelFilterAttribute.cs | 9 +-- .../MediaItemSaveValidationAttribute.cs | 11 ++-- .../Filters/MediaSaveModelValidator.cs | 4 +- .../Filters/MemberSaveModelValidator.cs | 6 +- .../Filters/MemberSaveValidationAttribute.cs | 9 +-- .../OutgoingEditorModelEventAttribute.cs | 9 +-- .../UmbracoApplicationAuthorizeAttribute.cs | 15 ++--- .../Filters/UmbracoTreeAuthorizeAttribute.cs | 17 +++--- .../UserGroupAuthorizationAttribute.cs | 9 +-- .../Trees/ApplicationTreeController.cs | 3 +- .../Trees/ContentTreeController.cs | 15 ++--- .../Trees/ContentTreeControllerBase.cs | 24 ++++---- .../Trees/MediaTreeController.cs | 13 ++-- .../Trees/MemberTreeController.cs | 9 +-- .../Install/InstallController.cs | 9 +-- .../Middleware/UmbracoRequestMiddleware.cs | 11 +++- .../Runtime/AspNetCoreComposer.cs | 3 +- .../{WebSecurity.cs => BackofficeSecurity.cs} | 5 +- .../Security/BackofficeSecurityFactory.cs | 43 +++++++++++++ .../UmbracoContext/UmbracoContext.cs | 10 ++-- .../UmbracoContext/UmbracoContextFactory.cs | 9 +-- .../Mvc/UmbracoAuthorizeAttribute.cs | 13 ++-- src/Umbraco.Web/Mvc/UmbracoController.cs | 2 +- .../{WebSecurity.cs => BackofficeSecurity.cs} | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- src/Umbraco.Web/UmbracoContext.cs | 10 ++-- src/Umbraco.Web/UmbracoContextFactory.cs | 2 +- src/Umbraco.Web/UmbracoHttpHandler.cs | 2 +- src/Umbraco.Web/UmbracoWebService.cs | 2 +- .../WebApi/UmbracoApiControllerBase.cs | 2 +- .../WebApi/UmbracoAuthorizeAttribute.cs | 13 ++-- 84 files changed, 571 insertions(+), 404 deletions(-) create mode 100644 src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs create mode 100644 src/Umbraco.Core/IBackofficeSecurityFactory.cs rename src/Umbraco.Core/Security/{IWebSecurity.cs => IBackofficeSecurity.cs} (97%) create mode 100644 src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs rename src/Umbraco.Web.Common/Security/{WebSecurity.cs => BackofficeSecurity.cs} (98%) create mode 100644 src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs rename src/Umbraco.Web/Security/{WebSecurity.cs => BackofficeSecurity.cs} (95%) diff --git a/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs b/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs new file mode 100644 index 0000000000..a953ed8b82 --- /dev/null +++ b/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs @@ -0,0 +1,30 @@ +using Umbraco.Core.Cache; +using Umbraco.Core.Security; +using Umbraco.Web; +using Umbraco.Web.Security; + +namespace Umbraco.Core +{ + + public class HybridBackofficeSecurityAccessor : HybridAccessorBase, IBackofficeSecurityAccessor + { + /// + /// Initializes a new instance of the class. + /// + public HybridBackofficeSecurityAccessor(IRequestCache requestCache) + : base(requestCache) + { } + + /// + protected override string ItemKey => "Umbraco.Web.HybridBackofficeSecurityAccessor"; + + /// + /// Gets or sets the object. + /// + public IBackofficeSecurity BackofficeSecurity + { + get => Value; + set => Value = value; + } + } +} diff --git a/src/Umbraco.Core/IBackofficeSecurityFactory.cs b/src/Umbraco.Core/IBackofficeSecurityFactory.cs new file mode 100644 index 0000000000..9f8f791e4c --- /dev/null +++ b/src/Umbraco.Core/IBackofficeSecurityFactory.cs @@ -0,0 +1,15 @@ +using Umbraco.Web.Security; + +namespace Umbraco.Core +{ + /// + /// Creates and manages instances. + /// + public interface IBackofficeSecurityFactory + { + /// + /// Ensures that a current exists. + /// + void EnsureBackofficeSecurity(); + } +} diff --git a/src/Umbraco.Core/IUmbracoContext.cs b/src/Umbraco.Core/IUmbracoContext.cs index 66b3dc3965..03fb305fb6 100644 --- a/src/Umbraco.Core/IUmbracoContext.cs +++ b/src/Umbraco.Core/IUmbracoContext.cs @@ -16,9 +16,9 @@ namespace Umbraco.Web DateTime ObjectCreated { get; } /// - /// Gets the WebSecurity class + /// Gets the BackofficeSecurity class /// - IWebSecurity Security { get; } + IBackofficeSecurity Security { get; } /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. diff --git a/src/Umbraco.Core/Security/IWebSecurity.cs b/src/Umbraco.Core/Security/IBackofficeSecurity.cs similarity index 97% rename from src/Umbraco.Core/Security/IWebSecurity.cs rename to src/Umbraco.Core/Security/IBackofficeSecurity.cs index 594f6d96ea..3a0e0baa1d 100644 --- a/src/Umbraco.Core/Security/IWebSecurity.cs +++ b/src/Umbraco.Core/Security/IBackofficeSecurity.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Security { - public interface IWebSecurity + public interface IBackofficeSecurity { /// /// Gets the current user. diff --git a/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs b/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs new file mode 100644 index 0000000000..d3cea99f9f --- /dev/null +++ b/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs @@ -0,0 +1,9 @@ +using Umbraco.Web.Security; + +namespace Umbraco.Core.Security +{ + public interface IBackofficeSecurityAccessor + { + IBackofficeSecurity BackofficeSecurity { get; set; } + } +} diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs index 24133d3be1..d060db2c43 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Umbraco.Core.Services; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Security; using Umbraco.Net; using Umbraco.Web.Install.Models; using Umbraco.Web.Security; @@ -17,16 +18,16 @@ namespace Umbraco.Web.Install.InstallSteps internal class StarterKitDownloadStep : InstallSetupStep { private readonly InstallHelper _installHelper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUmbracoVersion _umbracoVersion; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; private readonly IContentService _contentService; private readonly IPackagingService _packageService; - public StarterKitDownloadStep(IContentService contentService, IPackagingService packageService, InstallHelper installHelper, IWebSecurity webSecurity, IUmbracoVersion umbracoVersion, IUmbracoApplicationLifetime umbracoApplicationLifetime) + public StarterKitDownloadStep(IContentService contentService, IPackagingService packageService, InstallHelper installHelper, IBackofficeSecurityAccessor backofficeSecurityAccessor, IUmbracoVersion umbracoVersion, IUmbracoApplicationLifetime umbracoApplicationLifetime) { _installHelper = installHelper; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _umbracoVersion = umbracoVersion; _umbracoApplicationLifetime = umbracoApplicationLifetime; _contentService = contentService; @@ -67,7 +68,7 @@ namespace Umbraco.Web.Install.InstallSteps private async Task<(string packageFile, int packageId)> DownloadPackageFilesAsync(Guid kitGuid) { //Go get the package file from the package repo - var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, _umbracoVersion.Current, _webSecurity.GetUserId().ResultOr(0)); + var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, _umbracoVersion.Current, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (packageFile == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); //add an entry to the installedPackages.config @@ -77,7 +78,7 @@ namespace Umbraco.Web.Install.InstallSteps _packageService.SaveInstalledPackage(packageDefinition); - _packageService.InstallCompiledPackageFiles(packageDefinition, packageFile, _webSecurity.GetUserId().ResultOr(-1)); + _packageService.InstallCompiledPackageFiles(packageDefinition, packageFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(-1)); return (compiledPackage.PackageFile.Name, packageDefinition.Id); } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs index daf8255132..0f2394dcf4 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Umbraco.Core.Security; using Umbraco.Net; using Umbraco.Core.Services; using Umbraco.Web.Install.Models; @@ -15,13 +16,13 @@ namespace Umbraco.Web.Install.InstallSteps internal class StarterKitInstallStep : InstallSetupStep { private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IPackagingService _packagingService; - public StarterKitInstallStep(IUmbracoApplicationLifetime umbracoApplicationLifetime, IWebSecurity webSecurity, IPackagingService packagingService) + public StarterKitInstallStep(IUmbracoApplicationLifetime umbracoApplicationLifetime, IBackofficeSecurityAccessor backofficeSecurityAccessor, IPackagingService packagingService) { _umbracoApplicationLifetime = umbracoApplicationLifetime; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _packagingService = packagingService; } @@ -48,7 +49,7 @@ namespace Umbraco.Web.Install.InstallSteps var packageFile = new FileInfo(definition.PackagePath); - _packagingService.InstallCompiledPackageData(definition, packageFile, _webSecurity.GetUserId().ResultOr(-1)); + _packagingService.InstallCompiledPackageData(definition, packageFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(-1)); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs b/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs index b281e18b73..abc32fc008 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs @@ -10,6 +10,10 @@ using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; +using Umbraco.Core.Dictionary; +using Umbraco.Core.Configuration; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Web.Security; namespace Umbraco.Web.Models.Mapping @@ -24,7 +28,7 @@ namespace Umbraco.Web.Models.Mapping /// public class MemberTabsAndPropertiesMapper : TabsAndPropertiesMapper { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _localizedTextService; private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; @@ -33,7 +37,7 @@ namespace Umbraco.Web.Models.Mapping private readonly PropertyEditorCollection _propertyEditorCollection; public MemberTabsAndPropertiesMapper(ICultureDictionary cultureDictionary, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService, IMemberTypeService memberTypeService, IMemberService memberService, @@ -43,7 +47,7 @@ namespace Umbraco.Web.Models.Mapping PropertyEditorCollection propertyEditorCollection) : base(cultureDictionary, localizedTextService, contentTypeBaseServiceProvider) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); @@ -76,8 +80,8 @@ namespace Umbraco.Web.Models.Mapping isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } - if (_webSecurity.CurrentUser != null - && _webSecurity.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null + && _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", source.ContentTypeId); @@ -191,7 +195,7 @@ namespace Umbraco.Web.Models.Mapping // check if this property is flagged as sensitive var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias); // check permissions for viewing sensitive data - if (isSensitiveProperty && (_webSecurity.CurrentUser.HasAccessToSensitiveData() == false)) + if (isSensitiveProperty && (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData() == false)) { // mark this property as sensitive prop.IsSensitive = true; diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 08be22c07b..465305cd24 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -90,6 +90,7 @@ namespace Umbraco.Tests.Integration.TestServerTest { var url = LinkGenerator.GetUmbracoApiService(methodSelector); + var backofficeSecurityFactory = GetRequiredService(); var umbracoContextFactory = GetRequiredService(); var httpContextAccessor = GetRequiredService(); @@ -104,6 +105,7 @@ namespace Umbraco.Tests.Integration.TestServerTest } }; + backofficeSecurityFactory.EnsureBackofficeSecurity(); umbracoContextFactory.EnsureUmbracoContext(); return url; diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index b21de325cc..705690b898 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -243,6 +243,7 @@ namespace Umbraco.Tests.Integration.Testing public virtual void Configure(IApplicationBuilder app) { + Services.GetRequiredService().EnsureBackofficeSecurity(); Services.GetRequiredService().EnsureUmbracoContext(); // get the currently set ptions diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs index 236338390b..1a343a1e0b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -18,6 +18,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Mapping; using Umbraco.Core.Models; + using Umbraco.Core.Security; using Umbraco.Core.Strings; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; @@ -138,12 +139,14 @@ public void Validating_ContentItemSave() { var logger = Services.GetRequiredService(); - var webSecurity = Services.GetRequiredService(); + var backofficeSecurityFactory = Services.GetRequiredService(); + backofficeSecurityFactory.EnsureBackofficeSecurity(); + var backofficeSecurityAccessor = Services.GetRequiredService(); var localizedTextService = Services.GetRequiredService(); var propertyValidationService = Services.GetRequiredService(); var umbracoMapper = Services.GetRequiredService(); - var validator = new ContentSaveModelValidator(logger, webSecurity, localizedTextService, propertyValidationService); + var validator = new ContentSaveModelValidator(logger, backofficeSecurityAccessor.BackofficeSecurity, localizedTextService, propertyValidationService); var content = MockedContent.CreateTextpageContent(_contentType, "test", -1); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs index f087a4851c..6c725d1049 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs @@ -91,16 +91,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters .SetupGet(x => x.Id) .Returns(100); - var webSecurityMock = new Mock(); - webSecurityMock + var backofficeSecurityMock = new Mock(); + backofficeSecurityMock .SetupGet(x => x.CurrentUser) .Returns(currentUserMock.Object); var serviceProviderMock = new Mock(); serviceProviderMock - .Setup(x => x.GetService(typeof(IWebSecurity))) - .Returns(webSecurityMock.Object); + .Setup(x => x.GetService(typeof(IBackofficeSecurity))) + .Returns(backofficeSecurityMock.Object); httpContext.RequestServices = serviceProviderMock.Object; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs index 54499d97ba..f6e551dc27 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Tests.Common.TestHelpers.Entities; using Umbraco.Web.Actions; @@ -30,7 +31,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var result = att.GetValueFromResponse(new ObjectResult(expected)); @@ -48,7 +49,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var result = att.GetValueFromResponse(new ObjectResult(container)); @@ -66,7 +67,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var actual = att.GetValueFromResponse(new ObjectResult(container)); @@ -94,7 +95,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, userService, entityService, - Mock.Of() ); + Mock.Of() ); var path = ""; for (var i = 0; i < 10; i++) @@ -145,7 +146,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, userService, Mock.Of(), - Mock.Of() ); + Mock.Of() ); att.FilterBasedOnPermissions(list, user); Assert.AreEqual(3, list.Count); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs index 0d288b6310..a1904cb0da 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs @@ -9,6 +9,7 @@ using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Builders; @@ -39,6 +40,8 @@ namespace Umbraco.Tests.Integration { var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var globalSettings = new GlobalSettingsBuilder().Build(); var umbracoContextFactory = new UmbracoContextFactory( @@ -53,7 +56,7 @@ namespace Umbraco.Tests.Integration httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbracoContext = umbracoContextReference.UmbracoContext; @@ -73,7 +76,8 @@ namespace Umbraco.Tests.Integration var globalSettings = new GlobalSettingsBuilder().Build(); var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); - + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, Mock.Of(), @@ -86,7 +90,7 @@ namespace Umbraco.Tests.Integration httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbCtx = umbracoContextReference.UmbracoContext; @@ -105,7 +109,8 @@ namespace Umbraco.Tests.Integration publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); var content = new Mock(); content.Setup(x => x.Id).Returns(2); - + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var publishedSnapshotService = new Mock(); var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); @@ -123,7 +128,7 @@ namespace Umbraco.Tests.Integration httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbracoContext = umbracoContextReference.UmbracoContext; @@ -147,7 +152,8 @@ namespace Umbraco.Tests.Integration var globalSettings = new GlobalSettingsBuilder().Build(); var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); - + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, Mock.Of(), @@ -160,7 +166,7 @@ namespace Umbraco.Tests.Integration httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbracoContext = umbracoContextReference.UmbracoContext; diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 13f58f8021..02f6f24779 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -81,7 +81,7 @@ namespace Umbraco.Tests.Cache.PublishedCache _umbracoContext = new UmbracoContext( httpContextAccessor, publishedSnapshotService.Object, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 3d9b4af526..1c70879da1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -74,7 +74,7 @@ namespace Umbraco.Tests.PublishedContent var umbracoContext = new UmbracoContext( httpContextAccessor, publishedSnapshotService.Object, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 243ad50eef..edd4d38075 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -126,7 +126,7 @@ namespace Umbraco.Tests.Scoping var umbracoContext = new UmbracoContext( httpContextAccessor, service, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 87d470f31e..379c176099 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -95,7 +95,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var backofficeIdentity = (UmbracoBackOfficeIdentity) owinContext.Authentication.User.Identity; - var webSecurity = new Mock(); + var backofficeSecurity = new Mock(); //mock CurrentUser var groups = new List(); @@ -116,13 +116,13 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting mockUser.Setup(x => x.StartContentIds).Returns(backofficeIdentity.StartContentNodes); mockUser.Setup(x => x.StartMediaIds).Returns(backofficeIdentity.StartMediaNodes); mockUser.Setup(x => x.Username).Returns(backofficeIdentity.Username); - webSecurity.Setup(x => x.CurrentUser) + backofficeSecurity.Setup(x => x.CurrentUser) .Returns(mockUser.Object); //mock Validate - webSecurity.Setup(x => x.ValidateCurrentUser()) + backofficeSecurity.Setup(x => x.ValidateCurrentUser()) .Returns(() => true); - webSecurity.Setup(x => x.UserHasSectionAccess(It.IsAny(), It.IsAny())) + backofficeSecurity.Setup(x => x.UserHasSectionAccess(It.IsAny(), It.IsAny())) .Returns(() => true); var publishedSnapshot = new Mock(); @@ -135,7 +135,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var httpContextAccessor = TestHelper.GetHttpContextAccessor(httpContext); var umbCtx = new UmbracoContext(httpContextAccessor, publishedSnapshotService.Object, - webSecurity.Object, + backofficeSecurity.Object, globalSettings, TestHelper.GetHostingEnvironment(), new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index f1a834021f..fe41ac2d9c 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -372,7 +372,7 @@ namespace Umbraco.Tests.TestHelpers var umbracoContext = new UmbracoContext( httpContextAccessor, service, - Mock.Of(), + Mock.Of(), globalSettings ?? new GlobalSettingsBuilder().Build(), HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 0c39ee47f0..08a1297cda 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -316,7 +316,7 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(); Composition.RegisterUnique(); - Composition.RegisterUnique(); + Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index 5e89f29496..bcaf1ceccf 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -440,7 +440,7 @@ namespace Umbraco.Tests.Web.Mvc var ctx = new UmbracoContext( httpContextAccessor, _service, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs index 32d8e0917b..0e5b963d9f 100644 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( httpContextAccessor, Mock.Of(), - Mock.Of(), + Mock.Of(), TestObjects.GetGlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( httpContextAccessor, Mock.Of(), - Mock.Of(), + Mock.Of(), TestObjects.GetGlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), @@ -84,7 +84,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( httpContextAccessor, Mock.Of(), - Mock.Of(), + Mock.Of(), TestObjects.GetGlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 53a7a324dc..185269b6f1 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Extensions; using Umbraco.Net; @@ -39,7 +40,7 @@ namespace Umbraco.Web.BackOffice.Controllers [IsBackOffice] // TODO: This could be applied with our Application Model conventions public class AuthenticationController : UmbracoApiControllerBase { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly BackOfficeUserManager _userManager; private readonly BackOfficeSignInManager _signInManager; private readonly IUserService _userService; @@ -58,7 +59,7 @@ namespace Umbraco.Web.BackOffice.Controllers // TODO: We need to review all _userManager.Raise calls since many/most should be on the usermanager or signinmanager, very few should be here public AuthenticationController( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, BackOfficeUserManager backOfficeUserManager, BackOfficeSignInManager signInManager, IUserService userService, @@ -73,7 +74,7 @@ namespace Umbraco.Web.BackOffice.Controllers Core.Hosting.IHostingEnvironment hostingEnvironment, IRequestAccessor requestAccessor) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _userManager = backOfficeUserManager; _signInManager = signInManager; _userService = userService; @@ -96,7 +97,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize] public IDictionary GetPasswordConfig(int userId) { - return _passwordConfiguration.GetConfiguration(userId != _webSecurity.CurrentUser.Id); + return _passwordConfiguration.GetConfiguration(userId != _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); } /// @@ -164,7 +165,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public bool IsAuthenticated() { - var attempt = _webSecurity.AuthorizeRequest(); + var attempt = _backofficeSecurityAccessor.BackofficeSecurity.AuthorizeRequest(); if (attempt == ValidateRequestAttempt.Success) { return true; @@ -186,7 +187,7 @@ namespace Umbraco.Web.BackOffice.Controllers //[CheckIfUserTicketDataIsStale] // TODO: Migrate this, though it will need to be done differently at the cookie auth level public UserDetail GetCurrentUser() { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var result = _umbracoMapper.Map(user); //set their remaining seconds @@ -207,7 +208,7 @@ namespace Umbraco.Web.BackOffice.Controllers [SetAngularAntiForgeryTokens] public ActionResult GetCurrentInvitedUser() { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user.IsApproved) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 141578cccd..6db4efab40 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Configuration.Grid; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.WebAssets; using Umbraco.Extensions; @@ -45,7 +46,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly BackOfficeServerVariables _backOfficeServerVariables; private readonly AppCaches _appCaches; private readonly BackOfficeSignInManager _signInManager; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILogger _logger; public BackOfficeController( @@ -59,7 +60,7 @@ namespace Umbraco.Web.BackOffice.Controllers BackOfficeServerVariables backOfficeServerVariables, AppCaches appCaches, BackOfficeSignInManager signInManager, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger) { _userManager = userManager; @@ -72,7 +73,7 @@ namespace Umbraco.Web.BackOffice.Controllers _backOfficeServerVariables = backOfficeServerVariables; _appCaches = appCaches; _signInManager = signInManager; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _logger = logger; } @@ -93,7 +94,7 @@ namespace Umbraco.Web.BackOffice.Controllers //if you are hitting VerifyInvite, you're already signed in as a different user, and the token is invalid //you'll exit on one of the return RedirectToAction(nameof(Default)) but you're still logged in so you just get //dumped at the default admin view with no detail - if (_webSecurity.IsAuthenticated()) + if (_backofficeSecurityAccessor.BackofficeSecurity.IsAuthenticated()) { await _signInManager.SignOutAsync(); } @@ -186,7 +187,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public Dictionary> LocalizedText(string culture = null) { - var isAuthenticated = _webSecurity.IsAuthenticated(); + var isAuthenticated = _backofficeSecurityAccessor.BackofficeSecurity.IsAuthenticated(); var cultureInfo = string.IsNullOrWhiteSpace(culture) //if the user is logged in, get their culture, otherwise default to 'en' diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index 7704b198ae..66ece55162 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.Editors private readonly IContentService _contentService; private readonly ILocalizedTextService _localizedTextService; private readonly IUserService _userService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IContentTypeService _contentTypeService; private readonly UmbracoMapper _umbracoMapper; @@ -84,7 +84,7 @@ namespace Umbraco.Web.Editors PropertyEditorCollection propertyEditors, IContentService contentService, IUserService userService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IContentTypeService contentTypeService, UmbracoMapper umbracoMapper, @@ -105,7 +105,7 @@ namespace Umbraco.Web.Editors _contentService = contentService; _localizedTextService = localizedTextService; _userService = userService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _entityService = entityService; _contentTypeService = contentTypeService; _umbracoMapper = umbracoMapper; @@ -428,7 +428,7 @@ namespace Umbraco.Web.Editors private ContentItemDisplay GetEmpty(IContentType contentType, int parentId) { - var emptyContent = _contentService.Create("", parentId, contentType.Alias, _webSecurity.GetUserId().ResultOr(0)); + var emptyContent = _contentService.Create("", parentId, contentType.Alias, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var mapped = MapToDisplay(emptyContent); // translate the content type name if applicable mapped.ContentTypeName = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, mapped.ContentTypeName); @@ -597,9 +597,9 @@ namespace Umbraco.Web.Editors EnsureUniqueName(name, content, nameof(name)); - var blueprint = _contentService.CreateContentFromBlueprint(content, name, _webSecurity.GetUserId().ResultOr(0)); + var blueprint = _contentService.CreateContentFromBlueprint(content, name, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); - _contentService.SaveBlueprint(blueprint, _webSecurity.GetUserId().ResultOr(0)); + _contentService.SaveBlueprint(blueprint, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var notificationModel = new SimpleNotificationModel(); notificationModel.AddSuccessNotification( @@ -633,7 +633,7 @@ namespace Umbraco.Web.Editors { EnsureUniqueName(content.Name, content, "Name"); - _contentService.SaveBlueprint(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + _contentService.SaveBlueprint(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); //we need to reuse the underlying logic so return the result that it wants return OperationResult.Succeed(new EventMessages()); }, @@ -658,7 +658,7 @@ namespace Umbraco.Web.Editors { var contentItemDisplay = PostSaveInternal( contentItem, - content => _contentService.Save(contentItem.PersistedContent, _webSecurity.CurrentUser.Id), + content => _contentService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id), MapToDisplay); return contentItemDisplay; @@ -760,7 +760,7 @@ namespace Umbraco.Web.Editors case ContentSaveAction.SendPublish: case ContentSaveAction.SendPublishNew: - var sendResult = _contentService.SendToPublication(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + var sendResult = _contentService.SendToPublication(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); wasCancelled = sendResult == false; if (sendResult) { @@ -1204,7 +1204,7 @@ namespace Umbraco.Web.Editors //if this item's path has already been denied or if the user doesn't have access to it, add to the deny list if (denied.Any(x => c.Path.StartsWith($"{x.Path},")) || (ContentPermissionsHelper.CheckPermissions(c, - _webSecurity.CurrentUser, _userService, _entityService, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _userService, _entityService, ActionPublish.ActionLetter) == ContentPermissionsHelper.ContentAccess.Denied)) { denied.Add(c); @@ -1221,7 +1221,7 @@ namespace Umbraco.Web.Editors if (!contentItem.PersistedContent.ContentType.VariesByCulture()) { //its invariant, proceed normally - var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, userId: _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, userId: _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); // TODO: Deal with multiple cancellations wasCancelled = publishStatus.Any(x => x.Result == PublishResultType.FailedPublishCancelledByEvent); successfulCultures = null; //must be null! this implies invariant @@ -1256,7 +1256,7 @@ namespace Umbraco.Web.Editors if (canPublish) { //proceed to publish if all validation still succeeds - var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, culturesToPublish, _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, culturesToPublish, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); // TODO: Deal with multiple cancellations wasCancelled = publishStatus.Any(x => x.Result == PublishResultType.FailedPublishCancelledByEvent); successfulCultures = contentItem.Variants.Where(x => x.Publish).Select(x => x.Culture).ToArray(); @@ -1265,7 +1265,7 @@ namespace Umbraco.Web.Editors else { //can only save - var saveResult = _contentService.Save(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + var saveResult = _contentService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); var publishStatus = new[] { new PublishResult(PublishResultType.FailedPublishMandatoryCultureMissing, null, contentItem.PersistedContent) @@ -1293,7 +1293,7 @@ namespace Umbraco.Web.Editors if (!contentItem.PersistedContent.ContentType.VariesByCulture()) { //its invariant, proceed normally - var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, userId: _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, userId: _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent; successfulCultures = null; //must be null! this implies invariant return publishStatus; @@ -1338,7 +1338,7 @@ namespace Umbraco.Web.Editors if (canPublish) { //proceed to publish if all validation still succeeds - var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, culturesToPublish, _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, culturesToPublish, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent; successfulCultures = culturesToPublish; return publishStatus; @@ -1346,7 +1346,7 @@ namespace Umbraco.Web.Editors else { //can only save - var saveResult = _contentService.Save(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + var saveResult = _contentService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); var publishStatus = new PublishResult(PublishResultType.FailedPublishMandatoryCultureMissing, null, contentItem.PersistedContent); wasCancelled = saveResult.Result == OperationResultType.FailedCancelledByEvent; successfulCultures = Array.Empty(); @@ -1501,7 +1501,7 @@ namespace Umbraco.Web.Editors return HandleContentNotFound(id, false); } - var publishResult = _contentService.SaveAndPublish(foundContent, userId: _webSecurity.GetUserId().ResultOr(0)); + var publishResult = _contentService.SaveAndPublish(foundContent, userId: _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (publishResult.Success == false) { var notificationModel = new SimpleNotificationModel(); @@ -1553,7 +1553,7 @@ namespace Umbraco.Web.Editors //if the current item is in the recycle bin if (foundContent.Trashed == false) { - var moveResult = _contentService.MoveToRecycleBin(foundContent, _webSecurity.GetUserId().ResultOr(0)); + var moveResult = _contentService.MoveToRecycleBin(foundContent, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (moveResult.Success == false) { //returning an object of INotificationModel will ensure that any pending @@ -1563,7 +1563,7 @@ namespace Umbraco.Web.Editors } else { - var deleteResult = _contentService.Delete(foundContent, _webSecurity.GetUserId().ResultOr(0)); + var deleteResult = _contentService.Delete(foundContent, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (deleteResult.Success == false) { //returning an object of INotificationModel will ensure that any pending @@ -1587,7 +1587,7 @@ namespace Umbraco.Web.Editors [EnsureUserPermissionForContent(Constants.System.RecycleBinContent, ActionDelete.ActionLetter)] public IActionResult EmptyRecycleBin() { - _contentService.EmptyRecycleBin(_webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + _contentService.EmptyRecycleBin(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); return new UmbracoNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty")); } @@ -1616,7 +1616,7 @@ namespace Umbraco.Web.Editors var contentService = _contentService; // Save content with new sort order and update content xml in db accordingly - var sortResult = contentService.Sort(sorted.IdSortOrder, _webSecurity.CurrentUser.Id); + var sortResult = contentService.Sort(sorted.IdSortOrder, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); if (!sortResult.Success) { Logger.Warn("Content sorting failed, this was probably caused by an event being cancelled"); @@ -1643,7 +1643,7 @@ namespace Umbraco.Web.Editors { var toMove = ValidateMoveOrCopy(move); - _contentService.Move(toMove, move.ParentId, _webSecurity.GetUserId().ResultOr(0)); + _contentService.Move(toMove, move.ParentId, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return Content(toMove.Path, MediaTypeNames.Text.Plain, Encoding.UTF8); } @@ -1658,7 +1658,7 @@ namespace Umbraco.Web.Editors { var toCopy = ValidateMoveOrCopy(copy); - var c = _contentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive, _webSecurity.GetUserId().ResultOr(0)); + var c = _contentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return Content(c.Path, MediaTypeNames.Text.Plain, Encoding.UTF8); } @@ -1681,7 +1681,7 @@ namespace Umbraco.Web.Editors if (model.Cultures.Length == 0 || model.Cultures.Length == languageCount) { //this means that the entire content item will be unpublished - var unpublishResult = _contentService.Unpublish(foundContent, userId: _webSecurity.GetUserId().ResultOr(0)); + var unpublishResult = _contentService.Unpublish(foundContent, userId: _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var content = MapToDisplay(foundContent); @@ -1704,7 +1704,7 @@ namespace Umbraco.Web.Editors var results = new Dictionary(); foreach (var c in model.Cultures) { - var result = _contentService.Unpublish(foundContent, culture: c, userId: _webSecurity.GetUserId().ResultOr(0)); + var result = _contentService.Unpublish(foundContent, culture: c, userId: _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); results[c] = result; if (result.Result == PublishResultType.SuccessUnpublishMandatoryCulture) { @@ -1772,7 +1772,7 @@ namespace Umbraco.Web.Editors return NotFound("There is no content node with id {model.NodeId}."); } - var permission = _userService.GetPermissions(_webSecurity.CurrentUser, node.Path); + var permission = _userService.GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, node.Path); if (permission.AssignedPermissions.Contains(ActionAssignDomain.ActionLetter.ToString(), StringComparer.Ordinal) == false) @@ -2260,7 +2260,7 @@ namespace Umbraco.Web.Editors { var display = _umbracoMapper.Map(content, context => { - context.Items["CurrentUser"] = _webSecurity.CurrentUser; + context.Items["CurrentUser"] = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; }); display.AllowPreview = display.AllowPreview && content.Trashed == false && content.ContentType.IsElement == false; return display; @@ -2275,7 +2275,7 @@ namespace Umbraco.Web.Editors var content = _contentService.GetById(contentId); if (content == null) return NotFound(); - var userNotifications = _notificationService.GetUserNotifications(_webSecurity.CurrentUser, content.Path).ToList(); + var userNotifications = _notificationService.GetUserNotifications(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, content.Path).ToList(); foreach (var a in _actionCollection.Where(x => x.ShowInNotifier)) { @@ -2297,7 +2297,7 @@ namespace Umbraco.Web.Editors var content = _contentService.GetById(contentId); if (content == null) return NotFound(); - _notificationService.SetNotifications(_webSecurity.CurrentUser, content, notifyOptions); + _notificationService.SetNotifications(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, content, notifyOptions); return NoContent(); } @@ -2362,7 +2362,7 @@ namespace Umbraco.Web.Editors [HttpPost] public IActionResult PostRollbackContent(int contentId, int versionId, string culture = "*") { - var rollbackResult = _contentService.Rollback(contentId, versionId, culture, _webSecurity.GetUserId().ResultOr(0)); + var rollbackResult = _contentService.Rollback(contentId, versionId, culture, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (rollbackResult.Success) return Ok(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs index 4f7260a35c..7955b82eeb 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs @@ -26,6 +26,7 @@ using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; using Constants = Umbraco.Core.Constants; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; @@ -56,7 +57,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IIOHelper _ioHelper; private readonly IContentTypeService _contentTypeService; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IDataTypeService _dataTypeService; private readonly IShortStringHelper _shortStringHelper; private readonly ILocalizedTextService _localizedTextService; @@ -81,7 +82,7 @@ namespace Umbraco.Web.BackOffice.Controllers PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IIOHelper ioHelper, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IDataTypeService dataTypeService, IShortStringHelper shortStringHelper, IFileService fileService, @@ -108,7 +109,7 @@ namespace Umbraco.Web.BackOffice.Controllers _ioHelper = ioHelper; _contentTypeService = contentTypeService; _umbracoMapper = umbracoMapper; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _dataTypeService = dataTypeService; _shortStringHelper = shortStringHelper; _localizedTextService = localizedTextService; @@ -207,7 +208,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - _contentTypeService.Delete(foundType, _webSecurity.CurrentUser.Id); + _contentTypeService.Delete(foundType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -306,14 +307,14 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult DeleteContainer(int id) { - _contentTypeService.DeleteContainer(id, _webSecurity.CurrentUser.Id); + _contentTypeService.DeleteContainer(id, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } public IActionResult PostCreateContainer(int parentId, string name) { - var result = _contentTypeService.CreateContainer(parentId, name, _webSecurity.CurrentUser.Id); + var result = _contentTypeService.CreateContainer(parentId, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id @@ -322,7 +323,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult PostRenameContainer(int id, string name) { - var result = _contentTypeService.RenameContainer(id, name, _webSecurity.CurrentUser.Id); + var result = _contentTypeService.RenameContainer(id, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id @@ -622,7 +623,7 @@ namespace Umbraco.Web.BackOffice.Controllers var xd = new XmlDocument {XmlResolver = null}; xd.Load(filePath); - var userId = _webSecurity.GetUserId().ResultOr(0); + var userId = _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0); var element = XElement.Parse(xd.InnerXml); dataInstaller.ImportDocumentType(element, userId); diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 433c26169f..3aab1853dc 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -16,6 +16,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Media; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; @@ -39,7 +40,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ContentSettings _contentSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IImageUrlGenerator _imageUrlGenerator; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUserService _userService; private readonly UmbracoMapper _umbracoMapper; private readonly BackOfficeUserManager _backOfficeUserManager; @@ -53,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers IOptions contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IUserService userService, UmbracoMapper umbracoMapper, BackOfficeUserManager backOfficeUserManager, @@ -66,7 +67,7 @@ namespace Umbraco.Web.BackOffice.Controllers _contentSettings = contentSettings.Value; _hostingEnvironment = hostingEnvironment; _imageUrlGenerator = imageUrlGenerator; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _userService = userService; _umbracoMapper = umbracoMapper; _backOfficeUserManager = backOfficeUserManager; @@ -86,7 +87,7 @@ namespace Umbraco.Web.BackOffice.Controllers public Dictionary GetPermissions(int[] nodeIds) { var permissions = _userService - .GetPermissions(_webSecurity.CurrentUser, nodeIds); + .GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, nodeIds); var permissionsDictionary = new Dictionary(); foreach (var nodeId in nodeIds) @@ -107,7 +108,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public bool HasPermission(string permissionToCheck, int nodeId) { - var p = _userService.GetPermissions(_webSecurity.CurrentUser, nodeId).GetAllPermissions(); + var p = _userService.GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, nodeId).GetAllPermissions(); if (p.Contains(permissionToCheck.ToString(CultureInfo.InvariantCulture))) { return true; @@ -126,15 +127,15 @@ namespace Umbraco.Web.BackOffice.Controllers if (status == null) throw new ArgumentNullException(nameof(status)); List userTours; - if (_webSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) { userTours = new List { status }; - _webSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); - _userService.Save(_webSecurity.CurrentUser); + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); + _userService.Save(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); return userTours; } - userTours = JsonConvert.DeserializeObject>(_webSecurity.CurrentUser.TourData).ToList(); + userTours = JsonConvert.DeserializeObject>(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData).ToList(); var found = userTours.FirstOrDefault(x => x.Alias == status.Alias); if (found != null) { @@ -142,8 +143,8 @@ namespace Umbraco.Web.BackOffice.Controllers userTours.Remove(found); } userTours.Add(status); - _webSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); - _userService.Save(_webSecurity.CurrentUser); + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); + _userService.Save(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); return userTours; } @@ -153,10 +154,10 @@ namespace Umbraco.Web.BackOffice.Controllers /// public IEnumerable GetUserTours() { - if (_webSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) return Enumerable.Empty(); - var userTours = JsonConvert.DeserializeObject>(_webSecurity.CurrentUser.TourData); + var userTours = JsonConvert.DeserializeObject>(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData); return userTours; } @@ -172,7 +173,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize(redirectToUmbracoLogin: false, requireApproval : true)] public async Task PostSetInvitedUserPassword([FromBody]string newPassword) { - var user = await _backOfficeUserManager.FindByIdAsync(_webSecurity.GetUserId().ResultOr(0).ToString()); + var user = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0).ToString()); if (user == null) throw new InvalidOperationException("Could not find user"); var result = await _backOfficeUserManager.AddPasswordAsync(user, newPassword); @@ -187,13 +188,13 @@ namespace Umbraco.Web.BackOffice.Controllers } //They've successfully set their password, we can now update their user account to be approved - _webSecurity.CurrentUser.IsApproved = true; + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsApproved = true; //They've successfully set their password, and will now get fully logged into the back office, so the lastlogindate is set so the backoffice shows they have logged in - _webSecurity.CurrentUser.LastLoginDate = DateTime.UtcNow; - _userService.Save(_webSecurity.CurrentUser); + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.LastLoginDate = DateTime.UtcNow; + _userService.Save(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); //now we can return their full object since they are now really logged into the back office - var userDisplay = _umbracoMapper.Map(_webSecurity.CurrentUser); + var userDisplay = _umbracoMapper.Map(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); userDisplay.SecondsUntilTimeout = HttpContext.User.GetRemainingAuthSeconds(); return userDisplay; @@ -203,7 +204,7 @@ namespace Umbraco.Web.BackOffice.Controllers public async Task PostSetAvatar(IList files) { //borrow the logic from the user controller - return await UsersController.PostSetAvatarInternal(files, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, _webSecurity.GetUserId().ResultOr(0)); + return await UsersController.PostSetAvatarInternal(files, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); } /// @@ -216,7 +217,7 @@ namespace Umbraco.Web.BackOffice.Controllers public async Task> PostChangePassword(ChangingPasswordModel data) { var passwordChanger = new PasswordChanger(_logger); - var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_webSecurity.CurrentUser, _webSecurity.CurrentUser, data, _backOfficeUserManager); + var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, data, _backOfficeUserManager); if (passwordChangeResult.Success) { @@ -238,7 +239,7 @@ namespace Umbraco.Web.BackOffice.Controllers [ValidateAngularAntiForgeryToken] public async Task> GetCurrentUserLinkedLogins() { - var identityUser = await _backOfficeUserManager.FindByIdAsync(_webSecurity.GetUserId().ResultOr(0).ToString()); + var identityUser = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0).ToString()); return identityUser.Logins.ToDictionary(x => x.LoginProvider, x => x.ProviderKey); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs index 2882c28f4f..207dee60f4 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -34,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly ILogger _logger; private readonly ILocalizationService _localizationService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly GlobalSettings _globalSettings; private readonly ILocalizedTextService _localizedTextService; private readonly UmbracoMapper _umbracoMapper; @@ -42,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Controllers public DictionaryController( ILogger logger, ILocalizationService localizationService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IOptions globalSettings, ILocalizedTextService localizedTextService, UmbracoMapper umbracoMapper @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Controllers { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); @@ -74,10 +75,10 @@ namespace Umbraco.Web.BackOffice.Controllers foreach (var dictionaryItem in foundDictionaryDescendants) { - _localizationService.Delete(dictionaryItem, _webSecurity.CurrentUser.Id); + _localizationService.Delete(dictionaryItem, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); } - _localizationService.Delete(foundDictionary, _webSecurity.CurrentUser.Id); + _localizationService.Delete(foundDictionary, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -104,7 +105,7 @@ namespace Umbraco.Web.BackOffice.Controllers { var message = _localizedTextService.Localize( "dictionaryItem/changeKeyError", - _webSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings), + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings), new Dictionary { { "0", key } }); throw HttpResponseException.CreateNotificationValidationErrorResponse(message); } @@ -218,7 +219,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (dictionaryItem == null) throw HttpResponseException.CreateNotificationValidationErrorResponse("Dictionary item does not exist"); - var userCulture = _webSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings); + var userCulture = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings); if (dictionary.NameIsDirty) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 1afe9bccf4..35d9c51cd4 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Core.Mapping; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Xml; @@ -53,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IPublishedContentQuery _publishedContentQuery; private readonly IShortStringHelper _shortStringHelper; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IContentService _contentService; private readonly UmbracoMapper _umbracoMapper; @@ -74,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Controllers IPublishedContentQuery publishedContentQuery, IShortStringHelper shortStringHelper, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IPublishedUrlProvider publishedUrlProvider, IContentService contentService, UmbracoMapper umbracoMapper, @@ -96,7 +97,7 @@ namespace Umbraco.Web.BackOffice.Controllers publishedContentQuery ?? throw new ArgumentNullException(nameof(publishedContentQuery)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _publishedUrlProvider = publishedUrlProvider ?? throw new ArgumentNullException(nameof(publishedUrlProvider)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -175,7 +176,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (string.IsNullOrEmpty(query)) return result; - var allowedSections = _webSecurity.CurrentUser.AllowedSections.ToArray(); + var allowedSections = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.ToArray(); foreach (var searchableTree in _searchableTreeCollection.SearchableApplicationTrees.OrderBy(t => t.Value.SortOrder)) { @@ -721,9 +722,9 @@ namespace Umbraco.Web.BackOffice.Controllers switch (type) { case UmbracoEntityTypes.Document: - return _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); + return _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); case UmbracoEntityTypes.Media: - return _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); + return _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); default: return Array.Empty(); } @@ -862,10 +863,10 @@ namespace Umbraco.Web.BackOffice.Controllers switch (entityType) { case UmbracoEntityTypes.Document: - aids = _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); + aids = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); break; case UmbracoEntityTypes.Media: - aids = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); + aids = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); break; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/LogController.cs b/src/Umbraco.Web.BackOffice/Controllers/LogController.cs index e99ea890d7..7dd2b1af44 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/LogController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/LogController.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -26,7 +27,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IImageUrlGenerator _imageUrlGenerator; private readonly IAuditService _auditService; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUserService _userService; private readonly AppCaches _appCaches; private readonly ISqlContext _sqlContext; @@ -36,7 +37,7 @@ namespace Umbraco.Web.BackOffice.Controllers IImageUrlGenerator imageUrlGenerator, IAuditService auditService, UmbracoMapper umbracoMapper, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IUserService userService, AppCaches appCaches, ISqlContext sqlContext) @@ -45,7 +46,7 @@ namespace Umbraco.Web.BackOffice.Controllers _imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator)); _auditService = auditService ?? throw new ArgumentNullException(nameof(auditService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); _sqlContext = sqlContext ?? throw new ArgumentNullException(nameof(sqlContext)); @@ -89,7 +90,7 @@ namespace Umbraco.Web.BackOffice.Controllers long totalRecords; var dateQuery = sinceDate.HasValue ? _sqlContext.Query().Where(x => x.CreateDate >= sinceDate) : null; - var userId = _webSecurity.GetUserId().ResultOr(0); + var userId = _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0); var result = _auditService.GetPagedItemsByUser(userId, pageNumber - 1, pageSize, out totalRecords, orderDirection, customFilter:dateQuery); var mapped = _umbracoMapper.MapEnumerable(result); return new PagedResult(totalRecords, pageNumber, pageSize) diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs index cf951a57c3..b64a4753bb 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs @@ -18,6 +18,7 @@ using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Security; using Umbraco.Core; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; namespace Umbraco.Web.BackOffice.Controllers { @@ -32,7 +33,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ParameterEditorCollection _parameterEditorCollection; private readonly IMacroService _macroService; private readonly IShortStringHelper _shortStringHelper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILogger _logger; private readonly IHostingEnvironment _hostingEnvironment; private readonly UmbracoMapper _umbracoMapper; @@ -41,7 +42,7 @@ namespace Umbraco.Web.BackOffice.Controllers ParameterEditorCollection parameterEditorCollection, IMacroService macroService, IShortStringHelper shortStringHelper, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, IHostingEnvironment hostingEnvironment, UmbracoMapper umbracoMapper @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Controllers _parameterEditorCollection = parameterEditorCollection ?? throw new ArgumentNullException(nameof(parameterEditorCollection)); _macroService = macroService ?? throw new ArgumentNullException(nameof(macroService)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); @@ -95,7 +96,7 @@ namespace Umbraco.Web.BackOffice.Controllers MacroSource = string.Empty }; - _macroService.Save(macro, _webSecurity.CurrentUser.Id); + _macroService.Save(macro, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return macro.Id; } @@ -215,7 +216,7 @@ namespace Umbraco.Web.BackOffice.Controllers try { - _macroService.Save(macro, _webSecurity.CurrentUser.Id); + _macroService.Save(macro, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); macroDisplay.Notifications.Clear(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index c9eaea0d4a..34f0f0afd7 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -26,6 +26,9 @@ using Umbraco.Core.Models.Validation; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; +using Umbraco.Web.ContentApps; +using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; @@ -55,7 +58,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMediaTypeService _mediaTypeService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly UmbracoMapper _umbracoMapper; private readonly IDataTypeService _dataTypeService; private readonly ILocalizedTextService _localizedTextService; @@ -72,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Controllers IMediaTypeService mediaTypeService, IMediaService mediaService, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, UmbracoMapper umbracoMapper, IDataTypeService dataTypeService, ISqlContext sqlContext, @@ -88,7 +91,7 @@ namespace Umbraco.Web.BackOffice.Controllers _mediaTypeService = mediaTypeService; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _umbracoMapper = umbracoMapper; _dataTypeService = dataTypeService; _localizedTextService = localizedTextService; @@ -115,7 +118,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - var emptyContent = _mediaService.CreateMedia("", parentId, contentType.Alias, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var emptyContent = _mediaService.CreateMedia("", parentId, contentType.Alias, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); var mapped = _umbracoMapper.Map(emptyContent); //remove the listview app if it exists @@ -277,7 +280,7 @@ namespace Umbraco.Web.BackOffice.Controllers protected int[] UserStartNodes { - get { return _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); } + get { return _userStartNodes ?? (_userStartNodes = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); } } /// @@ -434,7 +437,7 @@ namespace Umbraco.Web.BackOffice.Controllers //if the current item is in the recycle bin if (foundMedia.Trashed == false) { - var moveResult = _mediaService.MoveToRecycleBin(foundMedia, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var moveResult = _mediaService.MoveToRecycleBin(foundMedia, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); if (moveResult == false) { //returning an object of INotificationModel will ensure that any pending @@ -444,7 +447,7 @@ namespace Umbraco.Web.BackOffice.Controllers } else { - var deleteResult = _mediaService.Delete(foundMedia, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var deleteResult = _mediaService.Delete(foundMedia, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); if (deleteResult == false) { //returning an object of INotificationModel will ensure that any pending @@ -468,7 +471,7 @@ namespace Umbraco.Web.BackOffice.Controllers var destinationParentID = move.ParentId; var sourceParentID = toMove.ParentId; - var moveResult = _mediaService.Move(toMove, move.ParentId, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var moveResult = _mediaService.Move(toMove, move.ParentId, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); if (sourceParentID == destinationParentID) { @@ -542,7 +545,7 @@ namespace Umbraco.Web.BackOffice.Controllers } //save the item - var saveStatus = _mediaService.Save(contentItem.PersistedContent, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var saveStatus = _mediaService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); //return the updated model var display = _umbracoMapper.Map(contentItem.PersistedContent); @@ -588,7 +591,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult EmptyRecycleBin() { - _mediaService.EmptyRecycleBin(_webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + _mediaService.EmptyRecycleBin(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); return new UmbracoNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty")); } @@ -645,7 +648,7 @@ namespace Umbraco.Web.BackOffice.Controllers var mediaService = _mediaService; var f = mediaService.CreateMedia(folder.Name, parentId.Value, Constants.Conventions.MediaTypes.Folder); - mediaService.Save(f, _webSecurity.CurrentUser.Id); + mediaService.Save(f, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return _umbracoMapper.Map(f); } @@ -753,7 +756,7 @@ namespace Umbraco.Web.BackOffice.Controllers var mediaItemName = fileName.ToFriendlyName(); - var f = mediaService.CreateMedia(mediaItemName, parentId.Value, mediaType, _webSecurity.CurrentUser.Id); + var f = mediaService.CreateMedia(mediaItemName, parentId.Value, mediaType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); await using (var stream = formFile.OpenReadStream()) @@ -762,7 +765,7 @@ namespace Umbraco.Web.BackOffice.Controllers } - var saveResult = mediaService.Save(f, _webSecurity.CurrentUser.Id); + var saveResult = mediaService.Save(f, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); if (saveResult == false) { AddCancelMessage(tempFiles, @@ -855,7 +858,7 @@ namespace Umbraco.Web.BackOffice.Controllers //ensure the user has access to this folder by parent id! if (validatePermissions && CheckPermissions( new Dictionary(), - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _mediaService, _entityService, intParentId) == false) diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs index 617d3f1538..31cc5d63cd 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.BackOffice.Filters; @@ -36,7 +37,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMediaTypeService _mediaTypeService; private readonly IShortStringHelper _shortStringHelper; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaTypeController(ICultureDictionary cultureDictionary, EditorValidatorCollection editorValidatorCollection, @@ -48,7 +49,7 @@ namespace Umbraco.Web.BackOffice.Controllers IShortStringHelper shortStringHelper, IEntityService entityService, IMediaService mediaService, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) : base( cultureDictionary, editorValidatorCollection, @@ -64,7 +65,7 @@ namespace Umbraco.Web.BackOffice.Controllers _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _contentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); } @@ -147,7 +148,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - _mediaTypeService.Delete(foundType, _webSecurity.CurrentUser.Id); + _mediaTypeService.Delete(foundType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -241,14 +242,14 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult DeleteContainer(int id) { - _mediaTypeService.DeleteContainer(id, _webSecurity.CurrentUser.Id); + _mediaTypeService.DeleteContainer(id, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } public IActionResult PostCreateContainer(int parentId, string name) { - var result = _mediaTypeService.CreateContainer(parentId, name, _webSecurity.CurrentUser.Id); + var result = _mediaTypeService.CreateContainer(parentId, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id @@ -257,7 +258,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult PostRenameContainer(int id, string name) { - var result = _mediaTypeService.RenameContainer(id, name, _webSecurity.CurrentUser.Id); + var result = _mediaTypeService.RenameContainer(id, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs index 6a93bf6437..6d60da0910 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs @@ -54,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMemberTypeService _memberTypeService; private readonly IDataTypeService _dataTypeService; private readonly ILocalizedTextService _localizedTextService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IJsonSerializer _jsonSerializer; public MemberController( @@ -70,7 +70,7 @@ namespace Umbraco.Web.BackOffice.Controllers IMemberService memberService, IMemberTypeService memberTypeService, IDataTypeService dataTypeService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IJsonSerializer jsonSerializer) : base(cultureDictionary, logger, shortStringHelper, eventMessages, localizedTextService) { @@ -82,7 +82,7 @@ namespace Umbraco.Web.BackOffice.Controllers _memberTypeService = memberTypeService; _dataTypeService = dataTypeService; _localizedTextService = localizedTextService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _jsonSerializer = jsonSerializer; } @@ -310,7 +310,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}"); var member = new Member(contentItem.Name, contentItem.Email, contentItem.Username, memberType, true) { - CreatorId = _webSecurity.CurrentUser.Id, + CreatorId = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id, RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword), Comments = contentItem.Comments, IsApproved = contentItem.IsApproved @@ -328,13 +328,13 @@ namespace Umbraco.Web.BackOffice.Controllers /// private void UpdateMemberData(MemberSave contentItem) { - contentItem.PersistedContent.WriterId = _webSecurity.CurrentUser.Id; + contentItem.PersistedContent.WriterId = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id; // If the user doesn't have access to sensitive values, then we need to check if any of the built in member property types // have been marked as sensitive. If that is the case we cannot change these persisted values no matter what value has been posted. // There's only 3 special ones we need to deal with that are part of the MemberSave instance: Comments, IsApproved, IsLockedOut // but we will take care of this in a generic way below so that it works for all props. - if (!_webSecurity.CurrentUser.HasAccessToSensitiveData()) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData()) { var memberType = _memberTypeService.Get(contentItem.PersistedContent.ContentTypeId); var sensitiveProperties = memberType @@ -458,7 +458,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public IActionResult ExportMemberData(Guid key) { - var currentUser = _webSecurity.CurrentUser; + var currentUser = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (currentUser.HasAccessToSensitiveData() == false) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs index 8ef8749c2d..e4d616cc43 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; using Constants = Umbraco.Core.Constants; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -33,7 +34,7 @@ namespace Umbraco.Web.Editors public class MemberTypeController : ContentTypeControllerBase { private readonly IMemberTypeService _memberTypeService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IShortStringHelper _shortStringHelper; private readonly UmbracoMapper _umbracoMapper; private readonly ILocalizedTextService _localizedTextService; @@ -46,7 +47,7 @@ namespace Umbraco.Web.Editors IMemberTypeService memberTypeService, UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IShortStringHelper shortStringHelper) : base(cultureDictionary, editorValidatorCollection, @@ -57,7 +58,7 @@ namespace Umbraco.Web.Editors localizedTextService) { _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _localizedTextService = @@ -141,7 +142,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - _memberTypeService.Delete(foundType, _webSecurity.CurrentUser.Id); + _memberTypeService.Delete(foundType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -201,7 +202,7 @@ namespace Umbraco.Web.Editors var ctId = Convert.ToInt32(contentTypeSave.Id); var ct = ctId > 0 ? _memberTypeService.Get(ctId) : null; - if (_webSecurity.CurrentUser.HasAccessToSensitiveData() == false) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData() == false) { //We need to validate if any properties on the contentTypeSave have had their IsSensitiveValue changed, //and if so, we need to check if the current user has access to sensitive values. If not, we have to return an error diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs index d8df34748d..fa16288fb5 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs @@ -10,6 +10,7 @@ using Semver; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -27,16 +28,16 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly IHostingEnvironment _hostingEnvironment; private readonly IPackagingService _packagingService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public PackageController( IHostingEnvironment hostingEnvironment, IPackagingService packagingService, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) { _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } public IEnumerable GetCreatedPackages() @@ -90,7 +91,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpDelete] public IActionResult DeleteCreatedPackage(int packageId) { - _packagingService.DeleteCreatedPackage(packageId, _webSecurity.GetUserId().ResultOr(0)); + _packagingService.DeleteCreatedPackage(packageId, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return Ok(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs index b61e86746a..fe9523f410 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models.Packaging; using Umbraco.Net; using Umbraco.Core.Packaging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.WebAssets; using Umbraco.Web.BackOffice.Filters; @@ -38,7 +39,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IRuntimeMinifier _runtimeMinifier; private readonly IPackagingService _packagingService; private readonly ILogger _logger; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _localizedTextService; public PackageInstallController( @@ -48,7 +49,7 @@ namespace Umbraco.Web.BackOffice.Controllers IRuntimeMinifier runtimeMinifier, IPackagingService packagingService, ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService) { _umbracoVersion = umbracoVersion ?? throw new ArgumentNullException(nameof(umbracoVersion)); @@ -57,7 +58,7 @@ namespace Umbraco.Web.BackOffice.Controllers _runtimeMinifier = runtimeMinifier ?? throw new ArgumentNullException(nameof(runtimeMinifier)); _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); } @@ -87,14 +88,14 @@ namespace Umbraco.Web.BackOffice.Controllers var package = _packagingService.GetInstalledPackageById(packageId); if (package == null) return NotFound(); - var summary = _packagingService.UninstallPackage(package.Name, _webSecurity.GetUserId().ResultOr(0)); + var summary = _packagingService.UninstallPackage(package.Name, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); //now get all other packages by this name since we'll uninstall all versions foreach (var installed in _packagingService.GetAllInstalledPackages() .Where(x => x.Name == package.Name && x.Id != package.Id)) { //remove from the xml - _packagingService.DeleteInstalledPackage(installed.Id, _webSecurity.GetUserId().ResultOr(0)); + _packagingService.DeleteInstalledPackage(installed.Id, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); } } catch (Exception ex) @@ -223,7 +224,7 @@ namespace Umbraco.Web.BackOffice.Controllers var packageFile = await _packagingService.FetchPackageFileAsync( Guid.Parse(packageGuid), _umbracoVersion.Current, - _webSecurity.GetUserId().ResultOr(0)); + _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); fileName = packageFile.Name; } @@ -310,7 +311,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); var zipFile = new FileInfo(definition.PackagePath); - var installedFiles = _packagingService.InstallCompiledPackageFiles(definition, zipFile, _webSecurity.GetUserId().ResultOr(0)); + var installedFiles = _packagingService.InstallCompiledPackageFiles(definition, zipFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); //set a restarting marker and reset the app pool _umbracoApplicationLifetime.Restart(); @@ -342,7 +343,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); var zipFile = new FileInfo(definition.PackagePath); - var installSummary = _packagingService.InstallCompiledPackageData(definition, zipFile, _webSecurity.GetUserId().ResultOr(0)); + var installSummary = _packagingService.InstallCompiledPackageData(definition, zipFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return model; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs index 3878eb9b14..771ca28f55 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.WebAssets; using Umbraco.Extensions; @@ -32,8 +33,8 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly UmbracoFeatures _features; private readonly GlobalSettings _globalSettings; private readonly IPublishedSnapshotService _publishedSnapshotService; - private readonly IWebSecurity _webSecurity; - private readonly ILocalizationService _localizationService; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly ILocalizationService _localizationService; private readonly IHostingEnvironment _hostingEnvironment; private readonly ICookieManager _cookieManager; private readonly IRuntimeMinifier _runtimeMinifier; @@ -43,7 +44,7 @@ namespace Umbraco.Web.BackOffice.Controllers UmbracoFeatures features, IOptions globalSettings, IPublishedSnapshotService publishedSnapshotService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizationService localizationService, IHostingEnvironment hostingEnvironment, ICookieManager cookieManager, @@ -53,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers _features = features; _globalSettings = globalSettings.Value; _publishedSnapshotService = publishedSnapshotService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _localizationService = localizationService; _hostingEnvironment = hostingEnvironment; _cookieManager = cookieManager; @@ -107,7 +108,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize] public ActionResult Frame(int id, string culture) { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var previewToken = _publishedSnapshotService.EnterPreview(user, id); diff --git a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs index 7a4b18e807..c5a2108ced 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs @@ -15,6 +15,7 @@ using Umbraco.Web.Security; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; +using Umbraco.Core.Security; namespace Umbraco.Web.BackOffice.Controllers { @@ -23,15 +24,16 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly ILogger _logger; private readonly WebRoutingSettings _webRoutingSettings; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IRedirectUrlService _redirectUrlService; private readonly UmbracoMapper _umbracoMapper; private readonly IHostingEnvironment _hostingEnvironment; private readonly IConfigManipulator _configManipulator; - public RedirectUrlManagementController(ILogger logger, + public RedirectUrlManagementController( + ILogger logger, IOptions webRoutingSettings, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IRedirectUrlService redirectUrlService, UmbracoMapper umbracoMapper, IHostingEnvironment hostingEnvironment, @@ -39,7 +41,7 @@ namespace Umbraco.Web.BackOffice.Controllers { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _webRoutingSettings = webRoutingSettings.Value ?? throw new ArgumentNullException(nameof(webRoutingSettings)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _redirectUrlService = redirectUrlService ?? throw new ArgumentNullException(nameof(redirectUrlService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); @@ -54,7 +56,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult GetEnableState() { var enabled = _webRoutingSettings.DisableRedirectUrlTracking == false; - var userIsAdmin = _webSecurity.CurrentUser.IsAdmin(); + var userIsAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); return Ok(new { enabled, userIsAdmin }); } @@ -110,7 +112,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult ToggleUrlTracker(bool disable) { - var userIsAdmin = _webSecurity.CurrentUser.IsAdmin(); + var userIsAdmin = _backofficeSecurityAccessor.BackofficeSecurity.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.BackOffice/Controllers/SectionController.cs b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs index 5239994e04..810e3e5646 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc.Controllers; using Umbraco.Core; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Attributes; @@ -27,15 +28,15 @@ namespace Umbraco.Web.Editors private readonly ISectionService _sectionService; private readonly ITreeService _treeService; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public SectionController( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService, IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService, UmbracoMapper umbracoMapper, IControllerFactory controllerFactory) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _localizedTextService = localizedTextService; _dashboardService = dashboardService; _sectionService = sectionService; @@ -46,7 +47,7 @@ namespace Umbraco.Web.Editors public IEnumerable
GetSections() { - var sections = _sectionService.GetAllowedSections(_webSecurity.GetUserId().ResultOr(0)); + var sections = _sectionService.GetAllowedSections(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var sectionModels = sections.Select(_umbracoMapper.Map
).ToArray(); @@ -58,7 +59,7 @@ namespace Umbraco.Web.Editors ControllerContext = ControllerContext }; - var dashboards = _dashboardService.GetDashboards(_webSecurity.CurrentUser); + var dashboards = _dashboardService.GetDashboards(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); //now we can add metadata for each section so that the UI knows if there's actually anything at all to render for //a dashboard for a given section, then the UI can deal with it accordingly (i.e. redirect to the first tree) @@ -104,10 +105,10 @@ namespace Umbraco.Web.Editors { var sections = _sectionService.GetSections(); var mapped = sections.Select(_umbracoMapper.Map
); - if (_webSecurity.CurrentUser.IsAdmin()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin()) return mapped; - return mapped.Where(x => _webSecurity.CurrentUser.AllowedSections.Contains(x.Alias)).ToArray(); + return mapped.Where(x => _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.Contains(x.Alias)).ToArray(); } } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/TourController.cs b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs index 6e7af87a11..818b4edf66 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TourController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Models; @@ -21,21 +22,21 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly TourFilterCollection _filters; private readonly IHostingEnvironment _hostingEnvironment; private readonly TourSettings _tourSettings; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IContentTypeService _contentTypeService; public TourController( TourFilterCollection filters, IHostingEnvironment hostingEnvironment, IOptions tourSettings, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IContentTypeService contentTypeService) { _filters = filters; _hostingEnvironment = hostingEnvironment; _tourSettings = tourSettings.Value; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _contentTypeService = contentTypeService; } @@ -46,7 +47,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (_tourSettings.EnableTours == false) return result; - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return result; @@ -188,7 +189,7 @@ namespace Umbraco.Web.BackOffice.Controllers var backOfficeTours = tours.Where(x => aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false); - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var localizedTours = backOfficeTours.Where(x => string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(user.Language, diff --git a/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs b/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs index 16fcb5b38c..71dc97c835 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs @@ -10,6 +10,7 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Models; @@ -23,20 +24,20 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IUpgradeService _upgradeService; private readonly IUmbracoVersion _umbracoVersion; private readonly ICookieManager _cookieManager; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly GlobalSettings _globalSettings; public UpdateCheckController( IUpgradeService upgradeService, IUmbracoVersion umbracoVersion, ICookieManager cookieManager, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IOptions globalSettings) { _upgradeService = upgradeService ?? throw new ArgumentNullException(nameof(upgradeService)); _umbracoVersion = umbracoVersion ?? throw new ArgumentNullException(nameof(umbracoVersion)); _cookieManager = cookieManager ?? throw new ArgumentNullException(nameof(cookieManager)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); } @@ -45,7 +46,7 @@ namespace Umbraco.Web.BackOffice.Controllers { var updChkCookie = _cookieManager.GetCookieValue("UMB_UPDCHK"); var updateCheckCookie = updChkCookie ?? string.Empty; - if (_globalSettings.VersionCheckPeriod > 0 && string.IsNullOrEmpty(updateCheckCookie) && _webSecurity.CurrentUser.IsAdmin()) + if (_globalSettings.VersionCheckPeriod > 0 && string.IsNullOrEmpty(updateCheckCookie) && _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin()) { try { diff --git a/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs b/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs index 44b675771b..6d641c9cf9 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.BackOffice.Filters; @@ -27,13 +28,13 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IContentService _contentService; private readonly IEntityService _entityService; private readonly IMediaService _mediaService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly UmbracoMapper _umbracoMapper; private readonly ILocalizedTextService _localizedTextService; private readonly IShortStringHelper _shortStringHelper; public UserGroupsController(IUserService userService, IContentService contentService, - IEntityService entityService, IMediaService mediaService, IWebSecurity webSecurity, + IEntityService entityService, IMediaService mediaService, IBackofficeSecurityAccessor backofficeSecurityAccessor, UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) { @@ -41,7 +42,7 @@ namespace Umbraco.Web.BackOffice.Controllers _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); @@ -57,19 +58,19 @@ namespace Umbraco.Web.BackOffice.Controllers var authHelper = new UserGroupEditorAuthorizationHelper( _userService, _contentService, _mediaService, _entityService); - var isAuthorized = authHelper.AuthorizeGroupAccess(_webSecurity.CurrentUser, userGroupSave.Alias); + var isAuthorized = authHelper.AuthorizeGroupAccess(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, userGroupSave.Alias); if (isAuthorized == false) throw new HttpResponseException(HttpStatusCode.Unauthorized, isAuthorized.Result); //if sections were added we need to check that the current user has access to that section - isAuthorized = authHelper.AuthorizeSectionChanges(_webSecurity.CurrentUser, + isAuthorized = authHelper.AuthorizeSectionChanges(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, userGroupSave.PersistedUserGroup.AllowedSections, userGroupSave.Sections); if (isAuthorized == false) throw new HttpResponseException(HttpStatusCode.Unauthorized, isAuthorized.Result); //if start nodes were changed we need to check that the current user has access to them - isAuthorized = authHelper.AuthorizeStartNodeChanges(_webSecurity.CurrentUser, + isAuthorized = authHelper.AuthorizeStartNodeChanges(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, userGroupSave.PersistedUserGroup.StartContentId, userGroupSave.StartContentId, userGroupSave.PersistedUserGroup.StartMediaId, @@ -111,18 +112,18 @@ namespace Umbraco.Web.BackOffice.Controllers private void EnsureNonAdminUserIsInSavedUserGroup(UserGroupSave userGroupSave) { - if (_webSecurity.CurrentUser.IsAdmin()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin()) { return; } var userIds = userGroupSave.Users.ToList(); - if (userIds.Contains(_webSecurity.CurrentUser.Id)) + if (userIds.Contains(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id)) { return; } - userIds.Add(_webSecurity.CurrentUser.Id); + userIds.Add(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); userGroupSave.Users = userIds; } @@ -144,7 +145,7 @@ namespace Umbraco.Web.BackOffice.Controllers var allGroups = _umbracoMapper.MapEnumerable(_userService.GetAllUserGroups()) .ToList(); - var isAdmin = _webSecurity.CurrentUser.IsAdmin(); + var isAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); if (isAdmin) return allGroups; if (onlyCurrentUserGroups == false) @@ -155,7 +156,7 @@ namespace Umbraco.Web.BackOffice.Controllers } //we cannot return user groups that this user does not have access to - var currentUserGroups = _webSecurity.CurrentUser.Groups.Select(x => x.Alias).ToArray(); + var currentUserGroups = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Groups.Select(x => x.Alias).ToArray(); return allGroups.Where(x => currentUserGroups.Contains(x.Alias)).ToArray(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index 3cffa307eb..cfa1e980bd 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -24,8 +24,12 @@ using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; +using Umbraco.Web.Models; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.WebApi.Filters; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.ModelBinders; @@ -58,7 +62,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly SecuritySettings _securitySettings; private readonly IRequestAccessor _requestAccessor; private readonly IEmailSender _emailSender; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly AppCaches _appCaches; private readonly IShortStringHelper _shortStringHelper; private readonly IUserService _userService; @@ -81,7 +85,7 @@ namespace Umbraco.Web.BackOffice.Controllers IOptions securitySettings, IRequestAccessor requestAccessor, IEmailSender emailSender, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, AppCaches appCaches, IShortStringHelper shortStringHelper, IUserService userService, @@ -103,7 +107,7 @@ namespace Umbraco.Web.BackOffice.Controllers _securitySettings = securitySettings.Value; _requestAccessor = requestAccessor; _emailSender = emailSender; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _appCaches = appCaches; _shortStringHelper = shortStringHelper; _userService = userService; @@ -124,7 +128,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// public string[] GetCurrentUserAvatarUrls() { - var urls = _webSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + var urls = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); if (urls == null) throw new HttpResponseException(HttpStatusCode.BadRequest, "Could not access Gravatar endpoint"); @@ -290,7 +294,7 @@ namespace Umbraco.Web.BackOffice.Controllers var hideDisabledUsers = _securitySettings.HideDisabledUsersInBackoffice; var excludeUserGroups = new string[0]; - var isAdmin = _webSecurity.CurrentUser.IsAdmin(); + var isAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); if (isAdmin == false) { //this user is not an admin so in that case we need to exclude all admin users @@ -299,7 +303,7 @@ namespace Umbraco.Web.BackOffice.Controllers var filterQuery = _sqlContext.Query(); - if (!_webSecurity.CurrentUser.IsSuper()) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsSuper()) { // only super can see super - but don't use IsSuper, cannot be mapped to SQL //filterQuery.Where(x => !x.IsSuper()); @@ -360,7 +364,7 @@ namespace Umbraco.Web.BackOffice.Controllers //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(_contentService,_mediaService, _userService, _entityService); - var canSaveUser = authHelper.IsAuthorized(_webSecurity.CurrentUser, null, null, null, userSave.UserGroups); + var canSaveUser = authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, null, null, null, userSave.UserGroups); if (canSaveUser == false) { throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result); @@ -444,7 +448,7 @@ namespace Umbraco.Web.BackOffice.Controllers //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(_contentService,_mediaService, _userService, _entityService); - var canSaveUser = authHelper.IsAuthorized(_webSecurity.CurrentUser, user, null, null, userSave.UserGroups); + var canSaveUser = authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, user, null, null, userSave.UserGroups); if (canSaveUser == false) { throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result); @@ -479,7 +483,7 @@ namespace Umbraco.Web.BackOffice.Controllers //send the email - await SendUserInviteEmailAsync(display, _webSecurity.CurrentUser.Name, _webSecurity.CurrentUser.Email, user, userSave.Message); + await SendUserInviteEmailAsync(display, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Email, user, userSave.Message); display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles/resendInviteHeader"), _localizedTextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name })); @@ -575,7 +579,7 @@ namespace Umbraco.Web.BackOffice.Controllers //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(_contentService,_mediaService, _userService, _entityService); - var canSaveUser = authHelper.IsAuthorized(_webSecurity.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups); + var canSaveUser = authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups); if (canSaveUser == false) { throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result); @@ -658,7 +662,7 @@ namespace Umbraco.Web.BackOffice.Controllers } var passwordChanger = new PasswordChanger(_logger); - var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_webSecurity.CurrentUser, found, changingPasswordModel, _backOfficeUserManager); + var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, found, changingPasswordModel, _backOfficeUserManager); if (passwordChangeResult.Success) { @@ -683,7 +687,7 @@ namespace Umbraco.Web.BackOffice.Controllers [AdminUsersAuthorize("userIds")] public IActionResult PostDisableUsers([FromQuery]int[] userIds) { - var tryGetCurrentUserId = _webSecurity.GetUserId(); + var tryGetCurrentUserId = _backofficeSecurityAccessor.BackofficeSecurity.GetUserId(); if (tryGetCurrentUserId && userIds.Contains(tryGetCurrentUserId.Result)) { throw HttpResponseException.CreateNotificationValidationErrorResponse("The current user cannot disable itself"); diff --git a/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs index 526504b04d..4920b6351a 100644 --- a/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Editors; using Umbraco.Web.Security; @@ -34,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IContentService _contentService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public AdminUsersAuthorizeFilter( IRequestAccessor requestAccessor, @@ -42,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Filters IContentService contentService, IMediaService mediaService, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, string parameterName) { _requestAccessor = requestAccessor; @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters _contentService = contentService; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _parameterName = parameterName; } @@ -86,7 +87,7 @@ namespace Umbraco.Web.BackOffice.Filters var users = _userService.GetUsersById(userIds); var authHelper = new UserEditorAuthorizationHelper(_contentService, _mediaService, _userService, _entityService); - return users.All(user => authHelper.IsAuthorized(_webSecurity.CurrentUser, user, null, null, null) != false); + return users.All(user => authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, user, null, null, null) != false); } } diff --git a/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs index 6541d122ab..c484de3bfb 100644 --- a/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs @@ -43,8 +43,8 @@ namespace Umbraco.Web.BackOffice.Filters throw new InvalidOperationException($"No argument found for the current action with the name: {_userIdParameter}"); } - var webSecurity = context.HttpContext.RequestServices.GetService(); - var user = webSecurity.CurrentUser; + var backofficeSecurity = context.HttpContext.RequestServices.GetService(); + var user = backofficeSecurity.CurrentUser; if (user == null) { return; diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs index 71323b1659..eee5cb6d30 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs @@ -22,14 +22,14 @@ namespace Umbraco.Web.BackOffice.Filters internal abstract class ContentModelValidator { - protected IWebSecurity WebSecurity { get; } + protected IBackofficeSecurity BackofficeSecurity { get; } public IPropertyValidationService PropertyValidationService { get; } protected ILogger Logger { get; } - protected ContentModelValidator(ILogger logger, IWebSecurity webSecurity, IPropertyValidationService propertyValidationService) + protected ContentModelValidator(ILogger logger, IBackofficeSecurity backofficeSecurity, IPropertyValidationService propertyValidationService) { Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - WebSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + BackofficeSecurity = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity)); PropertyValidationService = propertyValidationService ?? throw new ArgumentNullException(nameof(propertyValidationService)); } } @@ -53,10 +53,10 @@ namespace Umbraco.Web.BackOffice.Filters protected ContentModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, propertyValidationService) + : base(logger, backofficeSecurity, propertyValidationService) { _textService = textService ?? throw new ArgumentNullException(nameof(textService)); } diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs index 493b2e04ea..a73b20dca5 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs @@ -13,10 +13,10 @@ namespace Umbraco.Web.BackOffice.Filters { public ContentSaveModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, textService, propertyValidationService) + : base(logger, backofficeSecurity, textService, propertyValidationService) { } diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs index 216f94499b..457929690f 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs @@ -35,12 +35,12 @@ namespace Umbraco.Web.BackOffice.Filters private readonly ILogger _logger; private readonly ILocalizedTextService _textService; private readonly IUserService _userService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public ContentSaveValidationFilter( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, @@ -48,7 +48,7 @@ namespace Umbraco.Web.BackOffice.Filters IPropertyValidationService propertyValidationService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); @@ -59,11 +59,11 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { var model = (ContentItemSave) context.ActionArguments["contentItem"]; - var contentItemValidator = new ContentSaveModelValidator(_logger, _webSecurity, _textService, _propertyValidationService); + var contentItemValidator = new ContentSaveModelValidator(_logger, _backofficeSecurityAccessor.BackofficeSecurity, _textService, _propertyValidationService); if (!ValidateAtLeastOneVariantIsBeingSaved(model, context)) return; if (!contentItemValidator.ValidateExistingContent(model, context)) return; - if (!ValidateUserAccess(model, context, _webSecurity)) return; + if (!ValidateUserAccess(model, context, _backofficeSecurityAccessor.BackofficeSecurity)) return; //validate for each variant that is being updated foreach (var variant in model.Variants.Where(x => x.Save)) @@ -101,9 +101,9 @@ namespace Umbraco.Web.BackOffice.Filters ///
/// /// - /// + /// private bool ValidateUserAccess(ContentItemSave contentItem, ActionExecutingContext actionContext, - IWebSecurity webSecurity) + IBackofficeSecurity backofficeSecurity) { // We now need to validate that the user is allowed to be doing what they are doing. // Based on the action we need to check different permissions. @@ -217,13 +217,13 @@ namespace Umbraco.Web.BackOffice.Filters actionContext.HttpContext.Items[typeof(IContent).ToString()] = contentItem; accessResult = ContentPermissionsHelper.CheckPermissions( - contentToCheck, webSecurity.CurrentUser, + contentToCheck, backofficeSecurity.CurrentUser, _userService, _entityService, permissionToCheck.ToArray()); } else { accessResult = ContentPermissionsHelper.CheckPermissions( - contentIdToCheck, webSecurity.CurrentUser, + contentIdToCheck, backofficeSecurity.CurrentUser, _userService, _contentService, _entityService, out contentToCheck, permissionToCheck.ToArray()); diff --git a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs index 131854808e..1c271d93e6 100644 --- a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs @@ -75,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Filters private sealed class EnsureUserPermissionForContentFilter : IActionFilter { private readonly int? _nodeId; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IUserService _userService; private readonly IContentService _contentService; @@ -83,58 +83,58 @@ namespace Umbraco.Web.BackOffice.Filters private readonly char? _permissionToCheck; public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, string paramName) - :this(webSecurity, entityService, userService, contentService, null, paramName, ActionBrowse.ActionLetter) + :this(backofficeSecurityAccessor, entityService, userService, contentService, null, paramName, ActionBrowse.ActionLetter) { } public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, int nodeId, char permissionToCheck) - :this(webSecurity, entityService, userService, contentService, nodeId, null, permissionToCheck) + :this(backofficeSecurityAccessor, entityService, userService, contentService, nodeId, null, permissionToCheck) { } public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, int nodeId) - :this(webSecurity, entityService, userService, contentService, nodeId, null, null) + :this(backofficeSecurityAccessor, entityService, userService, contentService, nodeId, null, null) { } public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, string paramName, char permissionToCheck) - :this(webSecurity, entityService, userService, contentService, null, paramName, permissionToCheck) + :this(backofficeSecurityAccessor, entityService, userService, contentService, null, paramName, permissionToCheck) { } private EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, int? nodeId, string paramName, char? permissionToCheck) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -156,7 +156,7 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { - if (_webSecurity.CurrentUser == null) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser == null) { //not logged in throw new HttpResponseException(HttpStatusCode.Unauthorized); @@ -213,7 +213,7 @@ namespace Umbraco.Web.BackOffice.Filters } var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId, - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _userService, _contentService, _entityService, diff --git a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs index 526e95cf96..3bf3bd8730 100644 --- a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Exceptions; @@ -40,7 +41,7 @@ namespace Umbraco.Web.WebApi.Filters { private readonly int? _nodeId; private readonly string _paramName; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IMediaService _mediaService; @@ -48,21 +49,21 @@ namespace Umbraco.Web.WebApi.Filters /// This constructor will only be able to test the start node access ///
public EnsureUserPermissionForMediaFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IMediaService mediaService, int nodeId) - :this(webSecurity, entityService, mediaService, nodeId, null) + :this(backofficeSecurityAccessor, entityService, mediaService, nodeId, null) { _nodeId = nodeId; } public EnsureUserPermissionForMediaFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IMediaService mediaService, string paramName) - :this(webSecurity, entityService, mediaService,null, paramName) + :this(backofficeSecurityAccessor, entityService, mediaService,null, paramName) { if (paramName == null) throw new ArgumentNullException(nameof(paramName)); if (string.IsNullOrEmpty(paramName)) @@ -70,12 +71,12 @@ namespace Umbraco.Web.WebApi.Filters } private EnsureUserPermissionForMediaFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IMediaService mediaService, int? nodeId, string paramName) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); @@ -117,7 +118,7 @@ namespace Umbraco.Web.WebApi.Filters public void OnActionExecuting(ActionExecutingContext context) { - if (_webSecurity.CurrentUser == null) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser == null) { throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized); } @@ -158,7 +159,7 @@ namespace Umbraco.Web.WebApi.Filters if (MediaController.CheckPermissions( context.HttpContext.Items, - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _mediaService, _entityService, nodeId)) diff --git a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs index 855cd05829..c67bbefd89 100644 --- a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Actions; using Umbraco.Web.Security; @@ -60,8 +61,8 @@ namespace Umbraco.Web.BackOffice.Filters - public FilterAllowedOutgoingContentFilter(Type outgoingType, string propertyName, char permissionToCheck, IUserService userService, IEntityService entityService, IWebSecurity webSecurity) - : base(entityService, webSecurity, outgoingType, propertyName) + public FilterAllowedOutgoingContentFilter(Type outgoingType, string propertyName, char permissionToCheck, IUserService userService, IEntityService entityService, IBackofficeSecurityAccessor backofficeSecurityAccessor) + : base(entityService, backofficeSecurityAccessor, outgoingType, propertyName) { _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); diff --git a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs index a600f5a928..a6325e0650 100644 --- a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs @@ -34,13 +34,13 @@ namespace Umbraco.Web.WebApi.Filters { private readonly Type _outgoingType; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly string _propertyName; - public FilterAllowedOutgoingMediaFilter(IEntityService entityService, IWebSecurity webSecurity, Type outgoingType, string propertyName) + public FilterAllowedOutgoingMediaFilter(IEntityService entityService, IBackofficeSecurityAccessor backofficeSecurityAccessor, Type outgoingType, string propertyName) { _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _propertyName = propertyName; _outgoingType = outgoingType; @@ -57,7 +57,7 @@ namespace Umbraco.Web.WebApi.Filters { if (context.Result == null) return; - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return; var objectContent = context.Result as ObjectResult; diff --git a/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs index 521dd34d77..380995db4d 100644 --- a/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Umbraco.Core.Security; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; @@ -15,11 +16,11 @@ namespace Umbraco.Web.BackOffice.Filters private class IsCurrentUserModelFilter : IActionFilter { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; - public IsCurrentUserModelFilter(IWebSecurity webSecurity) + public IsCurrentUserModelFilter(IBackofficeSecurityAccessor backofficeSecurityAccessor) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; } @@ -27,7 +28,7 @@ namespace Umbraco.Web.BackOffice.Filters { if (context.Result == null) return; - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return; var objectContent = context.Result as ObjectResult; diff --git a/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs index a81f4d329a..ee89a8e2fd 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Models.ContentEditing; @@ -29,18 +30,18 @@ namespace Umbraco.Web.BackOffice.Filters private readonly ILogger _logger; private readonly IMediaService _mediaService; private readonly ILocalizedTextService _textService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaItemSaveValidationFilter( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IMediaService mediaService, IEntityService entityService, IPropertyValidationService propertyValidationService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { var model = (MediaItemSave) context.ActionArguments["contentItem"]; - var contentItemValidator = new MediaSaveModelValidator(_logger, _webSecurity, _textService, _propertyValidationService); + var contentItemValidator = new MediaSaveModelValidator(_logger, _backofficeSecurityAccessor.BackofficeSecurity, _textService, _propertyValidationService); if (ValidateUserAccess(model, context)) { @@ -101,7 +102,7 @@ namespace Umbraco.Web.BackOffice.Filters if (MediaController.CheckPermissions( actionContext.HttpContext.Items, - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _mediaService, _entityService, contentIdToCheck, contentToCheck) == false) { diff --git a/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs index 4dd9e6592c..7eaf0cb60f 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs @@ -13,10 +13,10 @@ namespace Umbraco.Web.BackOffice.Filters { public MediaSaveModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, textService, propertyValidationService) + : base(logger, backofficeSecurity, textService, propertyValidationService) { } } diff --git a/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs index 208f0eeb07..9ca7cc4f31 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs @@ -26,13 +26,13 @@ namespace Umbraco.Web.BackOffice.Filters public MemberSaveModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IMemberTypeService memberTypeService, IMemberService memberService, IShortStringHelper shortStringHelper, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, textService, propertyValidationService) + : base(logger, backofficeSecurity, textService, propertyValidationService) { _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); @@ -96,7 +96,7 @@ namespace Umbraco.Web.BackOffice.Filters //if the user doesn't have access to sensitive values, then we need to validate the incoming properties to check //if a sensitive value is being submitted. - if (WebSecurity.CurrentUser.HasAccessToSensitiveData() == false) + if (BackofficeSecurity.CurrentUser.HasAccessToSensitiveData() == false) { var contentType = _memberTypeService.Get(model.PersistedContent.ContentTypeId); var sensitiveProperties = contentType diff --git a/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs index e6f6edb2e3..bfa03264c3 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; @@ -22,7 +23,7 @@ namespace Umbraco.Web.BackOffice.Filters private sealed class MemberSaveValidationFilter : IActionFilter { private readonly ILogger _logger; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _textService; private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; @@ -31,7 +32,7 @@ namespace Umbraco.Web.BackOffice.Filters public MemberSaveValidationFilter( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IMemberTypeService memberTypeService, IMemberService memberService, @@ -39,7 +40,7 @@ namespace Umbraco.Web.BackOffice.Filters IPropertyValidationService propertyValidationService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { var model = (MemberSave)context.ActionArguments["contentItem"]; - var contentItemValidator = new MemberSaveModelValidator(_logger, _webSecurity, _textService, _memberTypeService, _memberService, _shortStringHelper, _propertyValidationService); + var contentItemValidator = new MemberSaveModelValidator(_logger, _backofficeSecurityAccessor.BackofficeSecurity, _textService, _memberTypeService, _memberService, _shortStringHelper, _propertyValidationService); //now do each validation step if (contentItemValidator.ValidateExistingContent(model, context)) if (contentItemValidator.ValidateProperties(model, model, context)) diff --git a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs index d433ba9886..9952eb52f9 100644 --- a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Web.Editors; using Umbraco.Web.Security; @@ -13,12 +14,12 @@ namespace Umbraco.Web.WebApi.Filters internal sealed class OutgoingEditorModelEventAttribute : ActionFilterAttribute { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; - public OutgoingEditorModelEventAttribute(IUmbracoContextAccessor umbracoContextAccessor, IWebSecurity webSecurity) + public OutgoingEditorModelEventAttribute(IUmbracoContextAccessor umbracoContextAccessor, IBackofficeSecurityAccessor backofficeSecurityAccessor) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } public override void OnActionExecuted(ActionExecutedContext context) @@ -26,7 +27,7 @@ namespace Umbraco.Web.WebApi.Filters if (context.Result == null) return; var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return; if (context.Result is ObjectResult objectContent) diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs index 4465436e77..3850682cf2 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Umbraco.Core.Security; using Umbraco.Web.Security; namespace Umbraco.Web.BackOffice.Filters @@ -22,19 +23,19 @@ namespace Umbraco.Web.BackOffice.Filters ///
internal static bool Enable = true; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly string[] _appNames; /// /// Constructor to set any number of applications that the user needs access to be authorized /// - /// + /// /// /// If the user has access to any of the specified apps, they will be authorized. /// - public UmbracoApplicationAuthorizeFilter(IWebSecurity webSecurity, params string[] appName) + public UmbracoApplicationAuthorizeFilter(IBackofficeSecurityAccessor backofficeSecurityAccessor, params string[] appName) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _appNames = appName; } @@ -54,9 +55,9 @@ namespace Umbraco.Web.BackOffice.Filters return true; } - var authorized = _webSecurity.CurrentUser != null - && _appNames.Any(app => _webSecurity.UserHasSectionAccess( - app, _webSecurity.CurrentUser)); + var authorized = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null + && _appNames.Any(app => _backofficeSecurityAccessor.BackofficeSecurity.UserHasSectionAccess( + app, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser)); return authorized; } diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs index d4ec1b45e1..5f6e00e82e 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Web.Security; using Umbraco.Web.Services; @@ -34,22 +35,22 @@ namespace Umbraco.Web.BackOffice.Filters private readonly string[] _treeAliases; private readonly ITreeService _treeService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; /// /// Constructor to set authorization to be based on a tree alias for which application security will be applied /// - /// + /// + /// /// /// If the user has access to the application that the treeAlias is specified in, they will be authorized. /// Multiple trees may be specified. /// - /// - public UmbracoTreeAuthorizeFilter(ITreeService treeService, IWebSecurity webSecurity, + public UmbracoTreeAuthorizeFilter(ITreeService treeService, IBackofficeSecurityAccessor backofficeSecurityAccessor, params string[] treeAliases) { _treeService = treeService ?? throw new ArgumentNullException(nameof(treeService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _treeAliases = treeAliases; } @@ -75,9 +76,9 @@ namespace Umbraco.Web.BackOffice.Filters .Distinct() .ToArray(); - return _webSecurity.CurrentUser != null - && apps.Any(app => _webSecurity.UserHasSectionAccess( - app, _webSecurity.CurrentUser)); + return _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null + && apps.Any(app => _backofficeSecurityAccessor.BackofficeSecurity.UserHasSectionAccess( + app, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser)); } } } diff --git a/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs index b0175fe6ec..d867cc90bc 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Security; @@ -34,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IContentService _contentService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public UserGroupAuthorizationFilter( IRequestAccessor requestAccessor, @@ -42,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Filters IContentService contentService, IMediaService mediaService, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, string parameterName) { _requestAccessor = requestAccessor; @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters _contentService = contentService; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _parameterName = parameterName; } @@ -64,7 +65,7 @@ namespace Umbraco.Web.BackOffice.Filters private bool IsAuthorized(AuthorizationFilterContext actionContext) { - var currentUser = _webSecurity.CurrentUser; + var currentUser = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var queryString = actionContext.HttpContext.Request.Query; diff --git a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs index c9bcf01fad..6253aa1ff4 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs @@ -1,4 +1,5 @@ -using System; + +using System; using System.Collections.Generic; using System.Linq; using System.Net; diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 44c83e3009..10fbdea0b6 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -13,6 +13,7 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Search; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Constants = Umbraco.Core.Constants; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Trees; @@ -44,7 +45,7 @@ namespace Umbraco.Web.Trees private readonly ActionCollection _actions; private readonly GlobalSettings _globalSettings; private readonly IMenuItemCollectionFactory _menuItemCollectionFactory; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IContentService _contentService; private readonly IEntityService _entityService; private readonly IPublicAccessService _publicAccessService; @@ -56,7 +57,7 @@ namespace Umbraco.Web.Trees UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, ActionCollection actionCollection, IUserService userService, @@ -67,13 +68,13 @@ namespace Umbraco.Web.Trees IContentService contentService, IPublicAccessService publicAccessService, ILocalizationService localizationService) - : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, webSecurity, logger, actionCollection, userService, dataTypeService) + : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, backofficeSecurityAccessor, logger, actionCollection, userService, dataTypeService) { _treeSearcher = treeSearcher; _actions = actions; _globalSettings = globalSettings.Value; _menuItemCollectionFactory = menuItemCollectionFactory; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _contentService = contentService; _entityService = entityService; _publicAccessService = publicAccessService; @@ -88,7 +89,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes - => _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService)); + => _userStartNodes ?? (_userStartNodes = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService)); @@ -166,7 +167,7 @@ namespace Umbraco.Web.Trees menu.DefaultMenuAlias = ActionNew.ActionAlias; // we need to get the default permissions as you can't set permissions on the very root node - var permission = _userService.GetPermissions(_webSecurity.CurrentUser, Constants.System.Root).First(); + var permission = _userService.GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, Constants.System.Root).First(); var nodeActions = _actions.FromEntityPermission(permission) .Select(x => new MenuItem(x)); @@ -202,7 +203,7 @@ namespace Umbraco.Web.Trees } //if the user has no path access for this node, all they can do is refresh - if (!_webSecurity.CurrentUser.HasContentPathAccess(item, _entityService)) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasContentPathAccess(item, _entityService)) { var menu = _menuItemCollectionFactory.Create(); menu.Items.Add(new RefreshNode(LocalizedTextService, true)); diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs index 8e05cb874e..ef2f4c2899 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Trees public abstract class ContentTreeControllerBase : TreeController, ITreeNodeController { private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILogger _logger; private readonly ActionCollection _actionCollection; private readonly IUserService _userService; @@ -38,7 +38,7 @@ namespace Umbraco.Web.Trees UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, ActionCollection actionCollection, IUserService userService, @@ -47,7 +47,7 @@ namespace Umbraco.Web.Trees : base(localizedTextService, umbracoApiControllerTypeCollection) { _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _logger = logger; _actionCollection = actionCollection; _userService = userService; @@ -147,12 +147,12 @@ namespace Umbraco.Web.Trees switch (RecycleBinId) { case Constants.System.RecycleBinMedia: - startNodeIds = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); - startNodePaths = _webSecurity.CurrentUser.GetMediaStartNodePaths(_entityService); + startNodeIds = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); + startNodePaths = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetMediaStartNodePaths(_entityService); break; case Constants.System.RecycleBinContent: - startNodeIds = _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); - startNodePaths = _webSecurity.CurrentUser.GetContentStartNodePaths(_entityService); + startNodeIds = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); + startNodePaths = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetContentStartNodePaths(_entityService); break; default: throw new NotSupportedException("Path access is only determined on content or media"); @@ -196,7 +196,7 @@ namespace Umbraco.Web.Trees // TODO: in the future we could return a validation statement so we can have some UI to notify the user they don't have access if (ignoreUserStartNodes == false && HasPathAccess(id, queryStrings) == false) { - _logger.Warn("User {Username} does not have access to node with id {Id}", _webSecurity.CurrentUser.Username, id); + _logger.Warn("User {Username} does not have access to node with id {Id}", _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Username, id); return nodes; } @@ -312,8 +312,8 @@ namespace Umbraco.Web.Trees { if (entity == null) return false; return RecycleBinId == Constants.System.RecycleBinContent - ? _webSecurity.CurrentUser.HasContentPathAccess(entity, _entityService) - : _webSecurity.CurrentUser.HasMediaPathAccess(entity, _entityService); + ? _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasContentPathAccess(entity, _entityService) + : _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasMediaPathAccess(entity, _entityService); } /// @@ -441,7 +441,7 @@ namespace Umbraco.Web.Trees var deleteAction = _actionCollection.FirstOrDefault(y => y.Letter == ActionDelete.ActionLetter); if (deleteAction != null) { - var perms = _webSecurity.CurrentUser.GetPermissions(Constants.System.RecycleBinContentString, _userService); + var perms = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetPermissions(Constants.System.RecycleBinContentString, _userService); deleteAllowed = perms.FirstOrDefault(x => x.Contains(deleteAction.Letter)) != null; } @@ -492,7 +492,7 @@ namespace Umbraco.Web.Trees internal IEnumerable GetAllowedUserMenuItemsForNode(IUmbracoEntity dd) { - var permissionsForPath = _userService.GetPermissionsForPath(_webSecurity.CurrentUser, dd.Path).GetAllPermissions(); + var permissionsForPath = _userService.GetPermissionsForPath(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, dd.Path).GetAllPermissions(); return _actionCollection.GetByLetters(permissionsForPath).Select(x => new MenuItem(x)); } diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index 46ef45e85d..2a7f769c7b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -12,6 +12,7 @@ using Umbraco.Web.Models.Trees; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Search; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Constants = Umbraco.Core.Constants; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Trees; @@ -39,26 +40,26 @@ namespace Umbraco.Web.Trees private readonly UmbracoTreeSearcher _treeSearcher; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaTreeController( ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, ActionCollection actionCollection, IUserService userService, IDataTypeService dataTypeService, UmbracoTreeSearcher treeSearcher, IMediaService mediaService) - : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, webSecurity, logger, actionCollection, userService, dataTypeService) + : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, backofficeSecurityAccessor, logger, actionCollection, userService, dataTypeService) { _treeSearcher = treeSearcher; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; } protected override int RecycleBinId => Constants.System.RecycleBinMedia; @@ -67,7 +68,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes - => _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); + => _userStartNodes ?? (_userStartNodes = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); /// /// Creates a tree node for a content item based on an UmbracoEntity @@ -134,7 +135,7 @@ namespace Umbraco.Web.Trees } //if the user has no path access for this node, all they can do is refresh - if (!_webSecurity.CurrentUser.HasMediaPathAccess(item, _entityService)) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasMediaPathAccess(item, _entityService)) { menu.Items.Add(new RefreshNode(LocalizedTextService, true)); return menu; diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs index 967e4f22fc..859ee2f846 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Extensions; using Umbraco.Web.Actions; @@ -37,7 +38,7 @@ namespace Umbraco.Web.Trees private readonly IMenuItemCollectionFactory _menuItemCollectionFactory; private readonly IMemberService _memberService; private readonly IMemberTypeService _memberTypeService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MemberTreeController( ILocalizedTextService localizedTextService, @@ -46,14 +47,14 @@ namespace Umbraco.Web.Trees IMenuItemCollectionFactory menuItemCollectionFactory, IMemberService memberService, IMemberTypeService memberTypeService, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) : base(localizedTextService, umbracoApiControllerTypeCollection) { _treeSearcher = treeSearcher; _menuItemCollectionFactory = menuItemCollectionFactory; _memberService = memberService; _memberTypeService = memberTypeService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; } /// @@ -145,7 +146,7 @@ namespace Umbraco.Web.Trees //add delete option for all members menu.Items.Add(LocalizedTextService, opensDialog: true); - if (_webSecurity.CurrentUser.HasAccessToSensitiveData()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData()) { menu.Items.Add(new ExportMember(LocalizedTextService)); } diff --git a/src/Umbraco.Web.Common/Install/InstallController.cs b/src/Umbraco.Web.Common/Install/InstallController.cs index 306a376533..026f604d50 100644 --- a/src/Umbraco.Web.Common/Install/InstallController.cs +++ b/src/Umbraco.Web.Common/Install/InstallController.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Core.WebAssets; using Umbraco.Extensions; using Umbraco.Web.Common.Filters; @@ -25,7 +26,7 @@ namespace Umbraco.Web.Common.Install [Area(Umbraco.Core.Constants.Web.Mvc.InstallArea)] public class InstallController : Controller { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly InstallHelper _installHelper; private readonly IRuntimeState _runtime; private readonly GlobalSettings _globalSettings; @@ -36,7 +37,7 @@ namespace Umbraco.Web.Common.Install private readonly IRuntimeMinifier _runtimeMinifier; public InstallController( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, InstallHelper installHelper, IRuntimeState runtime, IOptions globalSettings, @@ -46,7 +47,7 @@ namespace Umbraco.Web.Common.Install ILogger logger, LinkGenerator linkGenerator) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _installHelper = installHelper; _runtime = runtime; _globalSettings = globalSettings.Value; @@ -72,7 +73,7 @@ namespace Umbraco.Web.Common.Install // Update ClientDependency version and delete its temp directories to make sure we get fresh caches _runtimeMinifier.Reset(); - var result = _webSecurity.ValidateCurrentUser(false); + var result = _backofficeSecurityAccessor.BackofficeSecurity.ValidateCurrentUser(false); switch (result) { diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index 587a60caa9..f5b8d74402 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Logging; using System.Threading; using Umbraco.Core.Cache; using System.Collections.Generic; +using Umbraco.Core.Security; namespace Umbraco.Web.Common.Middleware { @@ -24,17 +25,20 @@ namespace Umbraco.Web.Common.Middleware private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager; private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly IRequestCache _requestCache; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; public UmbracoRequestMiddleware( ILogger logger, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager, IUmbracoContextFactory umbracoContextFactory, - IRequestCache requestCache) + IRequestCache requestCache, + IBackofficeSecurityFactory backofficeSecurityFactory) { _logger = logger; _umbracoRequestLifetimeManager = umbracoRequestLifetimeManager; _umbracoContextFactory = umbracoContextFactory; _requestCache = requestCache; + _backofficeSecurityFactory = backofficeSecurityFactory; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) @@ -47,13 +51,14 @@ namespace Umbraco.Web.Common.Middleware await next(context); return; } - + _backofficeSecurityFactory.EnsureBackofficeSecurity(); // Needs to be before UmbracoContext var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); + try { if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) - { + { LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); _logger.Verbose("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri); } diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 67755da5ea..58b7fc16b5 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -75,7 +75,8 @@ namespace Umbraco.Web.Common.Runtime // register the umbraco context factory composition.RegisterUnique(); - composition.RegisterUnique(); + composition.RegisterUnique(); + composition.RegisterUnique(); //register the install components //NOTE: i tried to not have these registered if we weren't installing or upgrading but post install when the site restarts diff --git a/src/Umbraco.Web.Common/Security/WebSecurity.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs similarity index 98% rename from src/Umbraco.Web.Common/Security/WebSecurity.cs rename to src/Umbraco.Web.Common/Security/BackofficeSecurity.cs index b822adf656..6587501be7 100644 --- a/src/Umbraco.Web.Common/Security/WebSecurity.cs +++ b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs @@ -13,14 +13,15 @@ using Umbraco.Web.Security; namespace Umbraco.Web.Common.Security { - public class WebSecurity : IWebSecurity + + public class BackofficeSecurity : IBackofficeSecurity { private readonly IUserService _userService; private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IHttpContextAccessor _httpContextAccessor; - public WebSecurity( + public BackofficeSecurity( IUserService userService, IOptions globalSettings, IHostingEnvironment hostingEnvironment, diff --git a/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs new file mode 100644 index 0000000000..7718981b27 --- /dev/null +++ b/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Core.Security; +using Umbraco.Core.Services; + +namespace Umbraco.Web.Common.Security +{ + public class BackofficeSecurityFactory: IBackofficeSecurityFactory + { + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly IUserService _userService; + private readonly IOptions _globalSettings; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IHttpContextAccessor _httpContextAccessor; + + public BackofficeSecurityFactory( + IBackofficeSecurityAccessor backofficeSecurityAccessor, + IUserService userService, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IHttpContextAccessor httpContextAccessor) + { + _backofficeSecurityAccessor = backofficeSecurityAccessor; + _userService = userService; + _globalSettings = globalSettings; + _hostingEnvironment = hostingEnvironment; + _httpContextAccessor = httpContextAccessor; + } + + public void EnsureBackofficeSecurity() + { + if (_backofficeSecurityAccessor.BackofficeSecurity is null) + { + _backofficeSecurityAccessor.BackofficeSecurity = new BackofficeSecurity(_userService, _globalSettings, _hostingEnvironment, _httpContextAccessor); + } + + } + } +} diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs index b255013b7f..6b4ce706e3 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs @@ -31,7 +31,7 @@ namespace Umbraco.Web // warn: does *not* manage setting any IUmbracoContextAccessor internal UmbracoContext( IPublishedSnapshotService publishedSnapshotService, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IVariationContextAccessor variationContextAccessor, @@ -40,7 +40,7 @@ namespace Umbraco.Web IRequestAccessor requestAccessor) { if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); + if (backofficeSecurity == null) throw new ArgumentNullException(nameof(backofficeSecurity)); VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); _hostingEnvironment = hostingEnvironment; @@ -49,7 +49,7 @@ namespace Umbraco.Web ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - Security = webSecurity; + Security = backofficeSecurity; // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); @@ -78,9 +78,9 @@ namespace Umbraco.Web public Guid UmbracoRequestId { get; } /// - /// Gets the WebSecurity class + /// Gets the BackofficeSecurity class /// - public IWebSecurity Security { get; } + public IBackofficeSecurity Security { get; } /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs index d9df11e4a9..a31ef614cf 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Common.Security; using Umbraco.Web.PublishedCache; @@ -30,7 +31,7 @@ namespace Umbraco.Web private readonly IHttpContextAccessor _httpContextAccessor; private readonly ICookieManager _cookieManager; private readonly IRequestAccessor _requestAccessor; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly UriUtility _uriUtility; /// @@ -48,7 +49,7 @@ namespace Umbraco.Web IHttpContextAccessor httpContextAccessor, ICookieManager cookieManager, IRequestAccessor requestAccessor, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService)); @@ -61,7 +62,7 @@ namespace Umbraco.Web _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); _cookieManager = cookieManager ?? throw new ArgumentNullException(nameof(cookieManager)); _requestAccessor = requestAccessor ?? throw new ArgumentNullException(nameof(requestAccessor)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } private IUmbracoContext CreateUmbracoContext() @@ -79,7 +80,7 @@ namespace Umbraco.Web return new UmbracoContext( _publishedSnapshotService, - _webSecurity, + _backofficeSecurityAccessor.BackofficeSecurity, _globalSettings, _hostingEnvironment, _variationContextAccessor, diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs index 64a9e56014..6148535d46 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs @@ -3,6 +3,7 @@ using System.Web; using System.Web.Mvc; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Security; using Umbraco.Core.Configuration.Models; using Umbraco.Web.Composing; using Umbraco.Web.Security; @@ -14,22 +15,22 @@ namespace Umbraco.Web.Mvc public sealed class UmbracoAuthorizeAttribute : AuthorizeAttribute { // see note in HttpInstallAuthorizeAttribute - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IRuntimeState _runtimeState; private readonly string _redirectUrl; private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState; - private IWebSecurity WebSecurity => _webSecurity ?? Current.UmbracoContext.Security; + private IBackofficeSecurity BackofficeSecurity => _backofficeSecurityAccessor.BackofficeSecurity ?? Current.UmbracoContext.Security; /// /// THIS SHOULD BE ONLY USED FOR UNIT TESTS /// - /// + /// /// - public UmbracoAuthorizeAttribute(IWebSecurity webSecurity, IRuntimeState runtimeState) + public UmbracoAuthorizeAttribute(IBackofficeSecurityAccessor backofficeSecurityAccessor, IRuntimeState runtimeState) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); } @@ -75,7 +76,7 @@ namespace Umbraco.Web.Mvc // otherwise we need to ensure that a user is logged in return RuntimeState.Level == RuntimeLevel.Install || RuntimeState.Level == RuntimeLevel.Upgrade - || WebSecurity.ValidateCurrentUser(); + || BackofficeSecurity.ValidateCurrentUser(); } catch (Exception) { diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs index 940a9521aa..29f0949473 100644 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoController.cs @@ -67,7 +67,7 @@ namespace Umbraco.Web.Mvc /// /// Gets the web security helper. /// - public virtual IWebSecurity Security => UmbracoContext.Security; + public virtual IBackofficeSecurity Security => UmbracoContext.Security; protected UmbracoController() : this( diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/BackofficeSecurity.cs similarity index 95% rename from src/Umbraco.Web/Security/WebSecurity.cs rename to src/Umbraco.Web/Security/BackofficeSecurity.cs index 5776ec876a..e5e46ea37f 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/BackofficeSecurity.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.Security { // NOTE: Moved to netcore - public class WebSecurity : IWebSecurity + public class BackofficeSecurity : IBackofficeSecurity { public IUser CurrentUser => throw new NotImplementedException(); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c2d36285e6..dfade80794 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -157,7 +157,7 @@ - + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index bda836c847..a4b6e1dd14 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -30,7 +30,7 @@ namespace Umbraco.Web // warn: does *not* manage setting any IUmbracoContextAccessor internal UmbracoContext(IHttpContextAccessor httpContextAccessor, IPublishedSnapshotService publishedSnapshotService, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IVariationContextAccessor variationContextAccessor, @@ -39,7 +39,7 @@ namespace Umbraco.Web { if (httpContextAccessor == null) throw new ArgumentNullException(nameof(httpContextAccessor)); if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); + if (backofficeSecurity == null) throw new ArgumentNullException(nameof(backofficeSecurity)); VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _httpContextAccessor = httpContextAccessor; _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); @@ -58,7 +58,7 @@ namespace Umbraco.Web ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - Security = webSecurity; + Security = backofficeSecurity; // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); @@ -87,9 +87,9 @@ namespace Umbraco.Web public Guid UmbracoRequestId { get; } /// - /// Gets the WebSecurity class + /// Gets the BackofficeSecurity class /// - public IWebSecurity Security { get; } + public IBackofficeSecurity Security { get; } /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. diff --git a/src/Umbraco.Web/UmbracoContextFactory.cs b/src/Umbraco.Web/UmbracoContextFactory.cs index 4eba56c36f..cc0bd59fa1 100644 --- a/src/Umbraco.Web/UmbracoContextFactory.cs +++ b/src/Umbraco.Web/UmbracoContextFactory.cs @@ -68,7 +68,7 @@ namespace Umbraco.Web _variationContextAccessor.VariationContext = new VariationContext(_defaultCultureAccessor.DefaultCulture); } - return new UmbracoContext(_httpContextAccessor, _publishedSnapshotService, new WebSecurity(), _globalSettings, _hostingEnvironment, _variationContextAccessor, _uriUtility, _cookieManager); + return new UmbracoContext(_httpContextAccessor, _publishedSnapshotService, new BackofficeSecurity(), _globalSettings, _hostingEnvironment, _variationContextAccessor, _uriUtility, _cookieManager); } /// diff --git a/src/Umbraco.Web/UmbracoHttpHandler.cs b/src/Umbraco.Web/UmbracoHttpHandler.cs index eb219f82d2..7db09b62ff 100644 --- a/src/Umbraco.Web/UmbracoHttpHandler.cs +++ b/src/Umbraco.Web/UmbracoHttpHandler.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web /// /// Gets the web security helper. /// - public IWebSecurity Security => UmbracoContextAccessor.UmbracoContext.Security; + public IBackofficeSecurity Security => UmbracoContextAccessor.UmbracoContext.Security; /// /// Gets the Url helper. diff --git a/src/Umbraco.Web/UmbracoWebService.cs b/src/Umbraco.Web/UmbracoWebService.cs index a0d12cba93..9dca6f5d33 100644 --- a/src/Umbraco.Web/UmbracoWebService.cs +++ b/src/Umbraco.Web/UmbracoWebService.cs @@ -62,7 +62,7 @@ namespace Umbraco.Web /// /// Gets the web security helper. /// - public IWebSecurity Security => UmbracoContext.Security; + public IBackofficeSecurity Security => UmbracoContext.Security; /// /// Gets the Url helper. diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs index 7c15775f7b..3434d825fe 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs @@ -118,7 +118,7 @@ namespace Umbraco.Web.WebApi /// /// Gets the web security helper. /// - public IWebSecurity Security => UmbracoContext.Security; + public IBackofficeSecurity Security => UmbracoContext.Security; /// /// Tries to get the current HttpContext. diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs index 69c697d0fc..83f08660d9 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs @@ -1,6 +1,7 @@ using System; using System.Web.Http; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Web.Composing; using Umbraco.Web.Security; @@ -19,21 +20,21 @@ namespace Umbraco.Web.WebApi internal static bool Enable = true; // TODO: inject! - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IRuntimeState _runtimeState; private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState; - private IWebSecurity WebSecurity => _webSecurity ?? Current.UmbracoContext.Security; + private IBackofficeSecurity BackofficeSecurity => _backofficeSecurityAccessor.BackofficeSecurity ?? Current.UmbracoContext.Security; /// /// THIS SHOULD BE ONLY USED FOR UNIT TESTS /// - /// + /// /// - public UmbracoAuthorizeAttribute(IWebSecurity webSecurity, IRuntimeState runtimeState) + public UmbracoAuthorizeAttribute(IBackofficeSecurityAccessor backofficeSecurityAccessor, IRuntimeState runtimeState) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); } @@ -58,7 +59,7 @@ namespace Umbraco.Web.WebApi // otherwise we need to ensure that a user is logged in return RuntimeState.Level == RuntimeLevel.Install || RuntimeState.Level == RuntimeLevel.Upgrade - || WebSecurity.ValidateCurrentUser(false, _requireApproval) == ValidateRequestAttempt.Success; + || BackofficeSecurity.ValidateCurrentUser(false, _requireApproval) == ValidateRequestAttempt.Success; } catch (Exception) { From 164fa24ef3269c5c6f397fb6d07a3b785c70c970 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 10:04:55 +0200 Subject: [PATCH 17/25] #8919 - Fix issue with wrong casing of variable name --- .../src/common/services/iconhelper.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js index f714cba4ad..5034de67eb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js @@ -209,7 +209,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { ,'Failed to retrieve icon: ' + iconName) .then(icon => { if(icon) { - var trustedIcon = this.defineIcon(icon.name, icon.SvgString); + var trustedIcon = this.defineIcon(icon.Name, icon.SvgString); liveRequests = _.filter(liveRequests, iconRequestPath); From 1badb69481ef82cc09990a79c642a0f406f9e384 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 10:14:34 +0200 Subject: [PATCH 18/25] #8919 - Clean up obsolete ctor --- src/Umbraco.Web/Editors/BackOfficeController.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 71bda4bfd2..cd5a3a50b6 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -67,9 +67,7 @@ namespace Umbraco.Web.Editors umbracoHelper, Current.IconService) { - _manifestParser = manifestParser; - _features = features; - _runtimeState = runtimeState; + } public BackOfficeController( From 8e9889d2690cca54ec1640cfd02f9c23ed78076e Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 12:44:36 +0200 Subject: [PATCH 19/25] Post merge Signed-off-by: Bjarke Berg --- src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj index 81d1c9f1d2..fefd18c11a 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -12,7 +12,6 @@ - From a80de91031aa474e428a9f1232a1a4c2b6df3555 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 13:19:54 +0200 Subject: [PATCH 20/25] Netcore: Handle tree authentication (#8866) * Added helper methods to invoke the authorization filters of the other controller action Signed-off-by: Bjarke Berg * Implemented Tree Auth Signed-off-by: Bjarke Berg * cleanup Signed-off-by: Bjarke Berg * Throw forbidden if user has no access instead of InternalServerError Signed-off-by: Bjarke Berg * EnsureBackofficeSecurity for background jobs Signed-off-by: Bjarke Berg Co-authored-by: Elitsa Marinovska --- .../Scheduling/ScheduledPublishing.cs | 5 +- .../Scheduling/SchedulerComponent.cs | 7 +- .../Controllers/SectionController.cs | 8 +- .../Extensions/ControllerContextExtensions.cs | 125 ++++++++++++++++++ .../Trees/ApplicationTreeController.cs | 81 ++++-------- .../UmbracoContext/UmbracoContext.cs | 4 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 - .../WebApi/HttpControllerContextExtensions.cs | 54 -------- 8 files changed, 170 insertions(+), 115 deletions(-) create mode 100644 src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs delete mode 100644 src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs diff --git a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs index 6ec0250d90..674012e797 100644 --- a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs @@ -14,13 +14,14 @@ namespace Umbraco.Web.Scheduling private readonly IMainDom _mainDom; private readonly IRuntimeState _runtime; private readonly IServerMessenger _serverMessenger; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; private readonly IServerRegistrar _serverRegistrar; private readonly IUmbracoContextFactory _umbracoContextFactory; public ScheduledPublishing(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService, - IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger) + IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger, IBackofficeSecurityFactory backofficeSecurityFactory) : base(runner, delayMilliseconds, periodMilliseconds) { _runtime = runtime; @@ -30,6 +31,7 @@ namespace Umbraco.Web.Scheduling _umbracoContextFactory = umbracoContextFactory; _logger = logger; _serverMessenger = serverMessenger; + _backofficeSecurityFactory = backofficeSecurityFactory; } public override bool IsAsync => false; @@ -76,6 +78,7 @@ namespace Umbraco.Web.Scheduling // but then what should be its "scope"? could we attach it to scopes? // - and we should definitively *not* have to flush it here (should be auto) // + _backofficeSecurityFactory.EnsureBackofficeSecurity(); using (var contextReference = _umbracoContextFactory.EnsureUmbracoContext()) { try diff --git a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs index cbf1df197d..5fb4f19473 100644 --- a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs @@ -39,6 +39,7 @@ namespace Umbraco.Web.Scheduling private readonly HealthChecksSettings _healthChecksSettings; private readonly IServerMessenger _serverMessenger; private readonly IRequestAccessor _requestAccessor; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; private readonly LoggingSettings _loggingSettings; private readonly KeepAliveSettings _keepAliveSettings; private readonly IHostingEnvironment _hostingEnvironment; @@ -60,7 +61,8 @@ namespace Umbraco.Web.Scheduling IApplicationShutdownRegistry applicationShutdownRegistry, IOptions healthChecksSettings, IServerMessenger serverMessenger, IRequestAccessor requestAccessor, IOptions loggingSettings, IOptions keepAliveSettings, - IHostingEnvironment hostingEnvironment) + IHostingEnvironment hostingEnvironment, + IBackofficeSecurityFactory backofficeSecurityFactory) { _runtime = runtime; _mainDom = mainDom; @@ -77,6 +79,7 @@ namespace Umbraco.Web.Scheduling _healthChecksSettings = healthChecksSettings.Value ?? throw new ArgumentNullException(nameof(healthChecksSettings)); _serverMessenger = serverMessenger; _requestAccessor = requestAccessor; + _backofficeSecurityFactory = backofficeSecurityFactory; _loggingSettings = loggingSettings.Value; _keepAliveSettings = keepAliveSettings.Value; _hostingEnvironment = hostingEnvironment; @@ -150,7 +153,7 @@ namespace Umbraco.Web.Scheduling { // scheduled publishing/unpublishing // install on all, will only run on non-replica servers - var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _logger, _serverMessenger); + var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _logger, _serverMessenger, _backofficeSecurityFactory); _publishingRunner.TryAdd(task); return task; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs index 810e3e5646..c579a3ec1d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Umbraco.Core; using Umbraco.Core.Mapping; using Umbraco.Core.Models; @@ -23,6 +24,7 @@ namespace Umbraco.Web.Editors public class SectionController : UmbracoAuthorizedJsonController { private readonly IControllerFactory _controllerFactory; + private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; private readonly IDashboardService _dashboardService; private readonly ILocalizedTextService _localizedTextService; private readonly ISectionService _sectionService; @@ -34,7 +36,8 @@ namespace Umbraco.Web.Editors IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService, IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService, - UmbracoMapper umbracoMapper, IControllerFactory controllerFactory) + UmbracoMapper umbracoMapper, IControllerFactory controllerFactory, + IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) { _backofficeSecurityAccessor = backofficeSecurityAccessor; _localizedTextService = localizedTextService; @@ -43,6 +46,7 @@ namespace Umbraco.Web.Editors _treeService = treeService; _umbracoMapper = umbracoMapper; _controllerFactory = controllerFactory; + _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; } public IEnumerable
GetSections() @@ -54,7 +58,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(_treeService, _sectionService, _localizedTextService, _controllerFactory) + new ApplicationTreeController(_treeService, _sectionService, _localizedTextService, _controllerFactory, _actionDescriptorCollectionProvider) { ControllerContext = ControllerContext }; diff --git a/src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs new file mode 100644 index 0000000000..ca17d97fc7 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; + +namespace Umbraco.Extensions +{ + internal static class ControllerContextExtensions + { + /// + /// Invokes the authorization filters for the controller action. + /// + /// Whether the user is authenticated or not. + internal static async Task InvokeAuthorizationFiltersForRequest(this ControllerContext controllerContext, ActionContext actionContext) + { + var actionDescriptor = controllerContext.ActionDescriptor; + + var filters = actionDescriptor.FilterDescriptors; + var filterGrouping = new FilterGrouping(filters, controllerContext.HttpContext.RequestServices); + + // because the continuation gets built from the inside out we need to reverse the filter list + // so that least specific filters (Global) get run first and the most specific filters (Action) get run last. + var authorizationFilters = filterGrouping.AuthorizationFilters.Reverse().ToList(); + var asyncAuthorizationFilters = filterGrouping.AsyncAuthorizationFilters.Reverse().ToList(); + + if (authorizationFilters.Count == 0 && asyncAuthorizationFilters.Count == 0) + return true; + + // if the authorization filter returns a result, it means it failed to authorize + var authorizationFilterContext = new AuthorizationFilterContext(actionContext, filters.Select(x=>x.Filter).ToArray()); + return await ExecuteAuthorizationFiltersAsync(authorizationFilterContext, authorizationFilters, asyncAuthorizationFilters); + } + + /// + /// Executes a chain of filters. + /// + /// + /// Recursively calls in to itself as its continuation for the next filter in the chain. + /// + private static async Task ExecuteAuthorizationFiltersAsync( + AuthorizationFilterContext authorizationFilterContext, + IList authorizationFilters, + IList asyncAuthorizationFilters) + { + + foreach (var authorizationFilter in authorizationFilters) + { + authorizationFilter.OnAuthorization(authorizationFilterContext); + if (!(authorizationFilterContext.Result is null)) + { + return false; + } + + } + + foreach (var asyncAuthorizationFilter in asyncAuthorizationFilters) + { + await asyncAuthorizationFilter.OnAuthorizationAsync(authorizationFilterContext); + if (!(authorizationFilterContext.Result is null)) + { + return false; + } + } + + return true; + } + + /// + /// Quickly split filters into different types + /// + private class FilterGrouping + { + private readonly List _actionFilters = new List(); + private readonly List _asyncActionFilters = new List(); + private readonly List _authorizationFilters = new List(); + private readonly List _asyncAuthorizationFilters = new List(); + private readonly List _exceptionFilters = new List(); + private readonly List _asyncExceptionFilters = new List(); + + public FilterGrouping(IEnumerable filters, IServiceProvider serviceProvider) + { + if (filters == null) throw new ArgumentNullException("filters"); + + foreach (FilterDescriptor f in filters) + { + var filter = f.Filter; + Categorize(filter, _actionFilters, serviceProvider); + Categorize(filter, _authorizationFilters, serviceProvider); + Categorize(filter, _exceptionFilters, serviceProvider); + Categorize(filter, _asyncActionFilters, serviceProvider); + Categorize(filter, _asyncAuthorizationFilters, serviceProvider); + } + } + + public IEnumerable ActionFilters => _actionFilters; + public IEnumerable AsyncActionFilters => _asyncActionFilters; + public IEnumerable AuthorizationFilters => _authorizationFilters; + + public IEnumerable AsyncAuthorizationFilters => _asyncAuthorizationFilters; + + public IEnumerable ExceptionFilters => _exceptionFilters; + + public IEnumerable AsyncExceptionFilters => _asyncExceptionFilters; + + private static void Categorize(IFilterMetadata filter, List list, IServiceProvider serviceProvider) where T : class + { + if(filter is TypeFilterAttribute typeFilterAttribute) + { + filter = typeFilterAttribute.CreateInstance(serviceProvider); + } + + T match = filter as T; + if (match != null) + { + list.Add(match); + } + } + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs index 6253aa1ff4..92cb5b1b93 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs @@ -8,10 +8,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Primitives; using Umbraco.Core; using Umbraco.Core.Services; +using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Trees; using Umbraco.Web.Common.Attributes; @@ -35,18 +37,22 @@ namespace Umbraco.Web.Trees private readonly ISectionService _sectionService; private readonly ILocalizedTextService _localizedTextService; private readonly IControllerFactory _controllerFactory; + private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; + public ApplicationTreeController( ITreeService treeService, ISectionService sectionService, ILocalizedTextService localizedTextService, - IControllerFactory controllerFactory + IControllerFactory controllerFactory, + IActionDescriptorCollectionProvider actionDescriptorCollectionProvider ) { _treeService = treeService; _sectionService = sectionService; _localizedTextService = localizedTextService; _controllerFactory = controllerFactory; + _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; } /// @@ -251,67 +257,36 @@ namespace Umbraco.Web.Trees private async Task GetApiControllerProxy(Type controllerType, string action, FormCollection querystring) { // note: this is all required in order to execute the auth-filters for the sub request, we - // need to "trick" web-api into thinking that it is actually executing the proxied controller. - + // need to "trick" mvc into thinking that it is actually executing the proxied controller. + var controllerName = controllerType.Name.Substring(0, controllerType.Name.Length - 10); // remove controller part of name; // create proxy route data specifying the action & controller to execute var routeData = new RouteData(new RouteValueDictionary() { ["action"] = action, - ["controller"] = controllerType.Name.Substring(0,controllerType.Name.Length-10) // remove controller part of name; - + ["controller"] = controllerName }); + if (!(querystring is null)) + { + foreach (var (key,value) in querystring) + { + routeData.Values[key] = value; + } + } + var actionDescriptor = _actionDescriptorCollectionProvider.ActionDescriptors.Items + .Cast() + .First(x => + x.ControllerName.Equals(controllerName) && + x.ActionName == action); - var controllerContext = new ControllerContext( - new ActionContext( - HttpContext, - routeData, - new ControllerActionDescriptor() - { - ControllerTypeInfo = controllerType.GetTypeInfo() - } - )); + var actionContext = new ActionContext(HttpContext, routeData, actionDescriptor); + var proxyControllerContext = new ControllerContext(actionContext); + var controller = (TreeController) _controllerFactory.CreateController(proxyControllerContext); - var controller = (TreeController) _controllerFactory.CreateController(controllerContext); - - - //TODO Refactor trees or reimplement this hacks to check authentication. - //https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/3694 - - // var context = ControllerContext; - // - // // get the controller - // var controller = (TreeController) DependencyResolver.Current.GetService(controllerType) - // ?? throw new Exception($"Failed to create controller of type {controllerType.FullName}."); - // - // // create the proxy URL for the controller action - // var proxyUrl = HttpContext.Request.RequestUri.GetLeftPart(UriPartial.Authority) - // + HttpContext.Request.GetUrlHelper().GetUmbracoApiService(action, controllerType) - // + "?" + querystring.ToQueryString(); - // - // - // - // // create a proxy request - // var proxyRequest = new HttpRequestMessage(HttpMethod.Get, proxyUrl); - // - // // create a proxy controller context - // var proxyContext = new HttpControllerContext(context.Configuration, proxyRoute, proxyRequest) - // { - // ControllerDescriptor = new HttpControllerDescriptor(context.ControllerDescriptor.Configuration, ControllerExtensions.GetControllerName(controllerType), controllerType), - // RequestContext = context.RequestContext, - // Controller = controller - // }; - // - // // wire everything - // controller.ControllerContext = proxyContext; - // controller.Request = proxyContext.Request; - // controller.RequestContext.RouteData = proxyRoute; - // - // // auth - // var authResult = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(); - // if (authResult != null) - // throw new HttpResponseException(authResult); + var isAllowed = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(actionContext); + if (!isAllowed) + throw new HttpResponseException(HttpStatusCode.Forbidden); return controller; } diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs index 6b4ce706e3..5e5b6f6910 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs @@ -40,16 +40,16 @@ namespace Umbraco.Web IRequestAccessor requestAccessor) { if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - if (backofficeSecurity == null) throw new ArgumentNullException(nameof(backofficeSecurity)); VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); + _hostingEnvironment = hostingEnvironment; _cookieManager = cookieManager; _requestAccessor = requestAccessor; ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - Security = backofficeSecurity; + Security = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity)); // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index dfade80794..962c8ed528 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -296,7 +296,6 @@ - diff --git a/src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs b/src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs deleted file mode 100644 index 323e52eb36..0000000000 --- a/src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using System.Web.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; -using Umbraco.Web.WebApi.Filters; - -namespace Umbraco.Web.WebApi -{ - internal static class HttpControllerContextExtensions - { - /// - /// Invokes the authorization filters for the controller action. - /// - /// The response of the first filter returning a result, if any, otherwise null (authorized). - internal static async Task InvokeAuthorizationFiltersForRequest(this HttpControllerContext controllerContext) - { - var controllerDescriptor = controllerContext.ControllerDescriptor; - var controllerServices = controllerDescriptor.Configuration.Services; - var actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext); - - var filters = actionDescriptor.GetFilterPipeline(); - var filterGrouping = new FilterGrouping(filters); - - // because the continuation gets built from the inside out we need to reverse the filter list - // so that least specific filters (Global) get run first and the most specific filters (Action) get run last. - var authorizationFilters = filterGrouping.AuthorizationFilters.Reverse().ToList(); - - if (authorizationFilters.Count == 0) - return null; - - // if the authorization filter returns a result, it means it failed to authorize - var actionContext = new HttpActionContext(controllerContext, actionDescriptor); - return await ExecuteAuthorizationFiltersAsync(actionContext, CancellationToken.None, authorizationFilters); - } - - /// - /// Executes a chain of filters. - /// - /// - /// Recursively calls in to itself as its continuation for the next filter in the chain. - /// - private static async Task ExecuteAuthorizationFiltersAsync(HttpActionContext actionContext, CancellationToken token, IList filters, int index = 0) - { - return await filters[index].ExecuteAuthorizationFilterAsync(actionContext, token, - () => ++index == filters.Count - ? Task.FromResult(null) - : ExecuteAuthorizationFiltersAsync(actionContext, token, filters, index)); - } - } -} From 35c39623a6343714a278813e1aadb9dcef039cfb Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 13:45:20 +0200 Subject: [PATCH 21/25] fix merge issue Signed-off-by: Bjarke Berg --- src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index f0ed1803a0..bcd3773ac8 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -41,8 +41,6 @@ - - From 3533c6a9590ee857b231a0e5833c332acb50ca11 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 14:14:27 +0200 Subject: [PATCH 22/25] Fixed issue with template using alpha001 Signed-off-by: Bjarke Berg --- build/templates/UmbracoSolution/.template.config/template.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/templates/UmbracoSolution/.template.config/template.json b/build/templates/UmbracoSolution/.template.config/template.json index c222161245..ed83414eb6 100644 --- a/build/templates/UmbracoSolution/.template.config/template.json +++ b/build/templates/UmbracoSolution/.template.config/template.json @@ -15,7 +15,7 @@ "version": { "type": "parameter", "datatype": "string", - "defaultValue": "0.5.0-alpha001", + "defaultValue": "0.5.0-alpha002", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, From 6fdf7082a043a520e45eba0b84d9d8f47664db76 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 14:16:00 +0200 Subject: [PATCH 23/25] Fixed issue models builder config and changed default mode to nothing Signed-off-by: Bjarke Berg --- .../Extensions/UmbracoCoreServiceCollectionExtensions.cs | 2 +- src/Umbraco.Web.UI.NetCore/appsettings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index 44fb18a159..e6808ea4e7 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -139,7 +139,7 @@ namespace Umbraco.Extensions services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "KeepAlive")); services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Logging")); services.Configure(configuration.GetSection(Constants.Configuration.ConfigSecurityPrefix + "MemberPassword")); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "ModelsBuilder")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "ModelsBuilder")); services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "NuCache")); services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "RequestHandler")); services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Runtime")); diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.json b/src/Umbraco.Web.UI.NetCore/appsettings.json index 1eb761e1ad..0082f3fa50 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.json @@ -56,7 +56,7 @@ "EnableTours": true }, "ModelsBuilder": { - "ModelsMode": "PureLive", + "ModelsMode": "Nothing", "Enable": "true" } } From 0c908a7bbb0d6988ed6d5f29488f38cbfbab14f7 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 14:44:41 +0200 Subject: [PATCH 24/25] Introduced interface on BackOfficeUserManager (#8913) * Introduced IBackOfficeUserManager * Fixed test * Moved class into own file Co-authored-by: Elitsa Marinovska --- .../BackOffice/BackOfficeUserManager.cs | 2 +- .../BackOffice/IBackOfficeUserManager.cs | 271 ++++++++++++++++++ .../Install/InstallSteps/NewInstallStep.cs | 4 +- ...kOfficeServiceCollectionExtensionsTests.cs | 2 +- .../Controllers/UsersControllerUnitTests.cs | 6 +- .../Controllers/AuthenticationController.cs | 4 +- .../Controllers/BackOfficeController.cs | 7 +- .../Controllers/CurrentUserController.cs | 4 +- .../Controllers/UsersController.cs | 4 +- .../BackOfficeServiceCollectionExtensions.cs | 3 +- .../Extensions/IdentityBuilderExtensions.cs | 22 ++ .../Security/BackOfficeSessionIdValidator.cs | 4 +- .../Security/PasswordChanger.cs | 2 +- .../Security/BackOfficeSignInManager.cs | 2 +- .../Security/BackOfficeSignInManager.cs | 4 +- 15 files changed, 316 insertions(+), 25 deletions(-) create mode 100644 src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs create mode 100644 src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs diff --git a/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs b/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs index 6e11e20c8f..8a7186da77 100644 --- a/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs +++ b/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs @@ -14,7 +14,7 @@ using Umbraco.Net; namespace Umbraco.Core.BackOffice { - public class BackOfficeUserManager : BackOfficeUserManager + public class BackOfficeUserManager : BackOfficeUserManager, IBackOfficeUserManager { public BackOfficeUserManager( IIpResolver ipResolver, diff --git a/src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs b/src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs new file mode 100644 index 0000000000..e4cff3e042 --- /dev/null +++ b/src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Security.Principal; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; + + +namespace Umbraco.Core.BackOffice +{ + public interface IBackOfficeUserManager : IBackOfficeUserManager + { + + } + public interface IBackOfficeUserManager: IDisposable + where TUser : BackOfficeIdentityUser + { + + /// + /// Finds and returns a user, if any, who has the specified . + /// + /// The user ID to search for. + /// + /// The that represents the asynchronous operation, containing the user matching the specified if it exists. + /// + Task FindByIdAsync(string userId); + + /// + /// Generates a password reset token for the specified , using + /// the configured password reset token provider. + /// + /// The user to generate a password reset token for. + /// The that represents the asynchronous operation, + /// containing a password reset token for the specified . + Task GeneratePasswordResetTokenAsync(TUser user); + + /// + /// This is a special method that will reset the password but will raise the Password Changed event instead of the reset event + /// + /// + /// + /// + /// + /// + /// We use this because in the back office the only way an admin can change another user's password without first knowing their password + /// is to generate a token and reset it, however, when we do this we want to track a password change, not a password reset + /// + Task ChangePasswordWithResetAsync(int userId, string token, string newPassword); + + /// + /// Validates that an email confirmation token matches the specified . + /// + /// The user to validate the token against. + /// The email confirmation token to validate. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task ConfirmEmailAsync(TUser user, string token); + + /// + /// Gets the user, if any, associated with the normalized value of the specified email address. + /// Note: Its recommended that identityOptions.User.RequireUniqueEmail be set to true when using this method, otherwise + /// the store may throw if there are users with duplicate emails. + /// + /// The email address to return the user for. + /// + /// The task object containing the results of the asynchronous lookup operation, the user, if any, associated with a normalized value of the specified email address. + /// + Task FindByEmailAsync(string email); + + /// + /// Resets the 's password to the specified after + /// validating the given password reset . + /// + /// The user whose password should be reset. + /// The password reset token to verify. + /// The new password to set if reset token verification succeeds. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task ResetPasswordAsync(TUser user, string token, string newPassword); + + /// + /// Override to check the user approval value as well as the user lock out date, by default this only checks the user's locked out date + /// + /// + /// + /// + /// In the ASP.NET Identity world, there is only one value for being locked out, in Umbraco we have 2 so when checking this for Umbraco we need to check both values + /// + Task IsLockedOutAsync(TUser user); + + /// + /// Locks out a user until the specified end date has passed. Setting a end date in the past immediately unlocks a user. + /// + /// The user whose lockout date should be set. + /// The after which the 's lockout should end. + /// The that represents the asynchronous operation, containing the of the operation. + Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd); + + /// + /// Gets a flag indicating whether the email address for the specified has been verified, true if the email address is verified otherwise + /// false. + /// + /// The user whose email confirmation status should be returned. + /// + /// The task object containing the results of the asynchronous operation, a flag indicating whether the email address for the specified + /// has been confirmed or not. + /// + Task IsEmailConfirmedAsync(TUser user); + + /// + /// Updates the specified in the backing store. + /// + /// The user to update. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task UpdateAsync(TUser user); + + /// + /// Returns a flag indicating whether the specified is valid for + /// the given and . + /// + /// The user to validate the token against. + /// The token provider used to generate the token. + /// The purpose the token should be generated for. + /// The token to validate + /// + /// The that represents the asynchronous operation, returning true if the + /// is valid, otherwise false. + /// + Task VerifyUserTokenAsync(TUser user, string tokenProvider, string purpose, + string token); + + /// + /// Adds the to the specified only if the user + /// does not already have a password. + /// + /// The user whose password should be set. + /// The password to set. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task AddPasswordAsync(TUser user, string password); + + + /// + /// Returns a flag indicating whether the given is valid for the + /// specified . + /// + /// The user whose password should be validated. + /// The password to validate + /// The that represents the asynchronous operation, containing true if + /// the specified matches the one store for the , + /// otherwise false. + Task CheckPasswordAsync(TUser user, string password); + + /// + /// Changes a user's password after confirming the specified is correct, + /// as an asynchronous operation. + /// + /// The user whose password should be set. + /// The current password to validate before changing. + /// The new password to set for the specified . + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task ChangePasswordAsync(TUser user, string currentPassword, + string newPassword); + + /// + /// Used to validate a user's session + /// + /// + /// + /// + Task ValidateSessionIdAsync(string userId, string sessionId); + + /// + /// Creates the specified in the backing store with no password, + /// as an asynchronous operation. + /// + /// The user to create. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task CreateAsync(TUser user); + + /// + /// Helper method to generate a password for a user based on the current password validator + /// + /// + string GeneratePassword(); + + + /// + /// Generates an email confirmation token for the specified user. + /// + /// The user to generate an email confirmation token for. + /// + /// The that represents the asynchronous operation, an email confirmation token. + /// + Task GenerateEmailConfirmationTokenAsync(TUser user); + + /// + /// Finds and returns a user, if any, who has the specified user name. + /// + /// The user name to search for. + /// + /// The that represents the asynchronous operation, containing the user matching the specified if it exists. + /// + Task FindByNameAsync(string userName); + + /// + /// Increments the access failed count for the user as an asynchronous operation. + /// If the failed access account is greater than or equal to the configured maximum number of attempts, + /// the user will be locked out for the configured lockout time span. + /// + /// The user whose failed access count to increment. + /// The that represents the asynchronous operation, containing the of the operation. + Task AccessFailedAsync(TUser user); + + /// + /// Returns a flag indicating whether the specified has two factor authentication enabled or not, + /// as an asynchronous operation. + /// + /// The user whose two factor authentication enabled status should be retrieved. + /// + /// The that represents the asynchronous operation, true if the specified + /// has two factor authentication enabled, otherwise false. + /// + Task GetTwoFactorEnabledAsync(TUser user); + + /// + /// Gets a list of valid two factor token providers for the specified , + /// as an asynchronous operation. + /// + /// The user the whose two factor authentication providers will be returned. + /// + /// The that represents result of the asynchronous operation, a list of two + /// factor authentication providers for the specified user. + /// + Task> GetValidTwoFactorProvidersAsync(TUser user); + + /// + /// Verifies the specified two factor authentication against the . + /// + /// The user the token is supposed to be for. + /// The provider which will verify the token. + /// The token to verify. + /// + /// The that represents result of the asynchronous operation, true if the token is valid, + /// otherwise false. + /// + Task VerifyTwoFactorTokenAsync(TUser user, string tokenProvider, string token); + + Task ResetAccessFailedCountAsync(TUser user); + + void RaiseForgotPasswordRequestedEvent(IPrincipal currentUser, int userId); + void RaiseForgotPasswordChangedSuccessEvent(IPrincipal currentUser, int userId); + void RaiseLogoutSuccessEvent(IPrincipal currentUser, int userId); + + void RaiseLoginSuccessEvent(TUser currentUser, int userId); + } +} diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs index f2e9556a48..96e4a9ae34 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.Install.InstallSteps private readonly SecuritySettings _securitySettings; private readonly ConnectionStrings _connectionStrings; private readonly ICookieManager _cookieManager; - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; public NewInstallStep( IUserService userService, @@ -43,7 +43,7 @@ namespace Umbraco.Web.Install.InstallSteps IOptions securitySettings, IOptions connectionStrings, ICookieManager cookieManager, - BackOfficeUserManager userManager) + IBackOfficeUserManager userManager) { _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _databaseBuilder = databaseBuilder ?? throw new ArgumentNullException(nameof(databaseBuilder)); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs index 51fce283f8..58be305b91 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions [Test] public void AddUmbracoBackOfficeIdentity_ExpectBackOfficeUserManagerResolvable() { - var userManager = Services.GetService(); + var userManager = Services.GetService(); Assert.NotNull(userManager); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs index 4c038a58e6..97a90be908 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs @@ -15,14 +15,14 @@ namespace Umbraco.Tests.Web.Controllers { [Test,AutoMoqData] public void PostUnlockUsers_When_User_Lockout_Update_Fails_Expect_Failure_Response( - [Frozen] IUserStore userStore, + [Frozen] IBackOfficeUserManager backOfficeUserManager, UsersController sut, BackOfficeIdentityUser user, int[] userIds, string expectedMessage) { - Mock.Get(userStore) - .Setup(x => x.FindByIdAsync(It.IsAny(), It.IsAny())) + Mock.Get(backOfficeUserManager) + .Setup(x => x.FindByIdAsync(It.IsAny())) .ReturnsAsync(user); Assert.ThrowsAsync(() => sut.PostUnlockUsers(userIds)); diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 185269b6f1..51ed87a7e7 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.BackOffice.Controllers public class AuthenticationController : UmbracoApiControllerBase { private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; private readonly BackOfficeSignInManager _signInManager; private readonly IUserService _userService; private readonly ILocalizedTextService _textService; @@ -60,7 +60,7 @@ namespace Umbraco.Web.BackOffice.Controllers public AuthenticationController( IBackofficeSecurityAccessor backofficeSecurityAccessor, - BackOfficeUserManager backOfficeUserManager, + IBackOfficeUserManager backOfficeUserManager, BackOfficeSignInManager signInManager, IUserService userService, ILocalizedTextService textService, diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 6db4efab40..efcf7d9e12 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -36,11 +36,10 @@ namespace Umbraco.Web.BackOffice.Controllers [PluginController(Constants.Web.Mvc.BackOfficeArea)] public class BackOfficeController : Controller { - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; private readonly IRuntimeMinifier _runtimeMinifier; private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ILocalizedTextService _textService; private readonly IGridConfig _gridConfig; private readonly BackOfficeServerVariables _backOfficeServerVariables; @@ -50,11 +49,10 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ILogger _logger; public BackOfficeController( - BackOfficeUserManager userManager, + IBackOfficeUserManager userManager, IRuntimeMinifier runtimeMinifier, IOptions globalSettings, IHostingEnvironment hostingEnvironment, - IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IGridConfig gridConfig, BackOfficeServerVariables backOfficeServerVariables, @@ -67,7 +65,6 @@ namespace Umbraco.Web.BackOffice.Controllers _runtimeMinifier = runtimeMinifier; _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; - _umbracoContextAccessor = umbracoContextAccessor; _textService = textService; _gridConfig = gridConfig ?? throw new ArgumentNullException(nameof(gridConfig)); _backOfficeServerVariables = backOfficeServerVariables; diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 3aab1853dc..abd9e6ab1d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -43,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUserService _userService; private readonly UmbracoMapper _umbracoMapper; - private readonly BackOfficeUserManager _backOfficeUserManager; + private readonly IBackOfficeUserManager _backOfficeUserManager; private readonly ILogger _logger; private readonly ILocalizedTextService _localizedTextService; private readonly AppCaches _appCaches; @@ -57,7 +57,7 @@ namespace Umbraco.Web.BackOffice.Controllers IBackofficeSecurityAccessor backofficeSecurityAccessor, IUserService userService, UmbracoMapper umbracoMapper, - BackOfficeUserManager backOfficeUserManager, + IBackOfficeUserManager backOfficeUserManager, ILogger logger, ILocalizedTextService localizedTextService, AppCaches appCaches, diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index cfa1e980bd..3e7216e497 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -72,7 +72,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMediaService _mediaService; private readonly IContentService _contentService; private readonly GlobalSettings _globalSettings; - private readonly BackOfficeUserManager _backOfficeUserManager; + private readonly IBackOfficeUserManager _backOfficeUserManager; private readonly ILogger _logger; private readonly LinkGenerator _linkGenerator; @@ -95,7 +95,7 @@ namespace Umbraco.Web.BackOffice.Controllers IMediaService mediaService, IContentService contentService, IOptions globalSettings, - BackOfficeUserManager backOfficeUserManager, + IBackOfficeUserManager backOfficeUserManager, ILogger logger, LinkGenerator linkGenerator) { diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs index d9eb0987d0..4e00525c2a 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; @@ -57,7 +58,7 @@ namespace Umbraco.Extensions services.BuildUmbracoBackOfficeIdentity() .AddDefaultTokenProviders() .AddUserStore() - .AddUserManager() + .AddUserManager() .AddSignInManager() .AddClaimsPrincipalFactory>(); diff --git a/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs new file mode 100644 index 0000000000..eab7142665 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.BackOffice; + +namespace Umbraco.Extensions +{ + public static class IdentityBuilderExtensions + { + /// + /// Adds a for the . + /// + /// The type of the user manager to add. + /// + /// The current instance. + public static IdentityBuilder AddUserManager(this IdentityBuilder identityBuilder) where TUserManager : UserManager, TInterface + { + identityBuilder.AddUserManager(); + identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TUserManager)); + return identityBuilder; + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs index e91a517496..b5974c870a 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs @@ -37,9 +37,9 @@ namespace Umbraco.Web.BackOffice.Security private readonly ISystemClock _systemClock; private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; - public BackOfficeSessionIdValidator(ISystemClock systemClock, IOptions globalSettings, IHostingEnvironment hostingEnvironment, BackOfficeUserManager userManager) + public BackOfficeSessionIdValidator(ISystemClock systemClock, IOptions globalSettings, IHostingEnvironment hostingEnvironment, IBackOfficeUserManager userManager) { _systemClock = systemClock; _globalSettings = globalSettings.Value; diff --git a/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs b/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs index 2ee74aad01..76ecaa32e3 100644 --- a/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs +++ b/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.BackOffice.Security IUser currentUser, IUser savingUser, ChangingPasswordModel passwordModel, - BackOfficeUserManager userMgr) + IBackOfficeUserManager userMgr) { if (passwordModel == null) throw new ArgumentNullException(nameof(passwordModel)); if (userMgr == null) throw new ArgumentNullException(nameof(userMgr)); diff --git a/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs b/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs index 07f7470243..6d4b2ddd4f 100644 --- a/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.Common.Security public class BackOfficeSignInManager : SignInManager { - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; public BackOfficeSignInManager( BackOfficeUserManager userManager, diff --git a/src/Umbraco.Web/Security/BackOfficeSignInManager.cs b/src/Umbraco.Web/Security/BackOfficeSignInManager.cs index 0dc86f7b1b..8c14d2544f 100644 --- a/src/Umbraco.Web/Security/BackOfficeSignInManager.cs +++ b/src/Umbraco.Web/Security/BackOfficeSignInManager.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.Security /// public class BackOfficeSignInManager : IDisposable { - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; private readonly IUserClaimsPrincipalFactory _claimsPrincipalFactory; private readonly IAuthenticationManager _authenticationManager; private readonly ILogger _logger; @@ -28,7 +28,7 @@ namespace Umbraco.Web.Security private readonly IOwinRequest _request; public BackOfficeSignInManager( - BackOfficeUserManager userManager, + IBackOfficeUserManager userManager, IUserClaimsPrincipalFactory claimsPrincipalFactory, IAuthenticationManager authenticationManager, ILogger logger, From 0ea251945b6c48cff164412a4dd3d4bdb7c9ca72 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 22 Sep 2020 15:59:37 +0200 Subject: [PATCH 25/25] Netcore: migrate more unittests (#8939) * Migrated unit tests * Migrated CoreThings tests Signed-off-by: Bjarke Berg * Migrated Property Editor unit tests Signed-off-by: Bjarke Berg * Migrated CoreXml tests Signed-off-by: Bjarke Berg * Moved more tests Signed-off-by: Bjarke Berg * revert some IsSZArray test code Signed-off-by: Bjarke Berg * Renamed bad named test Signed-off-by: Bjarke Berg * removed unnecessary file mentions in csproj file Signed-off-by: Bjarke Berg Co-authored-by: Elitsa Marinovska --- .../Models/PublishedContent/ModelType.cs | 1 - .../Compose/BlockEditorComponent.cs | 0 .../Compose/BlockEditorComposer.cs | 0 .../Compose/NestedContentPropertyComponent.cs | 0 .../Compose/NestedContentPropertyComposer.cs | 0 .../Published/PublishedSnapshotTestObjects.cs | 18 +- .../TestHelpers/MockedValueEditors.cs | 27 ++ .../TestHelpers/SolidPublishedSnapshot.cs | 445 ++++++++++++++++++ .../TestHelpers}/StringNewlineExtensions.cs | 2 +- .../CoreThings/CallContextTests.cs | 0 .../CoreThings/ObjectExtensionsTests.cs | 19 +- .../CoreThings/TryConvertToTests.cs | 9 +- .../Umbraco.Core}/CoreThings/UdiTests.cs | 0 .../CoreXml/FrameworkXmlTests.cs | 0 .../CoreXml/NavigableNavigatorTests.cs | 2 +- .../CoreXml/RenamedRootNavigatorTests.cs | 0 .../BlockEditorComponentTests.cs | 2 +- .../BlockListPropertyValueConverterTests.cs | 0 .../PropertyEditors/ColorListValidatorTest.cs | 8 +- ...ataValueReferenceFactoryCollectionTests.cs | 2 +- .../EnsureUniqueValuesValidatorTest.cs | 12 +- .../MultiValuePropertyEditorTests.cs | 32 +- .../NestedContentPropertyComponentTests.cs | 0 .../PropertyEditorValueConverterTests.cs | 3 +- .../PropertyEditorValueEditorTests.cs | 61 +-- .../Umbraco.Core/Published/ConvertersTests.cs | 177 +++++++ .../Umbraco.Core/Published/ModelTypeTests.cs | 64 +++ .../Published/NestedContentTests.cs | 25 +- .../Published/PropertyCacheLevelTests.cs | 48 +- .../CmsHelperCasingTests.cs | 15 +- .../DefaultShortStringHelperTests.cs | 202 ++++++++ ...aultShortStringHelperTestsWithoutSetup.cs} | 318 +++---------- .../MockShortStringHelper.cs | 0 .../StringExtensionsTests.cs | 40 +- .../StringValidationTests.cs | 42 ++ .../StylesheetHelperTests.cs | 5 +- .../Umbraco.Tests.UnitTests.csproj | 1 + src/Umbraco.Tests/Models/MediaXmlTest.cs | 1 - src/Umbraco.Tests/Models/VariationTests.cs | 3 +- .../Published/ConvertersTests.cs | 177 +------ src/Umbraco.Tests/Published/ModelTypeTests.cs | 61 +-- .../PublishedContent/NuCacheChildrenTests.cs | 3 +- .../PublishedContent/NuCacheTests.cs | 3 +- .../SolidPublishedSnapshot.cs | 39 +- .../Scoping/ScopedNuCacheTests.cs | 11 +- .../ContentTypeServiceVariantsTests.cs | 4 +- .../Strings/StringValidationTests.cs | 43 -- src/Umbraco.Tests/TestHelpers/TestHelper.cs | 19 - src/Umbraco.Tests/Umbraco.Tests.csproj | 32 +- src/Umbraco.Web/Umbraco.Web.csproj | 4 - 50 files changed, 1191 insertions(+), 789 deletions(-) rename src/{Umbraco.Web => Umbraco.Infrastructure}/Compose/BlockEditorComponent.cs (100%) rename src/{Umbraco.Web => Umbraco.Infrastructure}/Compose/BlockEditorComposer.cs (100%) rename src/{Umbraco.Web => Umbraco.Infrastructure}/Compose/NestedContentPropertyComponent.cs (100%) rename src/{Umbraco.Web => Umbraco.Infrastructure}/Compose/NestedContentPropertyComposer.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.Common}/Published/PublishedSnapshotTestObjects.cs (75%) create mode 100644 src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs create mode 100644 src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs rename src/{Umbraco.Tests => Umbraco.Tests.Common/TestHelpers}/StringNewlineExtensions.cs (96%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreThings/CallContextTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreThings/ObjectExtensionsTests.cs (93%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreThings/TryConvertToTests.cs (90%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreThings/UdiTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreXml/FrameworkXmlTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreXml/NavigableNavigatorTests.cs (99%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/CoreXml/RenamedRootNavigatorTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/BlockEditorComponentTests.cs (99%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/BlockListPropertyValueConverterTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/ColorListValidatorTest.cs (82%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs (99%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/EnsureUniqueValuesValidatorTest.cs (81%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/MultiValuePropertyEditorTests.cs (83%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/NestedContentPropertyComponentTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/PropertyEditorValueConverterTests.cs (97%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/PropertyEditors/PropertyEditorValueEditorTests.cs (60%) create mode 100644 src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs create mode 100644 src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/Published/NestedContentTests.cs (92%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/Published/PropertyCacheLevelTests.cs (84%) rename src/{Umbraco.Tests/Strings => Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper}/CmsHelperCasingTests.cs (74%) create mode 100644 src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs rename src/{Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs => Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTestsWithoutSetup.cs} (60%) rename src/{Umbraco.Tests/Strings => Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper}/MockShortStringHelper.cs (100%) rename src/{Umbraco.Tests/Strings => Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper}/StringExtensionsTests.cs (90%) create mode 100644 src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs rename src/{Umbraco.Tests/Strings => Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper}/StylesheetHelperTests.cs (97%) delete mode 100644 src/Umbraco.Tests/Strings/StringValidationTests.cs diff --git a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs index dd60eb9beb..94e7958780 100644 --- a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs @@ -390,7 +390,6 @@ namespace Umbraco.Core.Models.PublishedContent protected override bool IsCOMObjectImpl() => false; - public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { throw new NotSupportedException(); diff --git a/src/Umbraco.Web/Compose/BlockEditorComponent.cs b/src/Umbraco.Infrastructure/Compose/BlockEditorComponent.cs similarity index 100% rename from src/Umbraco.Web/Compose/BlockEditorComponent.cs rename to src/Umbraco.Infrastructure/Compose/BlockEditorComponent.cs diff --git a/src/Umbraco.Web/Compose/BlockEditorComposer.cs b/src/Umbraco.Infrastructure/Compose/BlockEditorComposer.cs similarity index 100% rename from src/Umbraco.Web/Compose/BlockEditorComposer.cs rename to src/Umbraco.Infrastructure/Compose/BlockEditorComposer.cs diff --git a/src/Umbraco.Web/Compose/NestedContentPropertyComponent.cs b/src/Umbraco.Infrastructure/Compose/NestedContentPropertyComponent.cs similarity index 100% rename from src/Umbraco.Web/Compose/NestedContentPropertyComponent.cs rename to src/Umbraco.Infrastructure/Compose/NestedContentPropertyComponent.cs diff --git a/src/Umbraco.Web/Compose/NestedContentPropertyComposer.cs b/src/Umbraco.Infrastructure/Compose/NestedContentPropertyComposer.cs similarity index 100% rename from src/Umbraco.Web/Compose/NestedContentPropertyComposer.cs rename to src/Umbraco.Infrastructure/Compose/NestedContentPropertyComposer.cs diff --git a/src/Umbraco.Tests/Published/PublishedSnapshotTestObjects.cs b/src/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs similarity index 75% rename from src/Umbraco.Tests/Published/PublishedSnapshotTestObjects.cs rename to src/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs index 0ec8c9cc4e..1c618380a0 100644 --- a/src/Umbraco.Tests/Published/PublishedSnapshotTestObjects.cs +++ b/src/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs @@ -1,13 +1,13 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using Moq; +using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; -using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { public class PublishedSnapshotTestObjects { + [PublishedModel("element1")] public class TestElementModel1 : PublishedElementModel { @@ -15,7 +15,7 @@ namespace Umbraco.Tests.Published : base(content) { } - public string Prop1 => this.Value("prop1"); + public string Prop1 => this.Value(Mock.Of(), "prop1"); } [PublishedModel("element2")] @@ -25,7 +25,7 @@ namespace Umbraco.Tests.Published : base(content) { } - public IEnumerable Prop2 => this.Value>("prop2"); + public IEnumerable Prop2 => this.Value>(Mock.Of(), "prop2"); } [PublishedModel("content1")] @@ -35,7 +35,7 @@ namespace Umbraco.Tests.Published : base(content) { } - public string Prop1 => this.Value("prop1"); + public string Prop1 => this.Value(Mock.Of(), "prop1"); } [PublishedModel("content2")] @@ -45,8 +45,8 @@ namespace Umbraco.Tests.Published : base(content) { } - public IEnumerable Prop2 => this.Value>("prop2"); + public IEnumerable Prop2 => this.Value>(Mock.Of(), "prop2"); } - + } } diff --git a/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs new file mode 100644 index 0000000000..954dedd3b4 --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs @@ -0,0 +1,27 @@ +using Moq; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; + +namespace Umbraco.Tests.TestHelpers.Entities +{ + public class MockedValueEditors + { + public static DataValueEditor CreateDataValueEditor(string name) + { + var valueType = (ValueTypes.IsValue(name)) ? name : ValueTypes.String; + + return new DataValueEditor( + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new DataEditorAttribute(name, name, name) + { + ValueType = valueType + } + + ); + } + } +} diff --git a/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs new file mode 100644 index 0000000000..1eef61a29e --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Tests.Common.PublishedContent +{ + public class SolidPublishedSnapshot : IPublishedSnapshot + { + public readonly SolidPublishedContentCache InnerContentCache = new SolidPublishedContentCache(); + public readonly SolidPublishedContentCache InnerMediaCache = new SolidPublishedContentCache(); + + public IPublishedContentCache Content => InnerContentCache; + + public IPublishedMediaCache Media => InnerMediaCache; + + public IPublishedMemberCache Members => null; + + public IDomainCache Domains => null; + + public IDisposable ForcedPreview(bool forcedPreview, Action callback = null) + { + throw new NotImplementedException(); + } + + public void Resync() + { } + + public IAppCache SnapshotCache => null; + + public IAppCache ElementsCache => null; + + public void Dispose() + { } + } + + public class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache + { + private readonly Dictionary _content = new Dictionary(); + + public SolidPublishedContentCache() + : base(false) + { } + + public void Add(SolidPublishedContent content) + { + _content[content.Id] = content.CreateModel(Mock.Of()); + } + + public void Clear() + { + _content.Clear(); + } + + public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string culture = null) + { + throw new NotImplementedException(); + } + + public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) + { + throw new NotImplementedException(); + } + + public string GetRouteById(bool preview, int contentId, string culture = null) + { + throw new NotImplementedException(); + } + + public string GetRouteById(int contentId, string culture = null) + { + throw new NotImplementedException(); + } + + public override IPublishedContent GetById(bool preview, int contentId) + { + return _content.ContainsKey(contentId) ? _content[contentId] : null; + } + + public override IPublishedContent GetById(bool preview, Guid contentId) + { + throw new NotImplementedException(); + } + + public override IPublishedContent GetById(bool preview, Udi nodeId) + => throw new NotSupportedException(); + + public override bool HasById(bool preview, int contentId) + { + return _content.ContainsKey(contentId); + } + + public override IEnumerable GetAtRoot(bool preview, string culture = null) + { + return _content.Values.Where(x => x.Parent == null); + } + + public override IPublishedContent GetSingleByXPath(bool preview, string xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override IPublishedContent GetSingleByXPath(bool preview, System.Xml.XPath.XPathExpression xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override IEnumerable GetByXPath(bool preview, string xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override IEnumerable GetByXPath(bool preview, System.Xml.XPath.XPathExpression xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override System.Xml.XPath.XPathNavigator CreateNavigator(bool preview) + { + throw new NotImplementedException(); + } + + public override System.Xml.XPath.XPathNavigator CreateNodeNavigator(int id, bool preview) + { + throw new NotImplementedException(); + } + + public override bool HasContent(bool preview) + { + return _content.Count > 0; + } + + public override IPublishedContentType GetContentType(int id) + { + throw new NotImplementedException(); + } + + public override IPublishedContentType GetContentType(string alias) + { + throw new NotImplementedException(); + } + + public override IPublishedContentType GetContentType(Guid key) + { + throw new NotImplementedException(); + } + + public override IEnumerable GetByContentType(IPublishedContentType contentType) + { + throw new NotImplementedException(); + } + } + + public class SolidPublishedContent : IPublishedContent + { + #region Constructor + + public SolidPublishedContent(IPublishedContentType contentType) + { + // initialize boring stuff + TemplateId = 0; + WriterId = CreatorId = 0; + CreateDate = UpdateDate = DateTime.Now; + Version = Guid.Empty; + + ContentType = contentType; + } + + #endregion + + #region Content + + private Dictionary _cultures; + + private Dictionary GetCultures() + { + return new Dictionary { { "", new PublishedCultureInfo("", Name, UrlSegment, UpdateDate) } }; + } + + public int Id { get; set; } + public Guid Key { get; set; } + public int? TemplateId { get; set; } + public int SortOrder { get; set; } + public string Name { get; set; } + public IReadOnlyDictionary Cultures => _cultures ?? (_cultures = GetCultures()); + public string UrlSegment { get; set; } + public int WriterId { get; set; } + public int CreatorId { get; set; } + public string Path { get; set; } + public DateTime CreateDate { get; set; } + public DateTime UpdateDate { get; set; } + public Guid Version { get; set; } + public int Level { get; set; } + + public PublishedItemType ItemType => PublishedItemType.Content; + public bool IsDraft(string culture = null) => false; + public bool IsPublished(string culture = null) => true; + + #endregion + + #region Tree + + public int ParentId { get; set; } + public IEnumerable ChildIds { get; set; } + + public IPublishedContent Parent { get; set; } + public IEnumerable Children { get; set; } + public IEnumerable ChildrenForAllCultures => Children; + + #endregion + + #region ContentType + + public IPublishedContentType ContentType { get; set; } + + #endregion + + #region Properties + + public IEnumerable Properties { get; set; } + + public IPublishedProperty GetProperty(string alias) + { + return Properties.FirstOrDefault(p => p.Alias.InvariantEquals(alias)); + } + + public IPublishedProperty GetProperty(string alias, bool recurse) + { + var property = GetProperty(alias); + if (recurse == false) return property; + + IPublishedContent content = this; + while (content != null && (property == null || property.HasValue() == false)) + { + content = content.Parent; + property = content?.GetProperty(alias); + } + + return property; + } + + public object this[string alias] + { + get + { + var property = GetProperty(alias); + return property == null || property.HasValue() == false ? null : property.GetValue(); + } + } + + #endregion + } + + public class SolidPublishedProperty : IPublishedProperty + { + public IPublishedPropertyType PropertyType { get; set; } + public string Alias { get; set; } + public object SolidSourceValue { get; set; } + public object SolidValue { get; set; } + public bool SolidHasValue { get; set; } + public object SolidXPathValue { get; set; } + + public virtual object GetSourceValue(string culture = null, string segment = null) => SolidSourceValue; + public virtual object GetValue(string culture = null, string segment = null) => SolidValue; + public virtual object GetXPathValue(string culture = null, string segment = null) => SolidXPathValue; + public virtual bool HasValue(string culture = null, string segment = null) => SolidHasValue; + } + + public class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty + { + private readonly IDictionary _solidSourceValues = new Dictionary(); + private readonly IDictionary _solidValues = new Dictionary(); + private readonly IDictionary _solidXPathValues = new Dictionary(); + + public override object GetSourceValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.GetSourceValue(culture, segment); + } + + return _solidSourceValues.ContainsKey(culture) ? _solidSourceValues[culture] : null; + } + + public override object GetValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.GetValue(culture, segment); + } + + return _solidValues.ContainsKey(culture) ? _solidValues[culture] : null; + } + + public override object GetXPathValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.GetXPathValue(culture, segment); + } + + return _solidXPathValues.ContainsKey(culture) ? _solidXPathValues[culture] : null; + } + + public override bool HasValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.HasValue(culture, segment); + } + + return _solidSourceValues.ContainsKey(culture); + } + + public void SetSourceValue(string culture, object value, bool defaultValue = false) + { + _solidSourceValues.Add(culture, value); + if (defaultValue) + { + SolidSourceValue = value; + SolidHasValue = true; + } + } + + public void SetValue(string culture, object value, bool defaultValue = false) + { + _solidValues.Add(culture, value); + if (defaultValue) + { + SolidValue = value; + SolidHasValue = true; + } + } + + public void SetXPathValue(string culture, object value, bool defaultValue = false) + { + _solidXPathValues.Add(culture, value); + if (defaultValue) + { + SolidXPathValue = value; + } + } + } + + [PublishedModel("ContentType2")] + public class ContentType2 : PublishedContentModel + { + #region Plumbing + + public ContentType2(IPublishedContent content, IPublishedValueFallback fallback) + : base(content) + { } + + #endregion + + public int Prop1 => this.Value(Mock.Of(), "prop1"); + } + + [PublishedModel("ContentType2Sub")] + public class ContentType2Sub : ContentType2 + { + #region Plumbing + + public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } + + #endregion + } + + public class PublishedContentStrong1 : PublishedContentModel + { + public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback) + : base(content) + { } + + public int StrongValue => this.Value(Mock.Of(), "strongValue"); + } + + public class PublishedContentStrong1Sub : PublishedContentStrong1 + { + public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } + + public int AnotherValue => this.Value(Mock.Of(), "anotherValue"); + } + + public class PublishedContentStrong2 : PublishedContentModel + { + public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback) + : base(content) + { } + + public int StrongValue => this.Value(Mock.Of(), "strongValue"); + } + + public class AutoPublishedContentType : PublishedContentType + { + private static readonly IPublishedPropertyType Default; + + static AutoPublishedContentType() + { + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 666 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); + + var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeServiceMock.Object); + Default = factory.CreatePropertyType("*", 666); + } + + public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable propertyTypes) + : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) + { } + + public AutoPublishedContentType(Guid key, int id, string alias, Func> propertyTypes) + : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) + { } + + public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) + : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) + { } + + public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, Func> propertyTypes) + : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) + { } + + public override IPublishedPropertyType GetPropertyType(string alias) + { + var propertyType = base.GetPropertyType(alias); + return propertyType ?? Default; + } + } +} diff --git a/src/Umbraco.Tests/StringNewlineExtensions.cs b/src/Umbraco.Tests.Common/TestHelpers/StringNewlineExtensions.cs similarity index 96% rename from src/Umbraco.Tests/StringNewlineExtensions.cs rename to src/Umbraco.Tests.Common/TestHelpers/StringNewlineExtensions.cs index b26f345788..6de58f84b2 100644 --- a/src/Umbraco.Tests/StringNewlineExtensions.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/StringNewlineExtensions.cs @@ -1,6 +1,6 @@ namespace Umbraco.Tests { - static class StringNewLineExtensions + public static class StringNewLineExtensions { /// /// Ensures Lf only everywhere. diff --git a/src/Umbraco.Tests/CoreThings/CallContextTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreThings/CallContextTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs diff --git a/src/Umbraco.Tests/CoreThings/ObjectExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs similarity index 93% rename from src/Umbraco.Tests/CoreThings/ObjectExtensionsTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs index 544c6335e1..3b09de2d0b 100644 --- a/src/Umbraco.Tests/CoreThings/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; -using System.Web.UI.WebControls; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.PropertyEditors; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.CoreThings { @@ -29,20 +28,6 @@ namespace Umbraco.Tests.CoreThings Thread.CurrentThread.CurrentCulture = _savedCulture; } - [Test] - public void CanParseStringToUnit() - { - const string stringUnit = "1234px"; - object objUnit = "1234px"; - var result = stringUnit.TryConvertTo(); - var result2 = objUnit.TryConvertTo(); - var unit = new Unit("1234px"); - Assert.IsTrue(result.Success); - Assert.IsTrue(result2.Success); - Assert.AreEqual(unit, result.Result); - Assert.AreEqual(unit, result2.Result); - } - [Test] public void Can_Convert_List_To_Enumerable() { @@ -301,7 +286,7 @@ namespace Umbraco.Tests.CoreThings [Test] public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType(12.34d); Assert.IsTrue(result.Success); diff --git a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs similarity index 90% rename from src/Umbraco.Tests/CoreThings/TryConvertToTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index cd26bf914f..c5c027ac65 100644 --- a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -10,15 +10,8 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.CoreThings { [TestFixture] - public class TryConvertToTests : UmbracoTestBase + public class TryConvertToTests { - protected void Compose() - { - base.Compose(); - - Composition.RegisterUnique(f => new DefaultShortStringHelper(f.GetInstance>())); - } - [Test] public void ConvertToIntegerTest() { diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreThings/UdiTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs diff --git a/src/Umbraco.Tests/CoreXml/FrameworkXmlTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreXml/FrameworkXmlTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs diff --git a/src/Umbraco.Tests/CoreXml/NavigableNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs similarity index 99% rename from src/Umbraco.Tests/CoreXml/NavigableNavigatorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs index 91ac3aacc2..c0d5d9af6d 100644 --- a/src/Umbraco.Tests/CoreXml/NavigableNavigatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs @@ -15,7 +15,7 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.CoreXml { [TestFixture] - public class NavigableNavigatorTests : UmbracoTestBase + public class NavigableNavigatorTests { [Test] public void NewNavigatorIsAtRoot() diff --git a/src/Umbraco.Tests/CoreXml/RenamedRootNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreXml/RenamedRootNavigatorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs diff --git a/src/Umbraco.Tests/PropertyEditors/BlockEditorComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs similarity index 99% rename from src/Umbraco.Tests/PropertyEditors/BlockEditorComponentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs index bfd8b8c77b..1636936615 100644 --- a/src/Umbraco.Tests/PropertyEditors/BlockEditorComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs @@ -15,7 +15,7 @@ namespace Umbraco.Tests.PropertyEditors { Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore, - + }; private const string _contentGuid1 = "036ce82586a64dfba2d523a99ed80f58"; diff --git a/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs similarity index 100% rename from src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs diff --git a/src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs similarity index 82% rename from src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs index f140e6a239..feb1b53b96 100644 --- a/src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs @@ -2,8 +2,10 @@ using Moq; using NUnit.Framework; using Newtonsoft.Json.Linq; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; @@ -16,7 +18,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -24,7 +26,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray_Of_Item_JObject() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -37,7 +39,7 @@ namespace Umbraco.Tests.PropertyEditors JObject.FromObject(new { value = "zxcvzxcvxzcv" }), JObject.FromObject(new { value = "ABC" }), JObject.FromObject(new { value = "1234567" })), - null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(2, result.Count()); } } diff --git a/src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs similarity index 99% rename from src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs index 24ac9cdbf4..aea4dab134 100644 --- a/src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.PropertyEditors public class DataValueReferenceFactoryCollectionTests { IDataTypeService DataTypeService { get; } = Mock.Of(); - private IIOHelper IOHelper { get; } = TestHelper.IOHelper; + private IIOHelper IOHelper { get; } = Mock.Of(); ILocalizedTextService LocalizedTextService { get; } = Mock.Of(); ILocalizationService LocalizationService { get; } = Mock.Of(); IShortStringHelper ShortStringHelper { get; } = Mock.Of(); diff --git a/src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs similarity index 81% rename from src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs index f3c3fb4672..930d039625 100644 --- a/src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs @@ -2,8 +2,10 @@ using Moq; using NUnit.Framework; using Newtonsoft.Json.Linq; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; @@ -16,7 +18,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -24,7 +26,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray_Of_Item_JObject() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -32,7 +34,7 @@ namespace Umbraco.Tests.PropertyEditors public void Allows_Unique_Values() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" })), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" })), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -41,7 +43,7 @@ namespace Umbraco.Tests.PropertyEditors { var validator = new ValueListUniqueValueValidator(); var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "hello" })), - null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(1, result.Count()); } @@ -54,7 +56,7 @@ namespace Umbraco.Tests.PropertyEditors JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" }), JObject.FromObject(new { value = "world" })), - null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(2, result.Count()); } } diff --git a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs similarity index 83% rename from src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs index 152a751a7b..262d55b6d7 100644 --- a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs @@ -1,18 +1,14 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using Moq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.PropertyEditors @@ -31,7 +27,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void DropDownMultipleValueEditor_Format_Data_For_Cache() { - var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, Mock.Of())) + var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Configuration = new ValueListConfiguration { @@ -45,14 +41,17 @@ namespace Umbraco.Tests.PropertyEditors Id = 1 }; - var dataTypeService = new TestObjects.TestDataTypeService(dataType); + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock + .Setup(x=>x.GetDataType(It.IsAny())) + .Returns(dataType); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, dataType)); + var prop = new Property(1, new PropertyType(Mock.Of(), dataType)); prop.SetValue("Value 1,Value 2,Value 3"); var valueEditor = dataType.Editor.GetValueEditor(); ((DataValueEditor) valueEditor).Configuration = dataType.Configuration; - var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService); + var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeServiceMock.Object); Assert.AreEqual("Value 1,Value 2,Value 3", result); } @@ -60,7 +59,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void DropDownValueEditor_Format_Data_For_Cache() { - var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, Mock.Of())) + var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Configuration = new ValueListConfiguration { @@ -74,12 +73,15 @@ namespace Umbraco.Tests.PropertyEditors Id = 1 }; - var dataTypeService = new TestObjects.TestDataTypeService(dataType); + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock + .Setup(x=>x.GetDataType(It.IsAny())) + .Returns(dataType); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, dataType)); + var prop = new Property(1, new PropertyType(Mock.Of(), dataType)); prop.SetValue("Value 2"); - var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService); + var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeServiceMock.Object); Assert.AreEqual("Value 2", result); } @@ -114,7 +116,7 @@ namespace Umbraco.Tests.PropertyEditors } }; - var editor = new ValueListConfigurationEditor(Mock.Of(), TestHelper.IOHelper); + var editor = new ValueListConfigurationEditor(Mock.Of(), Mock.Of()); var result = editor.ToConfigurationEditor(configuration); diff --git a/src/Umbraco.Tests/PropertyEditors/NestedContentPropertyComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs similarity index 100% rename from src/Umbraco.Tests/PropertyEditors/NestedContentPropertyComponentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs similarity index 97% rename from src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs index e8aa4f987c..dfd0e29674 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Serialization; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; using Umbraco.Web.PropertyEditors.ValueConverters; @@ -96,7 +97,7 @@ namespace Umbraco.Tests.PropertyEditors var publishedPropType = new PublishedPropertyType( new PublishedContentType(Guid.NewGuid(),1234, "test", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing), - new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Nvarchar) { DataTypeId = 123 }, + new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar) { DataTypeId = 123 }, new PropertyValueConverterCollection(Enumerable.Empty()), Mock.Of(), mockPublishedContentTypeFactory.Object); diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs similarity index 60% rename from src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs index 439036fa16..043f682a3f 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -1,56 +1,27 @@ using System; -using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Strings; -using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.Components; -using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.PropertyEditors { [TestFixture] public class PropertyEditorValueEditorTests { - [SetUp] - public virtual void TestSetup() - { - //normalize culture - Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; - - var register = TestHelper.GetRegister(); - var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); - - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - register.Register(_ - => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings))); - - Current.Factory = composition.CreateFactory(); - } - - [TearDown] - public virtual void TestTearDown() - { - Current.Reset(); - } - [TestCase("{prop1: 'val1', prop2: 'val2'}", true)] [TestCase("{1,2,3,4}", false)] [TestCase("[1,2,3,4]", true)] [TestCase("hello world", false)] public void Value_Editor_Can_Convert_To_Json_Object_For_Editor(string value, bool isOk) { - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Nvarchar)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar)); prop.SetValue(value); - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.String); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.String); var result = valueEditor.ToEditor(prop); Assert.AreEqual(isOk, !(result is string)); @@ -63,7 +34,7 @@ namespace Umbraco.Tests.PropertyEditors [TestCase("DATETIME", "", null)] //test empty string for date public void Value_Editor_Can_Convert_To_Clr_Type(string valueType, string val, object expected) { - var valueEditor = TestHelper.CreateDataValueEditor(valueType); + var valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); var result = valueEditor.TryConvertValueToCrlType(val); Assert.IsTrue(result.Success); @@ -75,7 +46,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType("12.34"); Assert.IsTrue(result.Success); @@ -85,7 +56,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type_With_Other_Separator() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType("12,34"); Assert.IsTrue(result.Success); @@ -95,7 +66,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type_With_Empty_String() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType(string.Empty); Assert.IsTrue(result.Success); @@ -105,7 +76,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Date_Clr_Type() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Date); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); var result = valueEditor.TryConvertValueToCrlType("2010-02-05"); Assert.IsTrue(result.Success); @@ -119,10 +90,10 @@ namespace Umbraco.Tests.PropertyEditors [TestCase(ValueTypes.DateTime, "", "")] //test empty string for date public void Value_Editor_Can_Serialize_Value(string valueType, object val, string expected) { - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Nvarchar)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar)); prop.SetValue(val); - var valueEditor = TestHelper.CreateDataValueEditor(valueType); + var valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); var result = valueEditor.ToEditor(prop); Assert.AreEqual(expected, result); @@ -132,9 +103,9 @@ namespace Umbraco.Tests.PropertyEditors public void Value_Editor_Can_Serialize_Decimal_Value() { var value = 12.34M; - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Decimal)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Decimal)); prop.SetValue(value); var result = valueEditor.ToEditor(prop); @@ -144,9 +115,9 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Serialize_Decimal_Value_With_Empty_String() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Decimal)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Decimal)); prop.SetValue(string.Empty); var result = valueEditor.ToEditor(prop); @@ -157,9 +128,9 @@ namespace Umbraco.Tests.PropertyEditors public void Value_Editor_Can_Serialize_Date_Value() { var now = DateTime.Now; - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Date); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Date)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Date)); prop.SetValue(now); var result = valueEditor.ToEditor(prop); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs new file mode 100644 index 0000000000..04c7abb72f --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.PublishedContent; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Tests.Published +{ + [TestFixture] + public class ConvertersTests + { + #region SimpleConverter1 + + [Test] + public void SimpleConverter1Test() + { + var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] + { + new SimpleConverter1(), + }); + + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); + + var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); + + IEnumerable CreatePropertyTypes(IPublishedContentType contentType) + { + yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); + } + + var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); + + var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); + + Assert.AreEqual(1234, element1.Value(Mock.Of(), "prop1")); + + // 'null' would be considered a 'missing' value by the default, magic logic + var e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", null } }, false); + Assert.IsFalse(e.HasValue("prop1")); + + // '0' would not - it's a valid integer - but the converter knows better + e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "0" } }, false); + Assert.IsFalse(e.HasValue("prop1")); + } + + private class SimpleConverter1 : IPropertyValueConverter + { + public bool? IsValue(object value, PropertyValueLevel level) + { + switch (level) + { + case PropertyValueLevel.Source: + return null; + case PropertyValueLevel.Inter: + return value is int ivalue && ivalue != 0; + default: + throw new NotSupportedException($"Invalid level: {level}."); + } + } + + public bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); + + public Type GetPropertyValueType(IPublishedPropertyType propertyType) + => typeof(int); + + public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) + => PropertyCacheLevel.Element; + + public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) + => int.TryParse(source as string, out int i) ? i : 0; + + public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => (int)inter; + + public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => ((int)inter).ToString(); + } + + #endregion + + #region SimpleConverter2 + + [Test] + public void SimpleConverter2Test() + { + var cacheMock = new Mock(); + var cacheContent = new Dictionary(); + cacheMock.Setup(x => x.GetById(It.IsAny())).Returns(id => cacheContent.TryGetValue(id, out IPublishedContent content) ? content : null); + var publishedSnapshotMock = new Mock(); + publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); + var publishedSnapshotAccessorMock = new Mock(); + publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); + var publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; + + var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] + { + new SimpleConverter2(publishedSnapshotAccessor), + }); + + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); + + var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); + + IEnumerable CreatePropertyTypes(IPublishedContentType contentType) + { + yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); + } + + var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); + + var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); + + var cntType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1001, "cnt1", t => Enumerable.Empty()); + var cnt1 = new SolidPublishedContent(cntType1) { Id = 1234 }; + cacheContent[cnt1.Id] = cnt1; + + Assert.AreSame(cnt1, element1.Value(Mock.Of(), "prop1")); + } + + private class SimpleConverter2 : IPropertyValueConverter + { + private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + private readonly PropertyCacheLevel _cacheLevel; + + public SimpleConverter2(IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel cacheLevel = PropertyCacheLevel.None) + { + _publishedSnapshotAccessor = publishedSnapshotAccessor; + _cacheLevel = cacheLevel; + } + + public bool? IsValue(object value, PropertyValueLevel level) + => value != null && (!(value is string) || string.IsNullOrWhiteSpace((string)value) == false); + + public bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); + + public Type GetPropertyValueType(IPublishedPropertyType propertyType) + // the first version would be the "generic" version, but say we want to be more precise + // and return: whatever Clr type is generated for content type with alias "cnt1" -- which + // we cannot really typeof() at the moment because it has not been generated, hence ModelType. + // => typeof (IPublishedContent); + => ModelType.For("cnt1"); + + public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) + => _cacheLevel; + + public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) + => int.TryParse(source as string, out int i) ? i : -1; + + public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById((int)inter); + + public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => ((int)inter).ToString(); + } + + #endregion + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs new file mode 100644 index 0000000000..43d5b56d6b --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Tests.Published +{ + [TestFixture] + public class ModelTypeTests + { + [Test] + public void ModelTypeEqualityTests() + { + Assert.AreNotEqual(ModelType.For("alias1"), ModelType.For("alias1")); + + Assert.IsTrue(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias1"))); + Assert.IsFalse(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias2"))); + + Assert.IsTrue(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")))); + Assert.IsFalse(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias2")))); + + Assert.IsTrue(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias1").MakeArrayType())); + Assert.IsFalse(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias2").MakeArrayType())); + } + + [Test] + public void TypeToStringTests() + { + var type = typeof(int); + Assert.AreEqual("System.Int32", type.ToString()); + Assert.AreEqual("System.Int32[]", type.MakeArrayType().ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[System.Int32[]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).ToString()); + } + + [Test] + public void TypeFullNameTests() + { + var type = typeof(int); + Assert.AreEqual("System.Int32", type.FullName); + Assert.AreEqual("System.Int32[]", type.MakeArrayType().FullName); + // note the inner assembly qualified name + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.Int32[], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).FullName); + } + + [Test] + public void ModelTypeMapTests() + { + var map = new Dictionary + { + { "alias1", typeof (PublishedSnapshotTestObjects.TestElementModel1) }, + { "alias2", typeof (PublishedSnapshotTestObjects.TestElementModel2) }, + }; + + Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1", + ModelType.Map(ModelType.For("alias1"), map).ToString()); + Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]", + ModelType.Map(ModelType.For("alias1").MakeArrayType(), map).ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1]", + ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), map).ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]]", + ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()), map).ToString()); + } + } +} diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs similarity index 92% rename from src/Umbraco.Tests/Published/NestedContentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index b4b941733c..49362183a9 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -5,24 +5,22 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Web.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Tests.PublishedContent; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.PublishedContent; using Umbraco.Web.PropertyEditors; using Umbraco.Web.PropertyEditors.ValueConverters; using Umbraco.Web.PublishedCache; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.Published { [TestFixture] - public class NestedContentTests : UmbracoTestBase + public class NestedContentTests { private (IPublishedContentType, IPublishedContentType) CreateContentTypes() { @@ -32,7 +30,7 @@ namespace Umbraco.Tests.Published var localizationService = Mock.Of(); PropertyEditorCollection editors = null; - var editor = new NestedContentPropertyEditor(logger, new Lazy(() => editors), Mock.Of(),localizationService, Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of()); + var editor = new NestedContentPropertyEditor(logger, new Lazy(() => editors), Mock.Of(),localizationService, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); editors = new PropertyEditorCollection(new DataEditorCollection(new DataEditor[] { editor })); var dataType1 = new DataType(editor) @@ -63,13 +61,14 @@ namespace Umbraco.Tests.Published } }; - var dataType3 = new DataType(new TextboxPropertyEditor(logger, Mock.Of(), localizationService, TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())) + var dataType3 = new DataType(new TextboxPropertyEditor(logger, Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; // mocked dataservice returns nested content preValues - var dataTypeService = new TestObjects.TestDataTypeService(dataType1, dataType2, dataType3); + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new []{dataType1, dataType2, dataType3}); var publishedModelFactory = new Mock(); @@ -123,7 +122,7 @@ namespace Umbraco.Tests.Published new NestedContentManyValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog), }); - var factory = new PublishedContentTypeFactory(publishedModelFactory.Object, converters, dataTypeService); + var factory = new PublishedContentTypeFactory(publishedModelFactory.Object, converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes1(IPublishedContentType contentType) { @@ -177,7 +176,7 @@ namespace Umbraco.Tests.Published ]") } }; - var value = content.Value("property1"); + var value = content.Value(Mock.Of(),"property1"); // nested single converter returns proper TestModel value Assert.IsInstanceOf(value); @@ -209,7 +208,7 @@ namespace Umbraco.Tests.Published ]") } }; - var value = content.Value("property2"); + var value = content.Value(Mock.Of(), ("property2")); // nested many converter returns proper IEnumerable value Assert.IsInstanceOf>(value); @@ -227,7 +226,7 @@ namespace Umbraco.Tests.Published : base(content) { } - public string PropValue => this.Value("propertyN1"); + public string PropValue => this.Value(Mock.Of(),"propertyN1"); } class TestPublishedProperty : PublishedPropertyBase diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs similarity index 84% rename from src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs index 8aeaf37f7f..cd0c3263dc 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs @@ -4,22 +4,18 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { [TestFixture] - public class PropertyCacheLevelTests : UmbracoTestBase + public class PropertyCacheLevelTests { [TestCase(PropertyCacheLevel.None, 2)] [TestCase(PropertyCacheLevel.Element, 1)] @@ -34,14 +30,18 @@ namespace Umbraco.Tests.Published converter, }); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); + + var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { - yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", 1); + yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", dataType.Id); } var setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); @@ -61,14 +61,14 @@ namespace Umbraco.Tests.Published var set1 = new PublishedElement(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(1, converter.InterConverts); // source is always converted once and cached per content // inter conversion depends on the specified cache level - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(interConverts, converter.InterConverts); } @@ -115,10 +115,13 @@ namespace Umbraco.Tests.Published converter, }); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); + var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { @@ -143,14 +146,14 @@ namespace Umbraco.Tests.Published var set1 = new PublishedElement(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false, referenceCacheLevel, publishedSnapshotAccessor.Object); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(1, converter.InterConverts); Assert.AreEqual(elementsCount1, elementsCache.Count); Assert.AreEqual(snapshotCount1, snapshotCache.Count); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(interConverts, converter.InterConverts); @@ -160,7 +163,7 @@ namespace Umbraco.Tests.Published var oldSnapshotCache = snapshotCache; snapshotCache.Clear(); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(elementsCount2, elementsCache.Count); @@ -172,7 +175,7 @@ namespace Umbraco.Tests.Published var oldElementsCache = elementsCache; elementsCache.Clear(); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(elementsCount2, elementsCache.Count); @@ -192,10 +195,13 @@ namespace Umbraco.Tests.Published converter, }); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); + var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { diff --git a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs similarity index 74% rename from src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs index 71d789eddb..ecdeb2b9e5 100644 --- a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs @@ -1,5 +1,9 @@ -using NUnit.Framework; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; @@ -8,8 +12,10 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.Strings { [TestFixture] - public class CmsHelperCasingTests : UmbracoTestBase + public class CmsHelperCasingTests { + private IShortStringHelper ShortStringHelper => new DefaultShortStringHelper(Options.Create(new RequestHandlerSettings())); + [TestCase("thisIsTheEnd", "This Is The End")] [TestCase("th", "Th")] [TestCase("t", "t")] @@ -31,9 +37,8 @@ namespace Umbraco.Tests.Strings [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6 In The Village")] // issue is fixed public void CompatibleDefaultReplacement(string input, string expected) { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings)); - var output = input.Length < 2 ? input : helper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); + + var output = input.Length < 2 ? input : ShortStringHelper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); Assert.AreEqual(expected, output); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs new file mode 100644 index 0000000000..e89fe680b3 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs @@ -0,0 +1,202 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Strings; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Strings +{ + [TestFixture] + public class DefaultShortStringHelperTests + { + private IShortStringHelper ShortStringHelper { get; set; } + + [SetUp] + public void SetUp() + { + + // NOTE pre-filters runs _before_ Recode takes place + // so there still may be utf8 chars even though you want ascii + + ShortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) + .WithConfig(CleanStringType.FileName, new DefaultShortStringHelperConfig.Config + { + //PreFilter = ClearFileChars, // done in IsTerm + IsTerm = (c, leading) => (char.IsLetterOrDigit(c) || c == '_') && DefaultShortStringHelper.IsValidFileNameChar(c), + StringType = CleanStringType.LowerCase | CleanStringType.Ascii, + Separator = '-' + }) + .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config + { + PreFilter = StripQuotes, + IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', + StringType = CleanStringType.LowerCase | CleanStringType.Ascii, + Separator = '-' + }) + .WithConfig("fr-FR", CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config + { + PreFilter = FilterFrenchElisions, + IsTerm = (c, leading) => leading ? char.IsLetter(c) : (char.IsLetterOrDigit(c) || c == '_'), + StringType = CleanStringType.LowerCase | CleanStringType.Ascii, + Separator = '-' + }) + .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config + { + PreFilter = StripQuotes, + IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), + StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii + }) + .WithConfig("fr-FR", CleanStringType.Alias, new DefaultShortStringHelperConfig.Config + { + PreFilter = WhiteQuotes, + IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), + StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii + }) + .WithConfig(CleanStringType.ConvertCase, new DefaultShortStringHelperConfig.Config + { + PreFilter = null, + IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore + StringType = CleanStringType.Ascii, + BreakTermsOnUpper = true + })); + } + + private static readonly Regex FrenchElisionsRegex = new Regex("\\b(c|d|j|l|m|n|qu|s|t)('|\u8217)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private static string FilterFrenchElisions(string s) + { + return FrenchElisionsRegex.Replace(s, ""); + } + + private static string StripQuotes(string s) + { + s = s.ReplaceMany(new Dictionary {{"'", ""}, {"\u8217", ""}}); + return s; + } + + private static string WhiteQuotes(string s) + { + s = s.ReplaceMany(new Dictionary { { "'", " " }, { "\u8217", " " } }); + return s; + } + + #region Cases + [TestCase("foo", "foo")] + [TestCase(" foo ", "foo")] + [TestCase("Foo", "Foo")] + [TestCase("FoO", "FoO")] + [TestCase("FoO bar", "FoOBar")] + [TestCase("FoO bar NIL", "FoOBarNIL")] + [TestCase("FoO 33bar 22NIL", "FoO33bar22NIL")] + [TestCase("FoO 33bar 22NI", "FoO33bar22NI")] + [TestCase("0foo", "foo")] + [TestCase("2foo bar", "fooBar")] + [TestCase("9FOO", "FOO")] + [TestCase("foo-BAR", "fooBAR")] + [TestCase("foo-BA-dang", "fooBADang")] + [TestCase("foo_BAR", "fooBAR")] + [TestCase("foo'BAR", "fooBAR")] + [TestCase("sauté dans l'espace", "sauteDansLespace")] + [TestCase("foo\"\"bar", "fooBar")] + [TestCase("-foo-", "foo")] + [TestCase("_foo_", "foo")] + [TestCase("spécial", "special")] + [TestCase("brô dëk ", "broDek")] + [TestCase("1235brô dëk ", "broDek")] + [TestCase("汉#字*/漢?字", "")] + [TestCase("aa DB cd EFG X KLMN OP qrst", "aaDBCdEFGXKLMNOPQrst")] + [TestCase("AA db cd EFG X KLMN OP qrst", "AADbCdEFGXKLMNOPQrst")] + [TestCase("AAA db cd EFG X KLMN OP qrst", "AAADbCdEFGXKLMNOPQrst")] + [TestCase("4 ways selector", "waysSelector")] + [TestCase("WhatIfWeDoItAgain", "WhatIfWeDoItAgain")] + [TestCase("whatIfWeDoItAgain", "whatIfWeDoItAgain")] + [TestCase("WhatIfWEDOITAgain", "WhatIfWEDOITAgain")] + [TestCase("WhatIfWe doItAgain", "WhatIfWeDoItAgain")] + #endregion + public void CleanStringForSafeAlias(string input, string expected) + { + var output = ShortStringHelper.CleanStringForSafeAlias(input); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("Home Page", "home-page")] + [TestCase("Shannon's Home Page!", "shannons-home-page")] + [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-h1z-n")] + [TestCase("Räksmörgås", "raksmorgas")] + [TestCase("'em guys-over there, are#goin' a \"little\"bit crazy eh!! :)", "em-guys-over-there-are-goin-a-little-bit-crazy-eh")] + [TestCase("汉#字*/漢?字", "")] + [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-losk")] + [TestCase("200 ways to be happy", "200-ways-to-be-happy")] + #endregion + public void CleanStringForUrlSegment(string input, string expected) + { + var output = ShortStringHelper.CleanStringForUrlSegment(input); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("ThisIsTheEndMyFriend", "This Is The End My Friend")] + [TestCase("ThisIsTHEEndMyFriend", "This Is THE End My Friend")] + [TestCase("THISIsTHEEndMyFriend", "THIS Is THE End My Friend")] + [TestCase("This33I33sThe33EndMyFriend", "This33 I33s The33 End My Friend")] // works! + [TestCase("ThisIsTHEEndMyFriendX", "This Is THE End My Friend X")] + [TestCase("ThisIsTHEEndMyFriendXYZ", "This Is THE End My Friend XYZ")] + [TestCase("ThisIsTHEEndMyFriendXYZt", "This Is THE End My Friend XY Zt")] + [TestCase("UneÉlévationÀPartir", "Une Élévation À Partir")] + #endregion + public void SplitPascalCasing(string input, string expected) + { + var output = ShortStringHelper.SplitPascalCasing(input, ' '); + Assert.AreEqual(expected, output); + + output = ShortStringHelper.SplitPascalCasing(input, '*'); + expected = expected.Replace(' ', '*'); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("sauté dans l'espace", "saute-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] + [TestCase("sauté dans l'espace", "sauté-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Utf8 | CleanStringType.LowerCase)] + [TestCase("sauté dans l'espace", "SauteDansLEspace", "fr-FR", CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.PascalCase)] + [TestCase("he doesn't want", "he-doesnt-want", null, CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] + [TestCase("he doesn't want", "heDoesntWant", null, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase)] + #endregion + public void CleanStringWithTypeAndCulture(string input, string expected, string culture, CleanStringType stringType) + { + // picks the proper config per culture + // and overrides some stringType params (ascii...) + var output = ShortStringHelper.CleanString(input, stringType, culture); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("foo.txt", "foo.txt")] + [TestCase("foo", "foo")] + [TestCase(".txt", ".txt")] + [TestCase("nag*dog/poo:xit.txt", "nag-dog-poo-xit.txt")] + [TestCase("the dog is in the house.txt", "the-dog-is-in-the-house.txt")] + [TestCase("nil.nil.nil.txt", "nil-nil-nil.txt")] + [TestCase("taradabum", "taradabum")] + [TestCase("tara$$da:b/u (char.IsLetterOrDigit(c) || c == '_') && DefaultShortStringHelper.IsValidFileNameChar(c), - StringType = CleanStringType.LowerCase | CleanStringType.Ascii, - Separator = '-' - }) - .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config - { - PreFilter = StripQuotes, - IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', - StringType = CleanStringType.LowerCase | CleanStringType.Ascii, - Separator = '-' - }) - .WithConfig("fr-FR", CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config - { - PreFilter = FilterFrenchElisions, - IsTerm = (c, leading) => leading ? char.IsLetter(c) : (char.IsLetterOrDigit(c) || c == '_'), - StringType = CleanStringType.LowerCase | CleanStringType.Ascii, - Separator = '-' - }) - .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config - { - PreFilter = StripQuotes, - IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), - StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii - }) - .WithConfig("fr-FR", CleanStringType.Alias, new DefaultShortStringHelperConfig.Config - { - PreFilter = WhiteQuotes, - IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), - StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii - }) - .WithConfig(CleanStringType.ConvertCase, new DefaultShortStringHelperConfig.Config - { - PreFilter = null, - IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore - StringType = CleanStringType.Ascii, - BreakTermsOnUpper = true - })); - - // FIXME: move to a "compose" thing? - Composition.RegisterUnique(f => _helper); - } - - private static readonly Regex FrenchElisionsRegex = new Regex("\\b(c|d|j|l|m|n|qu|s|t)('|\u8217)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static string FilterFrenchElisions(string s) - { - return FrenchElisionsRegex.Replace(s, ""); - } - - private static string StripQuotes(string s) - { - s = s.ReplaceMany(new Dictionary {{"'", ""}, {"\u8217", ""}}); - return s; - } - - private static string WhiteQuotes(string s) - { - s = s.ReplaceMany(new Dictionary { { "'", " " }, { "\u8217", " " } }); - return s; - } [Test] public void U4_4056() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder() - .WithConvertUrlsToAscii("false") - .WithCharCollection(Enumerable.Empty()) - .Build(); + var requestHandlerSettings = new RequestHandlerSettings() + { + CharCollection = Enumerable.Empty(), + ConvertUrlsToAscii = "false" + }; const string input = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page"; @@ -118,10 +42,11 @@ namespace Umbraco.Tests.Strings [Test] public void U4_4056_TryAscii() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder() - .WithConvertUrlsToAscii("false") - .WithCharCollection(Enumerable.Empty()) - .Build(); + var requestHandlerSettings = new RequestHandlerSettings() + { + CharCollection = Enumerable.Empty(), + ConvertUrlsToAscii = "false" + }; const string input1 = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page"; const string input2 = "ÆØÅ and æøå and größer БбДдЖж page"; @@ -144,8 +69,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringUnderscoreInTerm() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is accepted within terms @@ -155,7 +79,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo_bar*nil", helper.CleanString("foo_bar nil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is not accepted within terms @@ -169,8 +93,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringLeadingChars() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // letters and digits are valid leading chars @@ -180,7 +103,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("0123foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // only letters are valid leading chars @@ -191,15 +114,14 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123 foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings)); + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings() )); Assert.AreEqual("child2", helper.CleanStringForSafeAlias("1child2")); } [Test] public void CleanStringTermOnUpper() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -209,7 +131,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*Bar", helper.CleanString("fooBar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -223,8 +145,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringAcronymOnNonUpper() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -237,7 +158,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*BAnil", helper.CleanString("foo BAnil", CleanStringType.Alias)); Assert.AreEqual("foo*Bnil", helper.CleanString("foo Bnil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -254,8 +175,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringGreedyAcronyms() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -268,7 +188,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*BA*nil", helper.CleanString("foo BAnil", CleanStringType.Alias)); Assert.AreEqual("foo*Bnil", helper.CleanString("foo Bnil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -285,8 +205,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringWhiteSpace() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -299,8 +218,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSeparator() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -308,7 +226,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -316,14 +234,14 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged })); Assert.AreEqual("foobar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -335,8 +253,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSymbols() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -390,9 +307,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringEncoding() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -401,7 +316,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("中文测试", helper.CleanString("中文测试", CleanStringType.Alias)); Assert.AreEqual("léger*中文测试*ZÔRG", helper.CleanString("léger 中文测试 ZÔRG", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Ascii | CleanStringType.Unchanged, @@ -414,10 +329,11 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringDefaultConfig() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder() - .WithCharCollection(Enumerable.Empty()) - .WithConvertUrlsToAscii("false") - .Build(); + var requestHandlerSettings = new RequestHandlerSettings() + { + CharCollection = Enumerable.Empty(), + ConvertUrlsToAscii = "false" + }; var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings)); @@ -440,8 +356,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringCasing() { - var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -487,138 +402,29 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("Special Xml Writer", helper.CleanString("special XML writer", CleanStringType.Alias | CleanStringType.PascalCase)); } - #region Cases - [TestCase("foo", "foo")] - [TestCase(" foo ", "foo")] - [TestCase("Foo", "Foo")] - [TestCase("FoO", "FoO")] - [TestCase("FoO bar", "FoOBar")] - [TestCase("FoO bar NIL", "FoOBarNIL")] - [TestCase("FoO 33bar 22NIL", "FoO33bar22NIL")] - [TestCase("FoO 33bar 22NI", "FoO33bar22NI")] - [TestCase("0foo", "foo")] - [TestCase("2foo bar", "fooBar")] - [TestCase("9FOO", "FOO")] - [TestCase("foo-BAR", "fooBAR")] - [TestCase("foo-BA-dang", "fooBADang")] - [TestCase("foo_BAR", "fooBAR")] - [TestCase("foo'BAR", "fooBAR")] - [TestCase("sauté dans l'espace", "sauteDansLespace")] - [TestCase("foo\"\"bar", "fooBar")] - [TestCase("-foo-", "foo")] - [TestCase("_foo_", "foo")] - [TestCase("spécial", "special")] - [TestCase("brô dëk ", "broDek")] - [TestCase("1235brô dëk ", "broDek")] - [TestCase("汉#字*/漢?字", "")] - [TestCase("aa DB cd EFG X KLMN OP qrst", "aaDBCdEFGXKLMNOPQrst")] - [TestCase("AA db cd EFG X KLMN OP qrst", "AADbCdEFGXKLMNOPQrst")] - [TestCase("AAA db cd EFG X KLMN OP qrst", "AAADbCdEFGXKLMNOPQrst")] - [TestCase("4 ways selector", "waysSelector")] - [TestCase("WhatIfWeDoItAgain", "WhatIfWeDoItAgain")] - [TestCase("whatIfWeDoItAgain", "whatIfWeDoItAgain")] - [TestCase("WhatIfWEDOITAgain", "WhatIfWEDOITAgain")] - [TestCase("WhatIfWe doItAgain", "WhatIfWeDoItAgain")] - #endregion - public void CleanStringForSafeAlias(string input, string expected) - { - var output = _helper.CleanStringForSafeAlias(input); - Assert.AreEqual(expected, output); - } + // #region Cases + // [TestCase("This is my_little_house so cute.", "thisIsMyLittleHouseSoCute", false)] + // [TestCase("This is my_little_house so cute.", "thisIsMy_little_houseSoCute", true)] + // [TestCase("This is my_Little_House so cute.", "thisIsMyLittleHouseSoCute", false)] + // [TestCase("This is my_Little_House so cute.", "thisIsMy_Little_HouseSoCute", true)] + // [TestCase("An UPPER_CASE_TEST to check", "anUpperCaseTestToCheck", false)] + // [TestCase("An UPPER_CASE_TEST to check", "anUpper_case_testToCheck", true)] + // [TestCase("Trailing_", "trailing", false)] + // [TestCase("Trailing_", "trailing_", true)] + // [TestCase("_Leading", "leading", false)] + // [TestCase("_Leading", "leading", true)] + // [TestCase("Repeat___Repeat", "repeatRepeat", false)] + // [TestCase("Repeat___Repeat", "repeat___Repeat", true)] + // [TestCase("Repeat___repeat", "repeatRepeat", false)] + // [TestCase("Repeat___repeat", "repeat___repeat", true)] + // #endregion + // public void CleanStringWithUnderscore(string input, string expected, bool allowUnderscoreInTerm) + // { + // var helper = new DefaultShortStringHelper(SettingsForTests.GetDefault()) + // .WithConfig(allowUnderscoreInTerm: allowUnderscoreInTerm); + // var output = helper.CleanString(input, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase); + // Assert.AreEqual(expected, output); + // } - //#region Cases - //[TestCase("This is my_little_house so cute.", "thisIsMyLittleHouseSoCute", false)] - //[TestCase("This is my_little_house so cute.", "thisIsMy_little_houseSoCute", true)] - //[TestCase("This is my_Little_House so cute.", "thisIsMyLittleHouseSoCute", false)] - //[TestCase("This is my_Little_House so cute.", "thisIsMy_Little_HouseSoCute", true)] - //[TestCase("An UPPER_CASE_TEST to check", "anUpperCaseTestToCheck", false)] - //[TestCase("An UPPER_CASE_TEST to check", "anUpper_case_testToCheck", true)] - //[TestCase("Trailing_", "trailing", false)] - //[TestCase("Trailing_", "trailing_", true)] - //[TestCase("_Leading", "leading", false)] - //[TestCase("_Leading", "leading", true)] - //[TestCase("Repeat___Repeat", "repeatRepeat", false)] - //[TestCase("Repeat___Repeat", "repeat___Repeat", true)] - //[TestCase("Repeat___repeat", "repeatRepeat", false)] - //[TestCase("Repeat___repeat", "repeat___repeat", true)] - //#endregion - //public void CleanStringWithUnderscore(string input, string expected, bool allowUnderscoreInTerm) - //{ - // var helper = new DefaultShortStringHelper(SettingsForTests.GetDefault()) - // .WithConfig(allowUnderscoreInTerm: allowUnderscoreInTerm); - // var output = helper.CleanString(input, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase); - // Assert.AreEqual(expected, output); - //} - - #region Cases - [TestCase("Home Page", "home-page")] - [TestCase("Shannon's Home Page!", "shannons-home-page")] - [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-h1z-n")] - [TestCase("Räksmörgås", "raksmorgas")] - [TestCase("'em guys-over there, are#goin' a \"little\"bit crazy eh!! :)", "em-guys-over-there-are-goin-a-little-bit-crazy-eh")] - [TestCase("汉#字*/漢?字", "")] - [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-losk")] - [TestCase("200 ways to be happy", "200-ways-to-be-happy")] - #endregion - public void CleanStringForUrlSegment(string input, string expected) - { - var output = _helper.CleanStringForUrlSegment(input); - Assert.AreEqual(expected, output); - } - - #region Cases - [TestCase("ThisIsTheEndMyFriend", "This Is The End My Friend")] - [TestCase("ThisIsTHEEndMyFriend", "This Is THE End My Friend")] - [TestCase("THISIsTHEEndMyFriend", "THIS Is THE End My Friend")] - [TestCase("This33I33sThe33EndMyFriend", "This33 I33s The33 End My Friend")] // works! - [TestCase("ThisIsTHEEndMyFriendX", "This Is THE End My Friend X")] - [TestCase("ThisIsTHEEndMyFriendXYZ", "This Is THE End My Friend XYZ")] - [TestCase("ThisIsTHEEndMyFriendXYZt", "This Is THE End My Friend XY Zt")] - [TestCase("UneÉlévationÀPartir", "Une Élévation À Partir")] - #endregion - public void SplitPascalCasing(string input, string expected) - { - var output = _helper.SplitPascalCasing(input, ' '); - Assert.AreEqual(expected, output); - - output = _helper.SplitPascalCasing(input, '*'); - expected = expected.Replace(' ', '*'); - Assert.AreEqual(expected, output); - } - - #region Cases - [TestCase("sauté dans l'espace", "saute-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] - [TestCase("sauté dans l'espace", "sauté-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Utf8 | CleanStringType.LowerCase)] - [TestCase("sauté dans l'espace", "SauteDansLEspace", "fr-FR", CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.PascalCase)] - [TestCase("he doesn't want", "he-doesnt-want", null, CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] - [TestCase("he doesn't want", "heDoesntWant", null, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase)] - #endregion - public void CleanStringWithTypeAndCulture(string input, string expected, string culture, CleanStringType stringType) - { - // picks the proper config per culture - // and overrides some stringType params (ascii...) - var output = _helper.CleanString(input, stringType, culture); - Assert.AreEqual(expected, output); - } - - #region Cases - [TestCase("foo.txt", "foo.txt")] - [TestCase("foo", "foo")] - [TestCase(".txt", ".txt")] - [TestCase("nag*dog/poo:xit.txt", "nag-dog-poo-xit.txt")] - [TestCase("the dog is in the house.txt", "the-dog-is-in-the-house.txt")] - [TestCase("nil.nil.nil.txt", "nil-nil-nil.txt")] - [TestCase("taradabum", "taradabum")] - [TestCase("tara$$da:b/u()); Assert.AreEqual(result, output.Success); } @@ -89,37 +88,6 @@ namespace Umbraco.Tests.Strings Assert.AreEqual(cleaned, result); } - [TestCase("This is a string to encrypt")] - [TestCase("This is a string to encrypt\nThis is a second line")] - [TestCase(" White space is preserved ")] - [TestCase("\nWhite space is preserved\n")] - public void Encrypt_And_Decrypt(string input) - { - var encrypted = input.EncryptWithMachineKey(); - var decrypted = encrypted.DecryptWithMachineKey(); - Assert.AreNotEqual(input, encrypted); - Assert.AreEqual(input, decrypted); - } - - [Test()] - public void Encrypt_And_Decrypt_Long_Value() - { - // Generate a really long string - char[] chars = { 'a', 'b', 'c', '1', '2', '3', '\n' }; - - string valueToTest = string.Empty; - - // Create a string 7035 chars long - for (int i = 0; i < 1005; i++) - for (int j = 0; j < chars.Length; j++) - valueToTest += chars[j].ToString(); - - var encrypted = valueToTest.EncryptWithMachineKey(); - var decrypted = encrypted.DecryptWithMachineKey(); - Assert.AreNotEqual(valueToTest, encrypted); - Assert.AreEqual(valueToTest, decrypted); - } - [TestCase("Hello this is my string", " string", "Hello this is my")] [TestCase("Hello this is my string strung", " string", "Hello this is my string strung")] [TestCase("Hello this is my string string", " string", "Hello this is my")] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs new file mode 100644 index 0000000000..4de74b2828 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs @@ -0,0 +1,42 @@ +using System.ComponentModel.DataAnnotations; +using NUnit.Framework; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Strings +{ + [TestFixture] + public class StringValidationTests + { + [TestCase("someone@somewhere.com", ExpectedResult = true)] + [TestCase("someone@somewhere.co.uk", ExpectedResult = true)] + [TestCase("someone+tag@somewhere.net", ExpectedResult = true)] + [TestCase("futureTLD@somewhere.fooo", ExpectedResult = true)] + + [TestCase("abc@xyz.financial", ExpectedResult = true)] + [TestCase("admin+gmail-syntax@c.pizza", ExpectedResult = true)] + [TestCase("admin@c.pizza", ExpectedResult = true)] + + [TestCase("fdsa", ExpectedResult = false)] + [TestCase("fdsa@", ExpectedResult = false)] + + // IsValid can be either a powerful regex OR a dummy test, + // and by default it depends on System.ComponentModel.DataAnnotations.AppSettings.DisableRegEx + // which ends up using BinaryCompatibility.Current.TargetsAtLeastFramework472 so for some reason + // in 472 we are not using the regex anymore + // + // it can be forced, though with an app settings + // dataAnnotations:dataTypeAttribute:disableRegEx = false + // + // since Umbraco is now 4.7.2+, the setting is required for the following tests to pass + + //[TestCase("fdsa@fdsa", ExpectedResult = false)] + //[TestCase("fdsa@fdsa.", ExpectedResult = false)] + public bool Validate_Email_Address(string input) + { + var foo = new EmailAddressAttribute(); + + return foo.IsValid(input); + } + } +} diff --git a/src/Umbraco.Tests/Strings/StylesheetHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs similarity index 97% rename from src/Umbraco.Tests/Strings/StylesheetHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs index 5ae4c0511f..46efce7a5b 100644 --- a/src/Umbraco.Tests/Strings/StylesheetHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs @@ -1,15 +1,12 @@ using System.Linq; -using System.Text; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Strings.Css; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.Strings { [TestFixture] - public class StylesheetHelperTests : UmbracoTestBase + public class StylesheetHelperTests { [Test] public void Replace_Rule() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj index d22ca002a1..a0be703791 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj @@ -21,4 +21,5 @@ + diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 593a581f85..1a1f854e5e 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -9,7 +9,6 @@ using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs index e811d06db1..b8868a8d0d 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; using ILogger = Umbraco.Core.Logging.ILogger; using Current = Umbraco.Web.Composing.Current; @@ -37,7 +38,7 @@ namespace Umbraco.Tests.Models var dataEditors = new DataEditorCollection(new IDataEditor[] { - new DataEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { Alias = "editor", ExplicitValueEditor = TestHelper.CreateDataValueEditor("view") } + new DataEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { Alias = "editor", ExplicitValueEditor = MockedValueEditors.CreateDataValueEditor("view") } }); var propertyEditors = new PropertyEditorCollection(dataEditors); diff --git a/src/Umbraco.Tests/Published/ConvertersTests.cs b/src/Umbraco.Tests/Published/ConvertersTests.cs index 5f1fd7c3fd..21f7be9a54 100644 --- a/src/Umbraco.Tests/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests/Published/ConvertersTests.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -15,165 +16,13 @@ using Umbraco.Core.Strings; using Umbraco.Tests.Components; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { [TestFixture] - public class ConvertersTests : UmbracoTestBase + public class ConvertersTests { - #region SimpleConverter1 - - [Test] - public void SimpleConverter1Test() - { - var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] - { - new SimpleConverter1(), - }); - - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); - - var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); - - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) - { - yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); - } - - var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); - - var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - - Assert.AreEqual(1234, element1.Value("prop1")); - - // 'null' would be considered a 'missing' value by the default, magic logic - var e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", null } }, false); - Assert.IsFalse(e.HasValue("prop1")); - - // '0' would not - it's a valid integer - but the converter knows better - e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "0" } }, false); - Assert.IsFalse(e.HasValue("prop1")); - } - - private class SimpleConverter1 : IPropertyValueConverter - { - public bool? IsValue(object value, PropertyValueLevel level) - { - switch (level) - { - case PropertyValueLevel.Source: - return null; - case PropertyValueLevel.Inter: - return value is int ivalue && ivalue != 0; - default: - throw new NotSupportedException($"Invalid level: {level}."); - } - } - - public bool IsConverter(IPublishedPropertyType propertyType) - => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); - - public Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof(int); - - public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - => PropertyCacheLevel.Element; - - public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - => int.TryParse(source as string, out int i) ? i : 0; - - public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => (int)inter; - - public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => ((int)inter).ToString(); - } - - #endregion - - #region SimpleConverter2 - - [Test] - public void SimpleConverter2Test() - { - var cacheMock = new Mock(); - var cacheContent = new Dictionary(); - cacheMock.Setup(x => x.GetById(It.IsAny())).Returns(id => cacheContent.TryGetValue(id, out IPublishedContent content) ? content : null); - var publishedSnapshotMock = new Mock(); - publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); - var publishedSnapshotAccessorMock = new Mock(); - publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); - var publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; - - var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] - { - new SimpleConverter2(publishedSnapshotAccessor), - }); - - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); - - var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); - - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) - { - yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); - } - - var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); - - var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - - var cntType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1001, "cnt1", t => Enumerable.Empty()); - var cnt1 = new SolidPublishedContent(cntType1) { Id = 1234 }; - cacheContent[cnt1.Id] = cnt1; - - Assert.AreSame(cnt1, element1.Value("prop1")); - } - - private class SimpleConverter2 : IPropertyValueConverter - { - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly PropertyCacheLevel _cacheLevel; - - public SimpleConverter2(IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel cacheLevel = PropertyCacheLevel.None) - { - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _cacheLevel = cacheLevel; - } - - public bool? IsValue(object value, PropertyValueLevel level) - => value != null && (!(value is string) || string.IsNullOrWhiteSpace((string)value) == false); - - public bool IsConverter(IPublishedPropertyType propertyType) - => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); - - public Type GetPropertyValueType(IPublishedPropertyType propertyType) - // the first version would be the "generic" version, but say we want to be more precise - // and return: whatever Clr type is generated for content type with alias "cnt1" -- which - // we cannot really typeof() at the moment because it has not been generated, hence ModelType. - // => typeof (IPublishedContent); - => ModelType.For("cnt1"); - - public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - => _cacheLevel; - - public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - => int.TryParse(source as string, out int i) ? i : -1; - - public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById((int)inter); - - public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => ((int)inter).ToString(); - } - - #endregion - #region SimpleConverter3 [Test] @@ -182,10 +31,10 @@ namespace Umbraco.Tests.Published // Current.Reset(); var register = TestHelper.GetRegister(); - var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), Mock.Of(), AppCaches.NoCache); composition.WithCollectionBuilder() - .Append() + .Append() .Append(); IPublishedModelFactory factory = new PublishedModelFactory(new[] @@ -208,11 +57,17 @@ namespace Umbraco.Tests.Published var converters = registerFactory.GetInstance(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }, - new DataType(new VoidEditor("2", Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of(), Mock.Of())) { Id = 2 }); + var dataTypeServiceMock = new Mock(); + var dataType1 = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + var dataType2 = new DataType(new VoidEditor("2", Mock.Of(), Mock.Of(), + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 2 }; - var contentTypeFactory = new PublishedContentTypeFactory(factory, converters, dataTypeService); + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new []{dataType1, dataType2 }); + + var contentTypeFactory = new PublishedContentTypeFactory(factory, converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType, int i) { @@ -258,8 +113,8 @@ namespace Umbraco.Tests.Published var mmodel2 = (PublishedSnapshotTestObjects.TestElementModel2)model2; // and get direct property - Assert.IsInstanceOf(model2.Value("prop2")); - Assert.AreEqual(1, ((PublishedSnapshotTestObjects.TestContentModel1[])model2.Value("prop2")).Length); + Assert.IsInstanceOf(model2.Value(Mock.Of(), "prop2")); + Assert.AreEqual(1, ((PublishedSnapshotTestObjects.TestContentModel1[])model2.Value(Mock.Of(), "prop2")).Length); // and get model property Assert.IsInstanceOf>(mmodel2.Prop2); diff --git a/src/Umbraco.Tests/Published/ModelTypeTests.cs b/src/Umbraco.Tests/Published/ModelTypeTests.cs index f698c20fa2..43639c88a1 100644 --- a/src/Umbraco.Tests/Published/ModelTypeTests.cs +++ b/src/Umbraco.Tests/Published/ModelTypeTests.cs @@ -8,38 +8,21 @@ namespace Umbraco.Tests.Published [TestFixture] public class ModelTypeTests { - [Test] - public void ModelTypeEqualityTests() - { - Assert.AreNotEqual(ModelType.For("alias1"), ModelType.For("alias1")); - - Assert.IsTrue(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias1"))); - Assert.IsFalse(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias2"))); - - Assert.IsTrue(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")))); - Assert.IsFalse(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias2")))); - - Assert.IsTrue(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias1").MakeArrayType())); - Assert.IsFalse(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias2").MakeArrayType())); - } + //TODO these is not easy to move to the Unittest project due to underlysing NotImplementedException of Type.IsSZArray [Test] public void ModelTypeToStringTests() { - Assert.AreEqual("{alias1}", ModelType.For("alias1").ToString()); + var modelType = ModelType.For("alias1"); + var modelTypeArray = modelType.MakeArrayType(); + + Assert.AreEqual("{alias1}", modelType.ToString()); // there's an "*" there because the arrays are not true SZArray - but that changes when we map - Assert.AreEqual("{alias1}[*]", ModelType.For("alias1").MakeArrayType().ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[{alias1}[*]]", typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()).ToString()); - } - [Test] - public void TypeToStringTests() - { - var type = typeof(int); - Assert.AreEqual("System.Int32", type.ToString()); - Assert.AreEqual("System.Int32[]", type.MakeArrayType().ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[System.Int32[]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).ToString()); + Assert.AreEqual("{alias1}[*]", modelTypeArray.ToString()); + var enumArray = typeof(IEnumerable<>).MakeGenericType(modelTypeArray); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[{alias1}[*]]", enumArray.ToString()); } [Test] @@ -56,33 +39,5 @@ namespace Umbraco.Tests.Published Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[{alias1}[*], Umbraco.Core, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null]]", typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()).FullName); } - [Test] - public void TypeFullNameTests() - { - var type = typeof(int); - Assert.AreEqual("System.Int32", type.FullName); - Assert.AreEqual("System.Int32[]", type.MakeArrayType().FullName); - // note the inner assembly qualified name - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.Int32[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).FullName); - } - - [Test] - public void ModelTypeMapTests() - { - var map = new Dictionary - { - { "alias1", typeof (PublishedSnapshotTestObjects.TestElementModel1) }, - { "alias2", typeof (PublishedSnapshotTestObjects.TestElementModel2) }, - }; - - Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1", - ModelType.Map(ModelType.For("alias1"), map).ToString()); - Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]", - ModelType.Map(ModelType.For("alias1").MakeArrayType(), map).ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1]", - ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), map).ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]]", - ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()), map).ToString()); - } } } diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index e50d6fe8ab..42eb083667 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -20,7 +20,6 @@ using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -163,7 +162,7 @@ namespace Umbraco.Tests.PublishedContent PublishedModelFactory, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), hostingEnvironment, - new MockShortStringHelper(), + Mock.Of(), TestHelper.IOHelper, Options.Create(nuCacheSettings)); diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 010569fe42..f21ad1a3db 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -18,7 +18,6 @@ using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -203,7 +202,7 @@ namespace Umbraco.Tests.PublishedContent publishedModelFactory, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), TestHelper.GetHostingEnvironment(), - new MockShortStringHelper(), + Mock.Of(), TestHelper.IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index 5ce63874bc..0052ebe792 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -18,7 +18,7 @@ using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.PublishedContent { - class SolidPublishedSnapshot : IPublishedSnapshot + public class SolidPublishedSnapshot : IPublishedSnapshot { public readonly SolidPublishedContentCache InnerContentCache = new SolidPublishedContentCache(); public readonly SolidPublishedContentCache InnerMediaCache = new SolidPublishedContentCache(); @@ -47,7 +47,7 @@ namespace Umbraco.Tests.PublishedContent { } } - class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache + public class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache { private readonly Dictionary _content = new Dictionary(); @@ -164,7 +164,7 @@ namespace Umbraco.Tests.PublishedContent } } - internal class SolidPublishedContent : IPublishedContent + public class SolidPublishedContent : IPublishedContent { #region Constructor @@ -264,7 +264,7 @@ namespace Umbraco.Tests.PublishedContent #endregion } - internal class SolidPublishedProperty : IPublishedProperty + public class SolidPublishedProperty : IPublishedProperty { public IPublishedPropertyType PropertyType { get; set; } public string Alias { get; set; } @@ -279,7 +279,7 @@ namespace Umbraco.Tests.PublishedContent public virtual bool HasValue(string culture = null, string segment = null) => SolidHasValue; } - internal class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty + public class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty { private readonly IDictionary _solidSourceValues = new Dictionary(); private readonly IDictionary _solidValues = new Dictionary(); @@ -356,7 +356,7 @@ namespace Umbraco.Tests.PublishedContent } [PublishedModel("ContentType2")] - internal class ContentType2 : PublishedContentModel + public class ContentType2 : PublishedContentModel { #region Plumbing @@ -366,11 +366,11 @@ namespace Umbraco.Tests.PublishedContent #endregion - public int Prop1 => this.Value("prop1"); + public int Prop1 => this.Value(Mock.Of(), "prop1"); } [PublishedModel("ContentType2Sub")] - internal class ContentType2Sub : ContentType2 + public class ContentType2Sub : ContentType2 { #region Plumbing @@ -381,43 +381,46 @@ namespace Umbraco.Tests.PublishedContent #endregion } - internal class PublishedContentStrong1 : PublishedContentModel + public class PublishedContentStrong1 : PublishedContentModel { public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } - public int StrongValue => this.Value("strongValue"); + public int StrongValue => this.Value(Mock.Of(), "strongValue"); } - internal class PublishedContentStrong1Sub : PublishedContentStrong1 + public class PublishedContentStrong1Sub : PublishedContentStrong1 { public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback) : base(content, fallback) { } - public int AnotherValue => this.Value("anotherValue"); + public int AnotherValue => this.Value(Mock.Of(), "anotherValue"); } - internal class PublishedContentStrong2 : PublishedContentModel + public class PublishedContentStrong2 : PublishedContentModel { public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } - public int StrongValue => this.Value("strongValue"); + public int StrongValue => this.Value(Mock.Of(), "strongValue"); } - internal class AutoPublishedContentType : PublishedContentType + public class AutoPublishedContentType : PublishedContentType { private static readonly IPublishedPropertyType Default; static AutoPublishedContentType() { - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 666 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 666 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); + var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeServiceMock.Object); Default = factory.CreatePropertyType("*", 666); } diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index edd4d38075..a669e543f2 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -1,17 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Web.Routing; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; -using Umbraco.Core.Install; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -22,16 +16,13 @@ using Umbraco.Core.Strings; using Umbraco.Core.Sync; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; -using Umbraco.Web.Routing; using Umbraco.Web.Security; using Current = Umbraco.Web.Composing.Current; @@ -110,7 +101,7 @@ namespace Umbraco.Tests.Scoping new NoopPublishedModelFactory(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), hostingEnvironment, - new MockShortStringHelper(), + Mock.Of(), IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); } diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index bef6fde816..7e88e85360 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -10,7 +10,6 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.Install; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -21,7 +20,6 @@ using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Sync; using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -82,7 +80,7 @@ namespace Umbraco.Tests.Services Mock.Of(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), hostingEnvironment, - new MockShortStringHelper(), + Mock.Of(), IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); } diff --git a/src/Umbraco.Tests/Strings/StringValidationTests.cs b/src/Umbraco.Tests/Strings/StringValidationTests.cs deleted file mode 100644 index b76783080b..0000000000 --- a/src/Umbraco.Tests/Strings/StringValidationTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using NUnit.Framework; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Strings -{ - [TestFixture] - public class StringValidationTests : UmbracoTestBase - { - [Test] - public void Validate_Email_Address() - { - var foo = new EmailAddressAttribute(); - - Assert.IsTrue(foo.IsValid("someone@somewhere.com")); - Assert.IsTrue(foo.IsValid("someone@somewhere.co.uk")); - Assert.IsTrue(foo.IsValid("someone+tag@somewhere.net")); - Assert.IsTrue(foo.IsValid("futureTLD@somewhere.fooo")); - - Assert.IsTrue(foo.IsValid("abc@xyz.financial")); - Assert.IsTrue(foo.IsValid("admin+gmail-syntax@c.pizza")); - Assert.IsTrue(foo.IsValid("admin@c.pizza")); - - Assert.IsFalse(foo.IsValid("fdsa")); - Assert.IsFalse(foo.IsValid("fdsa@")); - - // IsValid can be either a powerful regex OR a dummy test, - // and by default it depends on System.ComponentModel.DataAnnotations.AppSettings.DisableRegEx - // which ends up using BinaryCompatibility.Current.TargetsAtLeastFramework472 so for some reason - // in 472 we are not using the regex anymore - // - // it can be forced, though with an app settings - // dataAnnotations:dataTypeAttribute:disableRegEx = false - // - // since Umbraco is now 4.7.2+, the setting is required for the following tests to pass - - Assert.IsFalse(foo.IsValid("fdsa@fdsa")); - Assert.IsFalse(foo.IsValid("fdsa@fdsa.")); - - } - } -} diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index 760fb7dbaa..041c9d0c21 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -303,25 +303,6 @@ namespace Umbraco.Tests.TestHelpers } } - // TODO: Move to MockedValueEditors.cs - public static DataValueEditor CreateDataValueEditor(string name) - { - var valueType = (ValueTypes.IsValue(name)) ? name : ValueTypes.String; - - return new DataValueEditor( - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - new DataEditorAttribute(name, name, name) - { - ValueType = valueType - } - - ); - } - - public static IUmbracoVersion GetUmbracoVersion() => _testHelperInternal.GetUmbracoVersion(); public static IRegister GetRegister() => _testHelperInternal.GetRegister(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 80b2329d8b..8e69230799 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -121,9 +121,7 @@ - - @@ -135,6 +133,9 @@ + + + @@ -145,14 +146,9 @@ - - - - - @@ -172,10 +168,6 @@ - - - - @@ -183,7 +175,6 @@ - @@ -221,10 +212,8 @@ - - @@ -253,9 +242,6 @@ - - - @@ -278,7 +264,6 @@ - @@ -289,10 +274,6 @@ - - - - @@ -311,11 +292,7 @@ - - - - True @@ -341,7 +318,6 @@ - @@ -367,7 +343,6 @@ - @@ -421,7 +396,6 @@ - diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 7ef41e847e..739bd2c95e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -148,9 +148,6 @@ - - - @@ -184,7 +181,6 @@ -