From 6a5bfcaa9c7eb6f04fc124bdb72aba3f5dcc9fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 21 Aug 2020 10:09:15 +0200 Subject: [PATCH 01/53] first take on umb-property-info-button --- src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../umb-property-info-button.html | 5 + .../umb-property-info-button.less | 101 ++++++++++++++++++ .../umbpropertyinfobutton.component.js | 35 ++++++ .../blocklist.blockconfiguration.overlay.html | 1 + 5 files changed, 143 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umbpropertyinfobutton.component.js diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index cdccbf527b..1eea02d1d6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -202,6 +202,7 @@ // Property Editors @import "../views/components/blockcard/umb-block-card-grid.less"; @import "../views/components/blockcard/umb-block-card.less"; +@import "../views/components/umb-property-info-button/umb-property-info-button.less"; @import "../views/propertyeditors/blocklist/umb-block-list-property-editor.less"; @import "../views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.less"; @import "../views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.less"; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.html new file mode 100644 index 0000000000..aca2858070 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.html @@ -0,0 +1,5 @@ + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less new file mode 100644 index 0000000000..19399d128e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less @@ -0,0 +1,101 @@ +umb-property-info-button { + position: relative; + display: inline-block; + vertical-align: text-bottom; + + .control-label + & { + margin-left: -8px; + } + + > .__button { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + + width: 16px; + height: 16px; + padding-left: 1px; + font-size: 12px; + font-weight: 700; + + border-radius: 50%; + border: 1px solid @ui-option-type; + box-shadow: 0 0 2px @ui-option-type; + color: @ui-option-type; + &:hover { + border-color: @ui-option-type-hover; + color: @ui-option-type-hover; + } + } + + > .__tooltip { + + position: absolute; + z-index: 1000; + top: 26px; + left: -6px; + font-size: @fontSizeSmall; + + border-radius: 6px; + + min-width: 240px; + max-width: 320px; + padding: 5px 10px; + background-color: @blueExtraDark; + color: white; + box-shadow: 0 3px 6px rgba(@blueDark, .24); + + a { + color: white; + text-decoration: underline; + &:hover { + color: @blueMidLight; + } + } + + &::before { + content:''; + position: absolute; + color: @blueExtraDark; + top: -4px; + left: 10px; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-bottom: 4px solid; + } + } + +} + +// hide umb-info-button if inside umb-property +.umb-property umb-property-info-button { + opacity: 0; +} + +.umb-property:focus-within umb-property-info-button, +.umb-property:hover umb-property-info-button, +.umb-property umb-property-info-button:focus { + opacity: 1; +} +// Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered. +.umb-property:hover .umb-property:not(:hover) umb-property-info-button { + opacity: 0; +} + +// hide umb-info-button if inside +.umb-control-group umb-property-info-button { + opacity: 0; +} + +.umb-control-group:focus-within umb-property-info-button, +.umb-control-group:hover umb-property-info-button, +.umb-control-group umb-property-info-button:focus { + opacity: 1; +} +// Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered. +.umb-control-group:hover .umb-control-group:not(:hover) umb-property-info-button { + opacity: 0; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umbpropertyinfobutton.component.js b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umbpropertyinfobutton.component.js new file mode 100644 index 0000000000..e160071ea2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umbpropertyinfobutton.component.js @@ -0,0 +1,35 @@ +(function () { + 'use strict'; + + angular + .module('umbraco') + .component('umbPropertyInfoButton', { + templateUrl: 'views/components/umb-property-info-button/umb-property-info-button.html', + controller: UmbPropertyInfoButtonController, + controllerAs: 'vm', + transclude: true, + bindings: { + buttonTitle: "@?", + symbol: "@?" + } + }); + + function UmbPropertyInfoButtonController() { + + var vm = this; + vm.show = false; + + vm.onMouseClick = function ($event) { + vm.show = !vm.show; + }; + vm.onMouseClickOutside = function ($event) { + vm.show = false; + }; + + vm.$onInit = function() { + vm.symbol = vm.symbol || "i"; + }; + + } + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html index af458f6a13..08a574fdca 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html @@ -37,6 +37,7 @@
+ Overwrite how this block appears in the BackOffice UI. Pick a .html file containing your presentation. Read more on Our
From 9882edeca098bcae9f96384f5af87cf216e671e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 16 Sep 2020 14:54:25 +0200 Subject: [PATCH 02/53] added translation to demo implementation --- .../umb-property-info-button.less | 32 ++++++++++--------- .../blocklist.blockconfiguration.overlay.html | 2 +- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 2 ++ src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 ++ .../Umbraco/config/lang/en_us.xml | 2 ++ 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less index 19399d128e..1d8588caca 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-property-info-button/umb-property-info-button.less @@ -13,15 +13,16 @@ umb-property-info-button { align-items: center; justify-content: center; - width: 16px; - height: 16px; + width: 15px; + height: 15px; + padding-top: 1px; padding-left: 1px; + margin-top: -1px; font-size: 12px; font-weight: 700; border-radius: 50%; border: 1px solid @ui-option-type; - box-shadow: 0 0 2px @ui-option-type; color: @ui-option-type; &:hover { border-color: @ui-option-type-hover; @@ -34,17 +35,18 @@ umb-property-info-button { position: absolute; z-index: 1000; top: 26px; - left: -6px; - font-size: @fontSizeSmall; + left: -8px; + font-size: 13px; border-radius: 6px; min-width: 240px; max-width: 320px; - padding: 5px 10px; - background-color: @blueExtraDark; + padding: 10px 16px; + background-color:@blueExtraDark; + border: 1px solid @blueExtraDark; color: white; - box-shadow: 0 3px 6px rgba(@blueDark, .24); + box-shadow: 0 2px 6px rgba(@blueExtraDark, .6); a { color: white; @@ -57,14 +59,14 @@ umb-property-info-button { &::before { content:''; position: absolute; - color: @blueExtraDark; - top: -4px; + transform: rotate(45deg); + background-color:@blueExtraDark; + top: -5px; left: 10px; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-bottom: 4px solid; + width: 8px; + height: 8px; + border-left: 1px solid @blueExtraDark; + border-top: 1px solid @blueExtraDark; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html index 08a574fdca..1975ae6b5e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.html @@ -37,7 +37,7 @@
- Overwrite how this block appears in the BackOffice UI. Pick a .html file containing your presentation. Read more on Our + Overwrite how this block appears in the BackOffice UI. Pick a .html file containing your presentation.
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index 997fa577b7..0519995ad8 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -1837,6 +1837,8 @@ Mange hilsner fra Umbraco robotten Indholds model Label Speciel visning + Vis speciel visning beskrivelsen + Overskrift hvordan denne block præsenteres i BackOffice interfacet. Vælg en .html fil der indeholder din præsensation. Indstillings model Rederings lagets størrelse Tilføj speciel visning diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index d72ee33d6c..2e53ea89b3 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -2453,6 +2453,8 @@ To manage your website, simply open the Umbraco back office and start adding con Content model Label Custom view + Show custom view description + Overwrite how this block appears in the BackOffice UI. Pick a .html file containing your presentation. Settings model Overlay editor size Add custom view diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index cb31695268..f9e122c6c6 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -2473,6 +2473,8 @@ To manage your website, simply open the Umbraco back office and start adding con Content model Label Custom view + Show custom view description + Overwrite how this block appears in the BackOffice UI. Pick a .html file containing your presentation. Settings model Overlay editor size Add custom view From 59784a155150cd1785d701d5e681aa0ea663dab3 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 17 Sep 2020 13:50:37 +0200 Subject: [PATCH 03/53] Update noUiSlider to v14.6.2 --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index e0afe1c2a7..37a2de77f6 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -38,7 +38,7 @@ "lazyload-js": "1.0.0", "moment": "2.22.2", "ng-file-upload": "12.2.13", - "nouislider": "14.6.1", + "nouislider": "14.6.2", "npm": "^6.14.7", "signalr": "2.4.0", "spectrum-colorpicker2": "2.0.3", From 0531fce9e2ca7abaf6bf588df97ce4f570941c67 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 23 Sep 2020 16:20:18 +0200 Subject: [PATCH 04/53] Move the IIconService and IconModel to the Umbraco.Core project See issue #8919 --- src/{Umbraco.Web => Umbraco.Core}/Models/IconModel.cs | 2 +- .../Services/IIconService.cs | 4 ++-- src/Umbraco.Core/Umbraco.Core.csproj | 2 ++ src/Umbraco.Web/Editors/BackOfficeModel.cs | 2 +- src/Umbraco.Web/Editors/BackOfficePreviewModel.cs | 3 +-- src/Umbraco.Web/Editors/IconController.cs | 4 ++-- src/Umbraco.Web/Services/IconService.cs | 11 ++++++----- src/Umbraco.Web/Umbraco.Web.csproj | 2 -- 8 files changed, 15 insertions(+), 15 deletions(-) rename src/{Umbraco.Web => Umbraco.Core}/Models/IconModel.cs (79%) rename src/{Umbraco.Web => Umbraco.Core}/Services/IIconService.cs (90%) diff --git a/src/Umbraco.Web/Models/IconModel.cs b/src/Umbraco.Core/Models/IconModel.cs similarity index 79% rename from src/Umbraco.Web/Models/IconModel.cs rename to src/Umbraco.Core/Models/IconModel.cs index 5c79ad6219..0de44301bb 100644 --- a/src/Umbraco.Web/Models/IconModel.cs +++ b/src/Umbraco.Core/Models/IconModel.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models { public class IconModel { diff --git a/src/Umbraco.Web/Services/IIconService.cs b/src/Umbraco.Core/Services/IIconService.cs similarity index 90% rename from src/Umbraco.Web/Services/IIconService.cs rename to src/Umbraco.Core/Services/IIconService.cs index 177921ceae..963edb22a5 100644 --- a/src/Umbraco.Web/Services/IIconService.cs +++ b/src/Umbraco.Core/Services/IIconService.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using Umbraco.Web.Models; +using Umbraco.Core.Models; -namespace Umbraco.Web.Services +namespace Umbraco.Core.Services { public interface IIconService { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f80784f12a..b7b9867618 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -143,12 +143,14 @@ + + diff --git a/src/Umbraco.Web/Editors/BackOfficeModel.cs b/src/Umbraco.Web/Editors/BackOfficeModel.cs index b620d893e3..cbdafd2e94 100644 --- a/src/Umbraco.Web/Editors/BackOfficeModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficeModel.cs @@ -1,8 +1,8 @@ using System; using Umbraco.Core.Configuration; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Features; -using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs index 7239bba8f7..cc7356b687 100644 --- a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; - using Umbraco.Core.Configuration; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Features; -using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/IconController.cs b/src/Umbraco.Web/Editors/IconController.cs index b45b0948c8..87303a4e62 100644 --- a/src/Umbraco.Web/Editors/IconController.cs +++ b/src/Umbraco.Web/Editors/IconController.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Web.Models; -using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Services/IconService.cs b/src/Umbraco.Web/Services/IconService.cs index 93389668b6..206af296f9 100644 --- a/src/Umbraco.Web/Services/IconService.cs +++ b/src/Umbraco.Web/Services/IconService.cs @@ -5,7 +5,8 @@ using Ganss.XSS; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.IO; -using Umbraco.Web.Models; +using Umbraco.Core.Models; +using Umbraco.Core.Services; namespace Umbraco.Web.Services { @@ -68,13 +69,13 @@ namespace Umbraco.Web.Services 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); + sanitizer.AllowedAttributes.UnionWith(Constants.SvgSanitizer.Attributes); + sanitizer.AllowedCssProperties.UnionWith(Constants.SvgSanitizer.Attributes); + sanitizer.AllowedTags.UnionWith(Constants.SvgSanitizer.Tags); try { - var svgContent = File.ReadAllText(iconPath); + var svgContent = System.IO.File.ReadAllText(iconPath); var sanitizedString = sanitizer.Sanitize(svgContent); var svg = new IconModel diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3187f2b371..c3eba87d6f 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -239,7 +239,6 @@ - @@ -290,7 +289,6 @@ - From fe3f60412208473fc94c899917036028788262c0 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 23 Sep 2020 16:20:18 +0200 Subject: [PATCH 05/53] Move the IIconService and IconModel to the Umbraco.Core project See issue #8919 (cherry picked from commit 0531fce9e2ca7abaf6bf588df97ce4f570941c67) --- src/{Umbraco.Web => Umbraco.Core}/Models/IconModel.cs | 2 +- .../Services/IIconService.cs | 4 ++-- src/Umbraco.Core/Umbraco.Core.csproj | 2 ++ src/Umbraco.Web/Editors/BackOfficeModel.cs | 2 +- src/Umbraco.Web/Editors/BackOfficePreviewModel.cs | 3 +-- src/Umbraco.Web/Editors/IconController.cs | 4 ++-- src/Umbraco.Web/Services/IconService.cs | 11 ++++++----- src/Umbraco.Web/Umbraco.Web.csproj | 2 -- 8 files changed, 15 insertions(+), 15 deletions(-) rename src/{Umbraco.Web => Umbraco.Core}/Models/IconModel.cs (79%) rename src/{Umbraco.Web => Umbraco.Core}/Services/IIconService.cs (90%) diff --git a/src/Umbraco.Web/Models/IconModel.cs b/src/Umbraco.Core/Models/IconModel.cs similarity index 79% rename from src/Umbraco.Web/Models/IconModel.cs rename to src/Umbraco.Core/Models/IconModel.cs index 5c79ad6219..0de44301bb 100644 --- a/src/Umbraco.Web/Models/IconModel.cs +++ b/src/Umbraco.Core/Models/IconModel.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models { public class IconModel { diff --git a/src/Umbraco.Web/Services/IIconService.cs b/src/Umbraco.Core/Services/IIconService.cs similarity index 90% rename from src/Umbraco.Web/Services/IIconService.cs rename to src/Umbraco.Core/Services/IIconService.cs index 177921ceae..963edb22a5 100644 --- a/src/Umbraco.Web/Services/IIconService.cs +++ b/src/Umbraco.Core/Services/IIconService.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using Umbraco.Web.Models; +using Umbraco.Core.Models; -namespace Umbraco.Web.Services +namespace Umbraco.Core.Services { public interface IIconService { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f80784f12a..b7b9867618 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -143,12 +143,14 @@ + + diff --git a/src/Umbraco.Web/Editors/BackOfficeModel.cs b/src/Umbraco.Web/Editors/BackOfficeModel.cs index b620d893e3..cbdafd2e94 100644 --- a/src/Umbraco.Web/Editors/BackOfficeModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficeModel.cs @@ -1,8 +1,8 @@ using System; using Umbraco.Core.Configuration; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Features; -using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs index 7239bba8f7..cc7356b687 100644 --- a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; - using Umbraco.Core.Configuration; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Features; -using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/IconController.cs b/src/Umbraco.Web/Editors/IconController.cs index b45b0948c8..87303a4e62 100644 --- a/src/Umbraco.Web/Editors/IconController.cs +++ b/src/Umbraco.Web/Editors/IconController.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Web.Models; -using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Services/IconService.cs b/src/Umbraco.Web/Services/IconService.cs index 93389668b6..206af296f9 100644 --- a/src/Umbraco.Web/Services/IconService.cs +++ b/src/Umbraco.Web/Services/IconService.cs @@ -5,7 +5,8 @@ using Ganss.XSS; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.IO; -using Umbraco.Web.Models; +using Umbraco.Core.Models; +using Umbraco.Core.Services; namespace Umbraco.Web.Services { @@ -68,13 +69,13 @@ namespace Umbraco.Web.Services 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); + sanitizer.AllowedAttributes.UnionWith(Constants.SvgSanitizer.Attributes); + sanitizer.AllowedCssProperties.UnionWith(Constants.SvgSanitizer.Attributes); + sanitizer.AllowedTags.UnionWith(Constants.SvgSanitizer.Tags); try { - var svgContent = File.ReadAllText(iconPath); + var svgContent = System.IO.File.ReadAllText(iconPath); var sanitizedString = sanitizer.Sanitize(svgContent); var svg = new IconModel diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3187f2b371..c3eba87d6f 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -239,7 +239,6 @@ - @@ -290,7 +289,6 @@ - From 5ed94065a71fb438ddeda5b431cb1d6153d20da8 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Sep 2020 18:45:26 +1000 Subject: [PATCH 06/53] Fixes issue with exceptions in logs because we are trying to unbind from httpapplication events but you cannot do that. --- .../Logging/WebProfilerComponent.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web/Logging/WebProfilerComponent.cs b/src/Umbraco.Web/Logging/WebProfilerComponent.cs index 1cb2142199..ff25eb6a22 100755 --- a/src/Umbraco.Web/Logging/WebProfilerComponent.cs +++ b/src/Umbraco.Web/Logging/WebProfilerComponent.cs @@ -10,7 +10,6 @@ namespace Umbraco.Web.Logging { private readonly WebProfiler _profiler; private readonly bool _profile; - private readonly List _terminate = new List(); public WebProfilerComponent(IProfiler profiler, ILogger logger) { @@ -39,21 +38,20 @@ namespace Umbraco.Web.Logging public void Terminate() { UmbracoApplicationBase.ApplicationInit -= InitializeApplication; - foreach (var t in _terminate) t(); } private void InitializeApplication(object sender, EventArgs args) { if (!(sender is HttpApplication app)) return; - // for *each* application (this will run more than once) - void beginRequest(object s, EventArgs a) => _profiler.UmbracoApplicationBeginRequest(s, a); - app.BeginRequest += beginRequest; - _terminate.Add(() => app.BeginRequest -= beginRequest); - - void endRequest(object s, EventArgs a) => _profiler.UmbracoApplicationEndRequest(s, a); - app.EndRequest += endRequest; - _terminate.Add(() => app.EndRequest -= endRequest); + // NOTE: We do not unbind these events ... because you just can't do that for HttpApplication events, they will + // be removed when the app dies. + app.BeginRequest += BeginRequest; + app.EndRequest += EndRequest; } + + private void BeginRequest(object s, EventArgs a) => _profiler.UmbracoApplicationBeginRequest(s, a); + + private void EndRequest(object s, EventArgs a) => _profiler.UmbracoApplicationEndRequest(s, a); } } From f24c54acad85f3b691565ad09b4f67b17966143d Mon Sep 17 00:00:00 2001 From: Claus Date: Thu, 24 Sep 2020 11:38:08 +0200 Subject: [PATCH 07/53] bump version to 8.6.5 --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 4ab97229d4..91765e57cf 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.6.4")] -[assembly: AssemblyInformationalVersion("8.6.4")] +[assembly: AssemblyFileVersion("8.6.5")] +[assembly: AssemblyInformationalVersion("8.6.5")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 0de757531a..5975ee52a1 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -345,9 +345,9 @@ False True - 8640 + 8650 / - http://localhost:8640 + http://localhost:8650 False False From e4c501075925191b370cf049369cf536d6ace1ab Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Sep 2020 18:45:26 +1000 Subject: [PATCH 08/53] Fixes issue with exceptions in logs because we are trying to unbind from httpapplication events but you cannot do that. (cherry picked from commit 5ed94065a71fb438ddeda5b431cb1d6153d20da8) --- .../Logging/WebProfilerComponent.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web/Logging/WebProfilerComponent.cs b/src/Umbraco.Web/Logging/WebProfilerComponent.cs index 1cb2142199..ff25eb6a22 100755 --- a/src/Umbraco.Web/Logging/WebProfilerComponent.cs +++ b/src/Umbraco.Web/Logging/WebProfilerComponent.cs @@ -10,7 +10,6 @@ namespace Umbraco.Web.Logging { private readonly WebProfiler _profiler; private readonly bool _profile; - private readonly List _terminate = new List(); public WebProfilerComponent(IProfiler profiler, ILogger logger) { @@ -39,21 +38,20 @@ namespace Umbraco.Web.Logging public void Terminate() { UmbracoApplicationBase.ApplicationInit -= InitializeApplication; - foreach (var t in _terminate) t(); } private void InitializeApplication(object sender, EventArgs args) { if (!(sender is HttpApplication app)) return; - // for *each* application (this will run more than once) - void beginRequest(object s, EventArgs a) => _profiler.UmbracoApplicationBeginRequest(s, a); - app.BeginRequest += beginRequest; - _terminate.Add(() => app.BeginRequest -= beginRequest); - - void endRequest(object s, EventArgs a) => _profiler.UmbracoApplicationEndRequest(s, a); - app.EndRequest += endRequest; - _terminate.Add(() => app.EndRequest -= endRequest); + // NOTE: We do not unbind these events ... because you just can't do that for HttpApplication events, they will + // be removed when the app dies. + app.BeginRequest += BeginRequest; + app.EndRequest += EndRequest; } + + private void BeginRequest(object s, EventArgs a) => _profiler.UmbracoApplicationBeginRequest(s, a); + + private void EndRequest(object s, EventArgs a) => _profiler.UmbracoApplicationEndRequest(s, a); } } From 26905078caa3aa2900d4cb199e5a51b7a3604abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 11:22:49 +0200 Subject: [PATCH 09/53] create enviroment configuration through install script --- .../createEnviromentConfiguration.js | 35 +++++++++++++++++++ src/Umbraco.Tests.AcceptanceTest/package.json | 5 ++- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js diff --git a/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js b/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js new file mode 100644 index 0000000000..6ee54bdf37 --- /dev/null +++ b/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js @@ -0,0 +1,35 @@ +const prompt = require('prompt'); +fs = require('fs'); + +const properties = [ + { + name: 'username' + }, + { + name: 'password', + hidden: true + } +]; + +prompt.start(); + +prompt.get(properties, function (error, result) { + if (error) { return onError(error); } + + console.log('Saving...'); + +var fileContent = `{ + "username": "${result.username}", + "password": "${result.password}" +}`; + + fs.writeFile('cypress.env.json', fileContent, function (error) { + if (error) return console.error(error); + console.log('Saved'); + }); +}); + +function onError(error) { + console.error(error); + return true; +} diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index 2017142d1e..12db29b68a 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -1,5 +1,7 @@ { "scripts": { + "postinstall": "node createEnviromentConfiguration.js", + "config": "node createEnviromentConfiguration.js", "test": "npx cypress run", "ui": "npx cypress open" }, @@ -7,7 +9,8 @@ "cross-env": "^7.0.2", "cypress": "^5.1.0", "ncp": "^2.0.0", - "umbraco-cypress-testhelpers": "^1.0.0-beta-50" + "umbraco-cypress-testhelpers": "^1.0.0-beta-50", + "prompt": "^1.0.0" }, "dependencies": { "typescript": "^3.9.2" From 9286282ecaeca859467183d7d35af5c8a558e41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 11:36:28 +0200 Subject: [PATCH 10/53] updated text --- .../createEnviromentConfiguration.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js b/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js index 6ee54bdf37..469408d4b3 100644 --- a/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js +++ b/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js @@ -3,21 +3,21 @@ fs = require('fs'); const properties = [ { - name: 'username' + name: 'superadmin username/email' }, { - name: 'password', + name: 'superadmin password', hidden: true } ]; +console.log("Configure your test enviroment:") + prompt.start(); prompt.get(properties, function (error, result) { if (error) { return onError(error); } - console.log('Saving...'); - var fileContent = `{ "username": "${result.username}", "password": "${result.password}" @@ -25,7 +25,7 @@ var fileContent = `{ fs.writeFile('cypress.env.json', fileContent, function (error) { if (error) return console.error(error); - console.log('Saved'); + console.log('Configuration saved'); }); }); From 78724c11eb4b07ef2ed6b1df213ce4dee73cca07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 11:36:43 +0200 Subject: [PATCH 11/53] updated readme --- src/Umbraco.Tests.AcceptanceTest/README.md | 70 +++++++++++----------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/README.md b/src/Umbraco.Tests.AcceptanceTest/README.md index 541efd40f8..f4edaa92ea 100644 --- a/src/Umbraco.Tests.AcceptanceTest/README.md +++ b/src/Umbraco.Tests.AcceptanceTest/README.md @@ -1,34 +1,36 @@ -# Umbraco Acceptance Tests - -### Prerequisites -- NodeJS 12+ -- A running installed Umbraco on url: [https://localhost:44331](https://localhost:44331) (Default development port) - - Install using a `SqlServer`/`LocalDb` as the tests execute too fast for `SqlCE` to handle. -- User information in `cypress.env.json` (See [Getting started](#getting-started)) - -### Getting started -The tests are located in the project/folder as `Umbraco.Tests.AcceptanceTests`. Make sure you run `npm install` in that folder, or let your IDE do that. - -Next, it is important that you create a new file in the root of the project called `cypress.env.json`. -This file is already added to `.gitignore` and can contain values that are different for each developer machine. - -The file needs the following content: -``` -{ - "username": "", - "password": "" -} -``` -Replace the `` and `` placeholders with correct info. - - - -### Executing tests -There are two npm scripts that can be used to execute the test: - -1. `npm run test` - - Executes the tests headless. -1. `npm run ui` - - Executes the tests in a browser handled by a cypress application. - - In case of errors it is recommended to use the UI to debug. +# Umbraco Acceptance Tests + +### Prerequisites +- NodeJS 12+ +- A running installed Umbraco on url: [https://localhost:44331](https://localhost:44331) (Default development port) + - Install using a `SqlServer`/`LocalDb` as the tests execute too fast for `SqlCE` to handle. + +### Getting started +The tests are located in the project/folder as `Umbraco.Tests.AcceptanceTests`. Make sure you run `npm install` in that folder, or let your IDE do that. + +The script will ask you to enter the username and password for a superadmin user of your Umbraco CMS. + +### Executing tests +There are two npm scripts that can be used to execute the test: + +1. `npm run test` + - Executes the tests headless. +1. `npm run ui` + - Executes the tests in a browser handled by a cypress application. + + In case of errors it is recommended to use the UI to debug. + +### Enviroment Configuration + +The enviroment configuration is begin setup by the npm installation script. +This results in the creation of this file: `cypress.env.json`. +This file is already added to `.gitignore` and can contain values that are different for each developer machine. + +The file has the following content: +``` +{ + "username": "", + "password": "" +} +``` +You can change this if you like or run the config script to reset the values, type "npm run config" in your terminal. From b46dad39ff75fc5ab9c59c4261becb05716ba834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 11:50:57 +0200 Subject: [PATCH 12/53] only write config if file does not already exist --- ...reateEnviromentConfiguration.js => config.js} | 16 ++++++++++------ src/Umbraco.Tests.AcceptanceTest/package.json | 4 ++-- src/Umbraco.Tests.AcceptanceTest/postinstall.js | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) rename src/Umbraco.Tests.AcceptanceTest/{createEnviromentConfiguration.js => config.js} (63%) create mode 100644 src/Umbraco.Tests.AcceptanceTest/postinstall.js diff --git a/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js b/src/Umbraco.Tests.AcceptanceTest/config.js similarity index 63% rename from src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js rename to src/Umbraco.Tests.AcceptanceTest/config.js index 469408d4b3..44f4f7543a 100644 --- a/src/Umbraco.Tests.AcceptanceTest/createEnviromentConfiguration.js +++ b/src/Umbraco.Tests.AcceptanceTest/config.js @@ -1,17 +1,21 @@ const prompt = require('prompt'); -fs = require('fs'); +const fs = require('fs'); const properties = [ { - name: 'superadmin username/email' + name: 'username' }, { - name: 'superadmin password', + name: 'password', hidden: true } ]; -console.log("Configure your test enviroment:") + +const configPath = './cypress.env.json' + +console.log("Configure your test enviroment") +console.log("Enter CMS superadmin credentials:") prompt.start(); @@ -23,10 +27,10 @@ var fileContent = `{ "password": "${result.password}" }`; - fs.writeFile('cypress.env.json', fileContent, function (error) { + fs.writeFile(configPath, fileContent, function (error) { if (error) return console.error(error); console.log('Configuration saved'); - }); + }); }); function onError(error) { diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index 12db29b68a..e845681f18 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -1,7 +1,7 @@ { "scripts": { - "postinstall": "node createEnviromentConfiguration.js", - "config": "node createEnviromentConfiguration.js", + "postinstall": "node postinstall.js", + "config": "node config.js", "test": "npx cypress run", "ui": "npx cypress open" }, diff --git a/src/Umbraco.Tests.AcceptanceTest/postinstall.js b/src/Umbraco.Tests.AcceptanceTest/postinstall.js new file mode 100644 index 0000000000..ba2246b592 --- /dev/null +++ b/src/Umbraco.Tests.AcceptanceTest/postinstall.js @@ -0,0 +1,14 @@ +const fs = require('fs'); + +const configPath = './cypress.env.json'; + +try { + if (fs.existsSync(configPath)) { + //file exists + console.log("Skips configuration as file already exists, run 'npm run config' to change your configuration."); + } else { + require('./createEnviromentConfiguration.js'); + } +} catch(err) { + console.error(err) +} From 408546812597989894f5f4597400a7b0fc32e2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 12:01:40 +0200 Subject: [PATCH 13/53] update dependency name --- src/Umbraco.Tests.AcceptanceTest/postinstall.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/postinstall.js b/src/Umbraco.Tests.AcceptanceTest/postinstall.js index ba2246b592..6117ac84f0 100644 --- a/src/Umbraco.Tests.AcceptanceTest/postinstall.js +++ b/src/Umbraco.Tests.AcceptanceTest/postinstall.js @@ -7,7 +7,7 @@ try { //file exists console.log("Skips configuration as file already exists, run 'npm run config' to change your configuration."); } else { - require('./createEnviromentConfiguration.js'); + require('./config.js'); } } catch(err) { console.error(err) From b5374152a1c3220edd4642359167d089e093e460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 12:45:45 +0200 Subject: [PATCH 14/53] make baseUrl an optional part of configuration --- src/Umbraco.Tests.AcceptanceTest/config.js | 12 ++++++++++-- .../cypress/plugins/index.js | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/config.js b/src/Umbraco.Tests.AcceptanceTest/config.js index 44f4f7543a..e86b14d076 100644 --- a/src/Umbraco.Tests.AcceptanceTest/config.js +++ b/src/Umbraco.Tests.AcceptanceTest/config.js @@ -3,11 +3,17 @@ const fs = require('fs'); const properties = [ { + description: 'Enter your superadmin username/email', name: 'username' }, { + description: 'Enter your superadmin password', name: 'password', hidden: true + }, + { + description: 'Enter CMS URL, or leave empty for default(https://localhost:44331)', + name: 'baseUrl' } ]; @@ -15,7 +21,6 @@ const properties = [ const configPath = './cypress.env.json' console.log("Configure your test enviroment") -console.log("Enter CMS superadmin credentials:") prompt.start(); @@ -24,7 +29,10 @@ prompt.get(properties, function (error, result) { var fileContent = `{ "username": "${result.username}", - "password": "${result.password}" + "password": "${result.password}"${ + result.baseUrl && `, + "baseUrl": "${result.baseUrl}"` + } }`; fs.writeFile(configPath, fileContent, function (error) { diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js b/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js index aa9918d215..59283feec5 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js @@ -18,4 +18,11 @@ module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config + const baseUrl = config.env.baseUrl || null; + + if (baseUrl) { + config.baseUrl = baseUrl; + } + + return config; } From b053ad142363b4e813c120da14d9025e434ca7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 25 Sep 2020 14:02:22 +0200 Subject: [PATCH 15/53] set to be required --- src/Umbraco.Tests.AcceptanceTest/config.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/config.js b/src/Umbraco.Tests.AcceptanceTest/config.js index e86b14d076..5297cbccbc 100644 --- a/src/Umbraco.Tests.AcceptanceTest/config.js +++ b/src/Umbraco.Tests.AcceptanceTest/config.js @@ -4,12 +4,14 @@ const fs = require('fs'); const properties = [ { description: 'Enter your superadmin username/email', - name: 'username' + name: 'username', + required: true }, { description: 'Enter your superadmin password', name: 'password', - hidden: true + hidden: true, + required: true }, { description: 'Enter CMS URL, or leave empty for default(https://localhost:44331)', From ebe3c26cb7e021c57dc4fdb99acb6c4934cc0207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 28 Sep 2020 14:13:43 +0200 Subject: [PATCH 16/53] use block.edit() --- .../blocklistentryeditors/labelblock/labelblock.editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html index 5e81efec8b..f51ea4607c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html @@ -1,5 +1,5 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html index 211c501e53..f41390bce3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html @@ -69,9 +69,9 @@ prevent-default> Last Updated - +
- +
@@ -79,15 +79,15 @@
- +
- + {{item.name}}
{{item.updateDate | date:'medium'}} -
+
From 5d9389b37c9f4687774b9b6d7998ccbf4eba3522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 28 Sep 2020 17:57:04 +0200 Subject: [PATCH 18/53] adjust default size of umb-button-ellipsis and its apperance in umb-tree --- .../src/less/components/buttons/umb-button-ellipsis.less | 9 +++++++-- .../src/less/components/tree/umb-tree-root.less | 4 +++- .../src/less/components/tree/umb-tree.less | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less index 54302ba869..7104e6478f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less @@ -4,10 +4,10 @@ margin: 0 auto; cursor: pointer; border-radius: @baseBorderRadius; - color: black; + color: @ui-action-discreet-type; position: relative; opacity: 0.8; - transition: opacity .3s ease-out; + transition: opacity 120ms, color 120ms; &--absolute { position: absolute; @@ -23,6 +23,10 @@ justify-content: center; } + &:hover { + color: @ui-action-discreet-type-hover; + } + .umb-button-ellipsis--tab, .umb-tour-is-visible .umb-tree &, &:hover, @@ -47,6 +51,7 @@ &__icon { color: inherit; flex-basis: 100%; + font-size: 12px; .umb-button-ellipsis--tab & { margin: 0 0 7px; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less index a3529d5504..ba33883b08 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less @@ -1,5 +1,7 @@ -.umb-tree-root { +.umb-tree-root { + border: 2px solid transparent; + &-link { display: flex; align-items: center; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less index d4599ea03d..bf8e7fdb70 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less @@ -95,7 +95,6 @@ body.touch .umb-tree { position: relative; width: auto; height: auto; - margin: 0 5px 0 auto; overflow: visible; clip: auto; } @@ -185,9 +184,10 @@ body.touch .umb-tree { flex: 0 0 auto; justify-content: flex-end; text-align: center; - margin: 0 5px 0 auto; + margin: 0 10px 0 auto; cursor: pointer; border-radius: @baseBorderRadius; + transition: background-color 120ms; .umb-button-ellipsis { padding: 3px 5px; @@ -207,7 +207,7 @@ body.touch .umb-tree { } &:hover { - background: rgba(255, 255, 255, .5); + background-color: rgba(255, 255, 255, .8); i { background: @ui-active-type-hover; From 1ec9e24ae5c671b83a0886feabadd17e200f8f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 28 Sep 2020 19:44:58 +0200 Subject: [PATCH 19/53] 8.8 Revert icon styling, to ensure backwards compatibility (#8941) (cherry picked from commit 956c81ff320e23ba7ce10d26c73b59accb1911b7) --- .../src/common/services/iconhelper.service.js | 11 +- .../src/less/components/umb-icon.less | 23 + .../src/less/components/umb-iconpicker.less | 1 - .../src/less/components/umb-media-grid.less | 4 + .../src/less/helveticons.less | 1266 ++++++++--------- .../iconpicker/iconpicker.controller.js | 20 +- .../iconpicker/iconpicker.html | 8 +- .../src/views/components/umb-media-grid.html | 10 +- 8 files changed, 662 insertions(+), 681 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 5034de67eb..f26763bd14 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 @@ -252,7 +252,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { /** LEGACY - Return a list of icons from icon fonts, optionally filter them */ /** It fetches them directly from the active stylesheets in the browser */ - getLegacyIcons: function(){ + getIcons: function(){ var deferred = $q.defer(); $timeout(function(){ if(collectedIcons){ @@ -284,13 +284,8 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { s = s.substring(0, hasPseudo); } - var icon = { - name: s, - svgString: undefined - }; - - if(collectedIcons.indexOf(icon) < 0 && s !== "icon-chevron-up" && s !== "icon-chevron-down"){ - collectedIcons.push(icon); + if(collectedIcons.indexOf(s) < 0){ + collectedIcons.push(s); } } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less index e3b0550d15..e08174e378 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less @@ -1,4 +1,27 @@ .umb-icon { + display: inline-block; + width: 1em; + height: 1em; + + svg { + width: 100%; + height: 100%; + fill: currentColor; + } + + &.large{ + width: 32px; + height: 32px; + } + &.medium{ + width: 24px; + height: 24px; + } + &.small{ + width: 14px; + height: 14px; + } + &:before, &:after { content: none !important; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less index e23325a7d2..5062aae660 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less @@ -58,7 +58,6 @@ } .umb-iconpicker-item i { - font-family: inherit; font-size: 30px; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less index 09fea977c7..d05139a06f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less @@ -234,3 +234,7 @@ .umb-media-grid__list-view .umb-table-cell.umb-table__name .item-name { white-space:normal; } +.umb-media-grid__list-view .umb-table-cell.umb-table__name ins { + text-decoration: none; + margin-top: 3px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/helveticons.less b/src/Umbraco.Web.UI.Client/src/less/helveticons.less index a51f4e9f6f..cded6b8269 100644 --- a/src/Umbraco.Web.UI.Client/src/less/helveticons.less +++ b/src/Umbraco.Web.UI.Client/src/less/helveticons.less @@ -8,36 +8,9 @@ font-style: normal; } -span[class^="icon-"], -span[class*=" icon-"] { - display: inline-block; - width: 1em; - height: 1em; - *margin-right: .3em; - - svg { - width: 100%; - height: 100%; - fill: currentColor; - } - - &.large{ - width: 32px; - height: 32px; - } - &.medium{ - width: 24px; - height: 24px; - } - &.small{ - width: 14px; - height: 14px; - } -} [class^="icon-"], -[class*=" icon-"], -button.icon-trash { +[class*=" icon-"]{ font-family: 'icomoon'; speak: none; font-style: normal; @@ -52,8 +25,7 @@ button.icon-trash { } [class^="icon-"]:before, -[class*=" icon-"]:before, -button.icon-trash { +[class*=" icon-"]:before { text-decoration: inherit; display: inline-block; speak: none; @@ -69,1838 +41,1834 @@ i.small{ font-size: 14px; } -i.icon-zoom-out:before { +.icon-zoom-out:before { content: "\e000"; } -i.icon-truck:before { +.icon-truck:before { content: "\e001"; } -i.icon-zoom-in:before { +.icon-zoom-in:before { content: "\e002"; } -i.icon-zip:before { +.icon-zip:before { content: "\e003"; } -i.icon-axis-rotation:before { +.icon-axis-rotation:before { content: "\e004"; } -i.icon-yen-bag:before { +.icon-yen-bag:before { content: "\e005"; } -i.icon-axis-rotation-2:before { +.icon-axis-rotation-2:before { content: "\e006"; } -i.icon-axis-rotation-3:before { +.icon-axis-rotation-3:before { content: "\e007"; } -i.icon-wrench:before { +.icon-wrench:before { content: "\e008"; } -i.icon-wine-glass:before { +.icon-wine-glass:before { content: "\e009"; } -i.icon-wrong:before { +.icon-wrong:before { content: "\e00a"; } -i.icon-windows:before { +.icon-windows:before { content: "\e00b"; } -i.icon-window-sizes:before { +.icon-window-sizes:before { content: "\e00c"; } -i.icon-window-popin:before { +.icon-window-popin:before { content: "\e00d"; } -i.icon-wifi:before { +.icon-wifi:before { content: "\e00e"; } -i.icon-width:before { +.icon-width:before { content: "\e00f"; } -i.icon-weight:before { +.icon-weight:before { content: "\e010"; } -i.icon-war:before { +.icon-war:before { content: "\e011"; } -i.icon-wand:before { +.icon-wand:before { content: "\e012"; } -i.icon-wallet:before { +.icon-wallet:before { content: "\e013"; } -i.icon-wall-plug:before { +.icon-wall-plug:before { content: "\e014"; } -i.icon-voice:before { +.icon-voice:before { content: "\e016"; } -i.icon-video:before { +.icon-video:before { content: "\e017"; } -i.icon-vcard:before { +.icon-vcard:before { content: "\e018"; } -i.icon-utilities:before { +.icon-utilities:before { content: "\e019"; } -i.icon-users:before { +.icon-users:before { content: "\e01a"; } -i.icon-users-alt:before { +.icon-users-alt:before { content: "\e01b"; } -i.icon-user:before { +.icon-user:before { content: "\e01c"; } -i.icon-user-glasses:before { +.icon-user-glasses:before { content: "\e01d"; } -i.icon-user-females:before { +.icon-user-females:before { content: "\e01e"; } -i.icon-user-females-alt:before { +.icon-user-females-alt:before { content: "\e01f"; } -i.icon-user-female:before { +.icon-user-female:before { content: "\e020"; } -i.icon-usb:before { +.icon-usb:before { content: "\e021"; } -i.icon-usb-connector:before { +.icon-usb-connector:before { content: "\e022"; } -i.icon-unlocked:before { +.icon-unlocked:before { content: "\e023"; } -i.icon-universal:before { +.icon-universal:before { content: "\e024"; } -i.icon-undo:before { +.icon-undo:before { content: "\e025"; } -i.icon-umbrella:before { +.icon-umbrella:before { content: "\e026"; } -i.icon-umb-deploy:before { +.icon-umb-deploy:before { content: "\e027"; } -i.icon-umb-contour:before, .traycontour:before { +.icon-umb-contour:before, .traycontour:before { content: "\e028"; } -i.icon-umb-settings:before, .traysettings:before { +.icon-umb-settings:before, .traysettings:before { content: "\e029"; } -i.icon-umb-users:before, .trayuser:before, .trayusers:before{ +.icon-umb-users:before, .trayuser:before, .trayusers:before{ content: "\e02a"; } -i.icon-umb-media:before, .traymedia:before { +.icon-umb-media:before, .traymedia:before { content: "\e02b"; } -i.icon-umb-content:before, .traycontent:before{ +.icon-umb-content:before, .traycontent:before{ content: "\e02c"; } -i.icon-umb-developer:before, .traydeveloper:before { +.icon-umb-developer:before, .traydeveloper:before { content: "\e02d"; } -i.icon-umb-members:before, .traymember:before { +.icon-umb-members:before, .traymember:before { content: "\e015"; } -i.icon-umb-translation:before, .traytranslation:before { +.icon-umb-translation:before, .traytranslation:before { content: "\e1fd"; } -i.icon-tv:before { +.icon-tv:before { content: "\e02e"; } -i.icon-tv-old:before { +.icon-tv-old:before { content: "\e02f"; } -i.icon-trophy:before { +.icon-trophy:before { content: "\e030"; } -i.icon-tree:before { +.icon-tree:before { content: "\e031"; } -i.icon-trash:before, -button.icon-trash:before { +.icon-trash:before { content: "\e032"; } -i.icon-trash-alt:before, -button.icon-trash-alt:before { +.icon-trash-alt:before { content: "\e033"; } -i.icon-trash-alt-2:before, -button.icon-trash-alt-2:before { +.icon-trash-alt-2:before { content: "\e034"; } -i.icon-train:before { +.icon-train:before { content: "\e035"; } -i.icon-trafic:before, -i.icon-traffic:before { +.icon-trafic:before, +.icon-traffic:before { content: "\e036"; } -i.icon-traffic-alt:before { +.icon-traffic-alt:before { content: "\e037"; } -i.icon-top:before { +.icon-top:before { content: "\e038"; } -i.icon-tools:before { +.icon-tools:before { content: "\e039"; } -i.icon-timer:before { +.icon-timer:before { content: "\e03a"; } -i.icon-time:before { +.icon-time:before { content: "\e03b"; } -i.icon-t-shirt:before { +.icon-t-shirt:before { content: "\e03c"; } -i.icon-tab-key:before { +.icon-tab-key:before { content: "\e03d"; } -i.icon-tab:before { +.icon-tab:before { content: "\e03e"; } -i.icon-tactics:before { +.icon-tactics:before { content: "\e03f"; } -i.icon-tag:before { +.icon-tag:before { content: "\e040"; } -i.icon-tags:before { +.icon-tags:before { content: "\e041"; } -i.icon-takeaway-cup:before { +.icon-takeaway-cup:before { content: "\e042"; } -i.icon-target:before { +.icon-target:before { content: "\e043"; } -i.icon-temperature-alt:before, -i.icon-temperatrure-alt:before { +.icon-temperature-alt:before, +.icon-temperatrure-alt:before { content: "\e044"; } -i.icon-temperature:before { +.icon-temperature:before { content: "\e045"; } -i.icon-terminal:before { +.icon-terminal:before { content: "\e046"; } -i.icon-theater:before { +.icon-theater:before { content: "\e047"; } -i.icon-thief:before, -i.icon-theif:before { +.icon-thief:before, +.icon-theif:before { content: "\e048"; } -i.icon-thought-bubble:before { +.icon-thought-bubble:before { content: "\e049"; } -i.icon-thumb-down:before { +.icon-thumb-down:before { content: "\e04a"; } -i.icon-thumb-up:before { +.icon-thumb-up:before { content: "\e04b"; } -i.icon-thumbnail-list:before { +.icon-thumbnail-list:before { content: "\e04c"; } -i.icon-thumbnails-small:before { +.icon-thumbnails-small:before { content: "\e04d"; } -i.icon-thumbnails:before { +.icon-thumbnails:before { content: "\e04e"; } -i.icon-ticket:before { +.icon-ticket:before { content: "\e04f"; } -i.icon-sync:before { +.icon-sync:before { content: "\e050"; } -i.icon-sweatshirt:before { +.icon-sweatshirt:before { content: "\e051"; } -i.icon-sunny:before { +.icon-sunny:before { content: "\e052"; } -i.icon-stream:before { +.icon-stream:before { content: "\e053"; } -i.icon-store:before { +.icon-store:before { content: "\e054"; } -i.icon-stop:before { +.icon-stop:before { content: "\e055"; } -i.icon-stop-hand:before { +.icon-stop-hand:before { content: "\e056"; } -i.icon-stop-alt:before { +.icon-stop-alt:before { content: "\e057"; } -i.icon-stamp:before { +.icon-stamp:before { content: "\e058"; } -i.icon-stacked-disks:before { +.icon-stacked-disks:before { content: "\e059"; } -i.icon-ssd:before { +.icon-ssd:before { content: "\e05a"; } -i.icon-squiggly-line:before { +.icon-squiggly-line:before { content: "\e05b"; } -i.icon-sprout:before { +.icon-sprout:before { content: "\e05c"; } -i.icon-split:before { +.icon-split:before { content: "\e05d"; } -i.icon-split-alt:before { +.icon-split-alt:before { content: "\e05e"; } -i.icon-speed-gauge:before { +.icon-speed-gauge:before { content: "\e05f"; } -i.icon-speaker:before { +.icon-speaker:before { content: "\e060"; } -i.icon-sound:before { +.icon-sound:before { content: "\e061"; } -i.icon-spades:before { +.icon-spades:before { content: "\e062"; } -i.icon-sound-waves:before { +.icon-sound-waves:before { content: "\e063"; } -i.icon-shipping-box:before { +.icon-shipping-box:before { content: "\e064"; } -i.icon-shipping:before { +.icon-shipping:before { content: "\e065"; } -i.icon-shoe:before { +.icon-shoe:before { content: "\e066"; } -i.icon-shopping-basket-alt-2:before { +.icon-shopping-basket-alt-2:before { content: "\e067"; } -i.icon-shopping-basket:before { +.icon-shopping-basket:before { content: "\e068"; } -i.icon-shopping-basket-alt:before { +.icon-shopping-basket-alt:before { content: "\e069"; } -i.icon-shorts:before { +.icon-shorts:before { content: "\e06a"; } -i.icon-shuffle:before { +.icon-shuffle:before { content: "\e06b"; } -i.icon-science:before, -i.icon-sience:before { +.icon-science:before, +.icon-sience:before { content: "\e06c"; } -i.icon-simcard:before { +.icon-simcard:before { content: "\e06d"; } -i.icon-single-note:before { +.icon-single-note:before { content: "\e06e"; } -i.icon-sitemap:before { +.icon-sitemap:before { content: "\e06f"; } -i.icon-sleep:before { +.icon-sleep:before { content: "\e070"; } -i.icon-slideshow:before { +.icon-slideshow:before { content: "\e071"; } -i.icon-smiley-inverted:before { +.icon-smiley-inverted:before { content: "\e072"; } -i.icon-smiley:before { +.icon-smiley:before { content: "\e073"; } -i.icon-snow:before { +.icon-snow:before { content: "\e074"; } -i.icon-sound-low:before { +.icon-sound-low:before { content: "\e075"; } -i.icon-sound-medium:before { +.icon-sound-medium:before { content: "\e076"; } -i.icon-sound-off:before { +.icon-sound-off:before { content: "\e077"; } -i.icon-shift:before { +.icon-shift:before { content: "\e078"; } -i.icon-shield:before { +.icon-shield:before { content: "\e079"; } -i.icon-sharing-iphone:before { +.icon-sharing-iphone:before { content: "\e07a"; } -i.icon-share:before { +.icon-share:before { content: "\e07b"; } -i.icon-share-alt:before { +.icon-share-alt:before { content: "\e07c"; } -i.icon-share-alt-2:before { +.icon-share-alt-2:before { content: "\e07d"; } -i.icon-settings:before, -button.icon-settings:before { +.icon-settings:before { content: "\e07e"; } -i.icon-settings-alt:before { +.icon-settings-alt:before { content: "\e07f"; } -i.icon-settings-alt-2:before { +.icon-settings-alt-2:before { content: "\e080"; } -i.icon-server:before { +.icon-server:before { content: "\e081"; } -i.icon-server-alt:before { +.icon-server-alt:before { content: "\e082"; } -i.icon-sensor:before { +.icon-sensor:before { content: "\e083"; } -i.icon-security-camera:before { +.icon-security-camera:before { content: "\e084"; } -i.icon-search:before { +.icon-search:before { content: "\e085"; } -i.icon-scull:before { +.icon-scull:before { content: "\e086"; } -i.icon-script:before { +.icon-script:before { content: "\e087"; } -i.icon-script-alt:before { +.icon-script-alt:before { content: "\e088"; } -i.icon-screensharing:before { +.icon-screensharing:before { content: "\e089"; } -i.icon-school:before { +.icon-school:before { content: "\e08a"; } -i.icon-scan:before { +.icon-scan:before { content: "\e08b"; } -i.icon-refresh:before { +.icon-refresh:before { content: "\e08c"; } -i.icon-remote:before { +.icon-remote:before { content: "\e08d"; } -i.icon-remove:before { +.icon-remove:before { content: "\e08e"; } -i.icon-repeat-one:before { +.icon-repeat-one:before { content: "\e08f"; } -i.icon-repeat:before { +.icon-repeat:before { content: "\e090"; } -i.icon-resize:before { +.icon-resize:before { content: "\e091"; } -i.icon-reply-arrow:before { +.icon-reply-arrow:before { content: "\e092"; } -i.icon-return-to-top:before { +.icon-return-to-top:before { content: "\e093"; } -i.icon-right-double-arrow:before { +.icon-right-double-arrow:before { content: "\e094"; } -i.icon-road:before { +.icon-road:before { content: "\e095"; } -i.icon-roadsign:before { +.icon-roadsign:before { content: "\e096"; } -i.icon-rocket:before { +.icon-rocket:before { content: "\e097"; } -i.icon-rss:before { +.icon-rss:before { content: "\e098"; } -i.icon-ruler-alt:before { +.icon-ruler-alt:before { content: "\e099"; } -i.icon-ruler:before { +.icon-ruler:before { content: "\e09a"; } -i.icon-sandbox-toys:before { +.icon-sandbox-toys:before { content: "\e09b"; } -i.icon-satellite-dish:before { +.icon-satellite-dish:before { content: "\e09c"; } -i.icon-save:before { +.icon-save:before { content: "\e09d"; } -i.icon-safedial:before { +.icon-safedial:before { content: "\e09e"; } -i.icon-safe:before { +.icon-safe:before { content: "\e09f"; } -i.icon-redo:before { +.icon-redo:before { content: "\e0a0"; } -i.icon-printer-alt:before { +.icon-printer-alt:before { content: "\e0a1"; } -i.icon-planet:before { +.icon-planet:before { content: "\e0a2"; } -i.icon-paste-in:before { +.icon-paste-in:before { content: "\e0a3"; } -i.icon-os-x:before { +.icon-os-x:before { content: "\e0a4"; } -i.icon-navigation-left:before { +.icon-navigation-left:before { content: "\e0a5"; } -i.icon-message:before { +.icon-message:before { content: "\e0a6"; } -i.icon-lock:before { +.icon-lock:before { content: "\e0a7"; } -i.icon-layers-alt:before { +.icon-layers-alt:before { content: "\e0a8"; } -i.icon-record:before { +.icon-record:before { content: "\e0a9"; } -i.icon-print:before { +.icon-print:before { content: "\e0aa"; } -i.icon-plane:before { +.icon-plane:before { content: "\e0ab"; } -i.icon-partly-cloudy:before { +.icon-partly-cloudy:before { content: "\e0ac"; } -i.icon-ordered-list:before { +.icon-ordered-list:before { content: "\e0ad"; } -i.icon-navigation-last:before { +.icon-navigation-last:before { content: "\e0ae"; } -i.icon-message-unopened:before { +.icon-message-unopened:before { content: "\e0af"; } -i.icon-location-nearby:before { +.icon-location-nearby:before { content: "\e0b0"; } -i.icon-laptop:before { +.icon-laptop:before { content: "\e0b1"; } -i.icon-reception:before { +.icon-reception:before { content: "\e0b2"; } -i.icon-price-yen:before { +.icon-price-yen:before { content: "\e0b3"; } -i.icon-piracy:before { +.icon-piracy:before { content: "\e0b4"; } -i.icon-parental-control:before { +.icon-parental-control:before { content: "\e0b5"; } -i.icon-operator:before { +.icon-operator:before { content: "\e0b6"; } -i.icon-navigation-horizontal:before { +.icon-navigation-horizontal:before { content: "\e0b7"; } -i.icon-message-open:before { +.icon-message-open:before { content: "\e0b8"; } -i.icon-lab:before { +.icon-lab:before { content: "\e0b9"; } -i.icon-location-near-me:before { +.icon-location-near-me:before { content: "\e0ba"; } -i.icon-receipt-yen:before { +.icon-receipt-yen:before { content: "\e0bb"; } -i.icon-price-pound:before { +.icon-price-pound:before { content: "\e0bc"; } -i.icon-pin-location:before { +.icon-pin-location:before { content: "\e0bd"; } -i.icon-parachute-drop:before { +.icon-parachute-drop:before { content: "\e0be"; } -i.icon-old-phone:before { +.icon-old-phone:before { content: "\e0bf"; } -i.icon-merge:before { +.icon-merge:before { content: "\e0c0"; } -i.icon-navigation-first:before { +.icon-navigation-first:before { content: "\e0c1"; } -i.icon-locate:before { +.icon-locate:before { content: "\e0c2"; } -i.icon-keyhole:before { +.icon-keyhole:before { content: "\e0c3"; } -i.icon-receipt-pound:before { +.icon-receipt-pound:before { content: "\e0c4"; } -i.icon-price-euro:before { +.icon-price-euro:before { content: "\e0c5"; } -i.icon-piggy-bank:before { +.icon-piggy-bank:before { content: "\e0c6"; } -i.icon-paper-plane:before { +.icon-paper-plane:before { content: "\e0c7"; } -i.icon-old-key:before { +.icon-old-key:before { content: "\e0c8"; } -i.icon-navigation-down:before { +.icon-navigation-down:before { content: "\e0c9"; } -i.icon-megaphone:before { +.icon-megaphone:before { content: "\e0ca"; } -i.icon-loading:before { +.icon-loading:before { content: "\e0cb"; } -i.icon-keychain:before { +.icon-keychain:before { content: "\e0cc"; } -i.icon-receipt-euro:before { +.icon-receipt-euro:before { content: "\e0cd"; } -i.icon-price-dollar:before { +.icon-price-dollar:before { content: "\e0ce"; } -i.icon-pie-chart:before { +.icon-pie-chart:before { content: "\e0cf"; } -i.icon-paper-plane-alt:before { +.icon-paper-plane-alt:before { content: "\e0d0"; } -i.icon-notepad:before { +.icon-notepad:before { content: "\e0d1"; } -i.icon-navigation-bottom:before { +.icon-navigation-bottom:before { content: "\e0d2"; } -i.icon-meeting:before { +.icon-meeting:before { content: "\e0d3"; } -i.icon-keyboard:before { +.icon-keyboard:before { content: "\e0d4"; } -i.icon-load:before { +.icon-load:before { content: "\e0d5"; } -i.icon-receipt-dollar:before { +.icon-receipt-dollar:before { content: "\e0d6"; } -i.icon-previous:before { +.icon-previous:before { content: "\e0d7"; } -i.icon-pictures:before { +.icon-pictures:before { content: "\e0d8"; } -i.icon-notepad-alt:before { +.icon-notepad-alt:before { content: "\e0d9"; } -i.icon-paper-bag:before { +.icon-paper-bag:before { content: "\e0da"; } -i.icon-badge:before { +.icon-badge:before { content: "\e0db"; } -i.icon-medicine:before { +.icon-medicine:before { content: "\e0dc"; } -i.icon-list:before { +.icon-list:before { content: "\e0dd"; } -i.icon-key:before { +.icon-key:before { content: "\e0de"; } -i.icon-receipt-alt:before { +.icon-receipt-alt:before { content: "\e0df"; } -i.icon-previous-media:before { +.icon-previous-media:before { content: "\e0e0"; } -i.icon-pictures-alt:before { +.icon-pictures-alt:before { content: "\e0e1"; } -i.icon-pants:before { +.icon-pants:before { content: "\e0e2"; } -i.icon-nodes:before { +.icon-nodes:before { content: "\e0e3"; } -i.icon-music:before { +.icon-music:before { content: "\e0e4"; } -i.icon-readonly:before { +.icon-readonly:before { content: "\e0e5"; } -i.icon-presentation:before { +.icon-presentation:before { content: "\e0e6"; } -i.icon-pictures-alt-2:before { +.icon-pictures-alt-2:before { content: "\e0e7"; } -i.icon-panel-close:before, -i.icon-pannel-close:before { +.icon-panel-close:before, +.icon-pannel-close:before { content: "\e0e8"; } -i.icon-next:before { +.icon-next:before { content: "\e0e9"; } -i.icon-multiple-windows:before { +.icon-multiple-windows:before { content: "\e0ea"; } -i.icon-medical-emergency:before { +.icon-medical-emergency:before { content: "\e0eb"; } -i.icon-medal:before { +.icon-medal:before { content: "\e0ec"; } -i.icon-link:before { +.icon-link:before { content: "\e0ed"; } -i.icon-linux-tux:before { +.icon-linux-tux:before { content: "\e0ee"; } -i.icon-junk:before { +.icon-junk:before { content: "\e0ef"; } -i.icon-item-arrangement:before { +.icon-item-arrangement:before { content: "\e0f0"; } -i.icon-iphone:before { +.icon-iphone:before { content: "\e0f1"; } -i.icon-lightning:before { +.icon-lightning:before { content: "\e0f2"; } -i.icon-map:before { +.icon-map:before { content: "\e0f3"; } -i.icon-multiple-credit-cards:before { +.icon-multiple-credit-cards:before { content: "\e0f4"; } -i.icon-next-media:before { +.icon-next-media:before { content: "\e0f5"; } -i.icon-panel-show:before { +.icon-panel-show:before { content: "\e0f6"; } -i.icon-picture:before { +.icon-picture:before { content: "\e0f7"; } -i.icon-power:before { +.icon-power:before { content: "\e0f8"; } -i.icon-re-post:before { +.icon-re-post:before { content: "\e0f9"; } -i.icon-rate:before { +.icon-rate:before { content: "\e0fa"; } -i.icon-rain:before { +.icon-rain:before { content: "\e0fb"; } -i.icon-radio:before { +.icon-radio:before { content: "\e0fc"; } -i.icon-radio-receiver:before { +.icon-radio-receiver:before { content: "\e0fd"; } -i.icon-radio-alt:before { +.icon-radio-alt:before { content: "\e0fe"; } -i.icon-quote:before { +.icon-quote:before { content: "\e0ff"; } -i.icon-qr-code:before { +.icon-qr-code:before { content: "\e100"; } -i.icon-pushpin:before { +.icon-pushpin:before { content: "\e101"; } -i.icon-pulse:before { +.icon-pulse:before { content: "\e102"; } -i.icon-projector:before { +.icon-projector:before { content: "\e103"; } -i.icon-play:before { +.icon-play:before { content: "\e104"; } -i.icon-playing-cards:before { +.icon-playing-cards:before { content: "\e105"; } -i.icon-playlist:before { +.icon-playlist:before { content: "\e106"; } -i.icon-plugin:before { +.icon-plugin:before { content: "\e107"; } -i.icon-podcast:before { +.icon-podcast:before { content: "\e108"; } -i.icon-poker-chip:before { +.icon-poker-chip:before { content: "\e109"; } -i.icon-poll:before { +.icon-poll:before { content: "\e10a"; } -i.icon-post-it:before { +.icon-post-it:before { content: "\e10b"; } -i.icon-pound-bag:before { +.icon-pound-bag:before { content: "\e10c"; } -i.icon-power-outlet:before { +.icon-power-outlet:before { content: "\e10d"; } -i.icon-photo-album:before { +.icon-photo-album:before { content: "\e10e"; } -i.icon-phone:before { +.icon-phone:before { content: "\e10f"; } -i.icon-phone-ring:before { +.icon-phone-ring:before { content: "\e110"; } -i.icon-people:before { +.icon-people:before { content: "\e111"; } -i.icon-people-female:before { +.icon-people-female:before { content: "\e112"; } -i.icon-people-alt:before { +.icon-people-alt:before { content: "\e113"; } -i.icon-people-alt-2:before { +.icon-people-alt-2:before { content: "\e114"; } -i.icon-pc:before { +.icon-pc:before { content: "\e115"; } -i.icon-pause:before { +.icon-pause:before { content: "\e116"; } -i.icon-path:before { +.icon-path:before { content: "\e117"; } -i.icon-out:before { +.icon-out:before { content: "\e118"; } -i.icon-outbox:before { +.icon-outbox:before { content: "\e119"; } -i.icon-outdent:before { +.icon-outdent:before { content: "\e11a"; } -i.icon-page-add:before { +.icon-page-add:before { content: "\e11b"; } -i.icon-page-down:before { +.icon-page-down:before { content: "\e11c"; } -i.icon-page-remove:before { +.icon-page-remove:before { content: "\e11d"; } -i.icon-page-restricted:before { +.icon-page-restricted:before { content: "\e11e"; } -i.icon-page-up:before { +.icon-page-up:before { content: "\e11f"; } -i.icon-paint-roller:before { +.icon-paint-roller:before { content: "\e120"; } -i.icon-palette:before { +.icon-palette:before { content: "\e121"; } -i.icon-newspaper:before { +.icon-newspaper:before { content: "\e122"; } -i.icon-newspaper-alt:before { +.icon-newspaper-alt:before { content: "\e123"; } -i.icon-network-alt:before { +.icon-network-alt:before { content: "\e124"; } -i.icon-navigational-arrow:before { +.icon-navigational-arrow:before { content: "\e125"; } -i.icon-navigation:before { +.icon-navigation:before { content: "\e126"; } -i.icon-navigation-vertical:before { +.icon-navigation-vertical:before { content: "\e127"; } -i.icon-navigation-up:before { +.icon-navigation-up:before { content: "\e128"; } -i.icon-navigation-top:before { +.icon-navigation-top:before { content: "\e129"; } -i.icon-navigation-road:before { +.icon-navigation-road:before { content: "\e12a"; } -i.icon-navigation-right:before { +.icon-navigation-right:before { content: "\e12b"; } -i.icon-microscope:before { +.icon-microscope:before { content: "\e12c"; } -i.icon-mindmap:before { +.icon-mindmap:before { content: "\e12d"; } -i.icon-molecular-network:before { +.icon-molecular-network:before { content: "\e12e"; } -i.icon-molecular:before { +.icon-molecular:before { content: "\e12f"; } -i.icon-mountain:before { +.icon-mountain:before { content: "\e130"; } -i.icon-mouse-cursor:before { +.icon-mouse-cursor:before { content: "\e131"; } -i.icon-mouse:before { +.icon-mouse:before { content: "\e132"; } -i.icon-movie-alt:before { +.icon-movie-alt:before { content: "\e133"; } -i.icon-map-marker:before { +.icon-map-marker:before { content: "\e134"; } -i.icon-movie:before { +.icon-movie:before { content: "\e135"; } -i.icon-map-location:before { +.icon-map-location:before { content: "\e136"; } -i.icon-map-alt:before { +.icon-map-alt:before { content: "\e137"; } -i.icon-male-symbol:before { +.icon-male-symbol:before { content: "\e138"; } -i.icon-male-and-female:before { +.icon-male-and-female:before { content: "\e139"; } -i.icon-mailbox:before { +.icon-mailbox:before { content: "\e13a"; } -i.icon-magnet:before { +.icon-magnet:before { content: "\e13b"; } -i.icon-loupe:before { +.icon-loupe:before { content: "\e13c"; } -i.icon-mobile:before { +.icon-mobile:before { content: "\e13d"; } -i.icon-logout:before { +.icon-logout:before { content: "\e13e"; } -i.icon-log-out:before { +.icon-log-out:before { content: "\e13f"; } -i.icon-layers:before { +.icon-layers:before { content: "\e140"; } -i.icon-left-double-arrow:before { +.icon-left-double-arrow:before { content: "\e141"; } -i.icon-layout:before { +.icon-layout:before { content: "\e142"; } -i.icon-legal:before { +.icon-legal:before { content: "\e143"; } -i.icon-lense:before { +.icon-lense:before { content: "\e144"; } -i.icon-library:before { +.icon-library:before { content: "\e145"; } -i.icon-light-down:before { +.icon-light-down:before { content: "\e146"; } -i.icon-light-up:before { +.icon-light-up:before { content: "\e147"; } -i.icon-lightbulb-active:before { +.icon-lightbulb-active:before { content: "\e148"; } -i.icon-lightbulb:before { +.icon-lightbulb:before { content: "\e149"; } -i.icon-ipad:before { +.icon-ipad:before { content: "\e14a"; } -i.icon-invoice:before { +.icon-invoice:before { content: "\e14b"; } -i.icon-info:before { +.icon-info:before { content: "\e14c"; } -i.icon-infinity:before { +.icon-infinity:before { content: "\e14d"; } -i.icon-indent:before { +.icon-indent:before { content: "\e14e"; } -i.icon-inbox:before { +.icon-inbox:before { content: "\e14f"; } -i.icon-inbox-full:before { +.icon-inbox-full:before { content: "\e150"; } -i.icon-inactive-line:before { +.icon-inactive-line:before { content: "\e151"; } -i.icon-imac:before { +.icon-imac:before { content: "\e152"; } -i.icon-hourglass:before { +.icon-hourglass:before { content: "\e153"; } -i.icon-home:before { +.icon-home:before { content: "\e154"; } -i.icon-grid:before { +.icon-grid:before { content: "\e155"; } -i.icon-food:before { +.icon-food:before { content: "\e156"; } -i.icon-favorite:before { +.icon-favorite:before { content: "\e157"; } -i.icon-door-open-alt:before { +.icon-door-open-alt:before { content: "\e158"; } -i.icon-diagnostics:before { +.icon-diagnostics:before { content: "\e159"; } -i.icon-contrast:before { +.icon-contrast:before { content: "\e15a"; } -i.icon-coins-dollar-alt:before { +.icon-coins-dollar-alt:before { content: "\e15b"; } -i.icon-circle-dotted-active:before { +.icon-circle-dotted-active:before { content: "\e15c"; } -i.icon-cinema:before { +.icon-cinema:before { content: "\e15d"; } -i.icon-chip:before { +.icon-chip:before { content: "\e15e"; } -i.icon-chip-alt:before { +.icon-chip-alt:before { content: "\e15f"; } -i.icon-chess:before { +.icon-chess:before { content: "\e160"; } -i.icon-checkbox:before { +.icon-checkbox:before { content: "\e161"; } -i.icon-checkbox-empty:before { +.icon-checkbox-empty:before { content: "\e162"; } -i.icon-checkbox-dotted:before { +.icon-checkbox-dotted:before { content: "\e163"; } -i.icon-checkbox-dotted-active:before { +.icon-checkbox-dotted-active:before { content: "\e164"; } -i.icon-check:before { +.icon-check:before { content: "\e165"; } -i.icon-chat:before { +.icon-chat:before { content: "\e166"; } -i.icon-chat-active:before { +.icon-chat-active:before { content: "\e167"; } -i.icon-chart:before { +.icon-chart:before { content: "\e168"; } -i.icon-chart-curve:before { +.icon-chart-curve:before { content: "\e169"; } -i.icon-certificate:before { +.icon-certificate:before { content: "\e16a"; } -i.icon-categories:before { +.icon-categories:before { content: "\e16b"; } -i.icon-cash-register:before { +.icon-cash-register:before { content: "\e16c"; } -i.icon-car:before { +.icon-car:before { content: "\e16d"; } -i.icon-caps-lock:before { +.icon-caps-lock:before { content: "\e16e"; } -i.icon-candy:before { +.icon-candy:before { content: "\e16f"; } -i.icon-circle-dotted:before { +.icon-circle-dotted:before { content: "\e170"; } -i.icon-circuits:before { +.icon-circuits:before { content: "\e171"; } -i.icon-circus:before { +.icon-circus:before { content: "\e172"; } -i.icon-client:before { +.icon-client:before { content: "\e173"; } -i.icon-clothes-hanger:before { +.icon-clothes-hanger:before { content: "\e174"; } -i.icon-cloud-drive:before { +.icon-cloud-drive:before { content: "\e175"; } -i.icon-cloud-upload:before { +.icon-cloud-upload:before { content: "\e176"; } -i.icon-cloud:before { +.icon-cloud:before { content: "\e177"; } -i.icon-cloudy:before { +.icon-cloudy:before { content: "\e178"; } -i.icon-clubs:before { +.icon-clubs:before { content: "\e179"; } -i.icon-cocktail:before { +.icon-cocktail:before { content: "\e17a"; } -i.icon-code:before { +.icon-code:before { content: "\e17b"; } -i.icon-coffee:before { +.icon-coffee:before { content: "\e17c"; } -i.icon-coin-dollar:before { +.icon-coin-dollar:before { content: "\e17d"; } -i.icon-coin-pound:before { +.icon-coin-pound:before { content: "\e17e"; } -i.icon-coin-yen:before { +.icon-coin-yen:before { content: "\e17f"; } -i.icon-coin:before { +.icon-coin:before { content: "\e180"; } -i.icon-coins-alt:before { +.icon-coins-alt:before { content: "\e181"; } -i.icon-console:before { +.icon-console:before { content: "\e182"; } -i.icon-connection:before { +.icon-connection:before { content: "\e183"; } -i.icon-compress:before { +.icon-compress:before { content: "\e184"; } -i.icon-company:before { +.icon-company:before { content: "\e185"; } -i.icon-command:before { +.icon-command:before { content: "\e186"; } -i.icon-coin-euro:before { +.icon-coin-euro:before { content: "\e187"; } -i.icon-combination-lock:before { +.icon-combination-lock:before { content: "\e188"; } -i.icon-combination-lock-open:before { +.icon-combination-lock-open:before { content: "\e189"; } -i.icon-comb:before { +.icon-comb:before { content: "\e18a"; } -i.icon-columns:before { +.icon-columns:before { content: "\e18b"; } -i.icon-colorpicker:before { +.icon-colorpicker:before { content: "\e18c"; } -i.icon-color-bucket:before { +.icon-color-bucket:before { content: "\e18d"; } -i.icon-coins:before { +.icon-coins:before { content: "\e18e"; } -i.icon-coins-yen:before { +.icon-coins-yen:before { content: "\e18f"; } -i.icon-coins-yen-alt:before { +.icon-coins-yen-alt:before { content: "\e190"; } -i.icon-coins-pound:before { +.icon-coins-pound:before { content: "\e191"; } -i.icon-coins-pound-alt:before { +.icon-coins-pound-alt:before { content: "\e192"; } -i.icon-coins-euro:before { +.icon-coins-euro:before { content: "\e193"; } -i.icon-coins-euro-alt:before { +.icon-coins-euro-alt:before { content: "\e194"; } -i.icon-coins-dollar:before { +.icon-coins-dollar:before { content: "\e195"; } -i.icon-conversation-alt:before { +.icon-conversation-alt:before { content: "\e196"; } -i.icon-conversation:before { +.icon-conversation:before { content: "\e197"; } -i.icon-coverflow:before { +.icon-coverflow:before { content: "\e198"; } -i.icon-credit-card-alt:before { +.icon-credit-card-alt:before { content: "\e199"; } -i.icon-credit-card:before { +.icon-credit-card:before { content: "\e19a"; } -i.icon-crop:before { +.icon-crop:before { content: "\e19b"; } -i.icon-crosshair:before { +.icon-crosshair:before { content: "\e19c"; } -i.icon-crown-alt:before { +.icon-crown-alt:before { content: "\e19d"; } -i.icon-crown:before { +.icon-crown:before { content: "\e19e"; } -i.icon-cupcake:before { +.icon-cupcake:before { content: "\e19f"; } -i.icon-curve:before { +.icon-curve:before { content: "\e1a0"; } -i.icon-cut:before { +.icon-cut:before { content: "\e1a1"; } -i.icon-dashboard:before { +.icon-dashboard:before { content: "\e1a2"; } -i.icon-defrag:before { +.icon-defrag:before { content: "\e1a3"; } -i.icon-delete:before { +.icon-delete:before { content: "\e1a4"; } -i.icon-delete-key:before { +.icon-delete-key:before { content: "\e1a5"; } -i.icon-departure:before { +.icon-departure:before { content: "\e1a6"; } -i.icon-desk:before { +.icon-desk:before { content: "\e1a7"; } -i.icon-desktop:before { +.icon-desktop:before { content: "\e1a8"; } -i.icon-donate:before { +.icon-donate:before { content: "\e1a9"; } -i.icon-dollar-bag:before { +.icon-dollar-bag:before { content: "\e1aa"; } -i.icon-documents:before { +.icon-documents:before { content: "\e1ab"; } -i.icon-document:before { +.icon-document:before { content: "\e1ac"; } -i.icon-document-dashed-line:before { +.icon-document-dashed-line:before { content: "\e1ad"; } -i.icon-dock-connector:before { +.icon-dock-connector:before { content: "\e1ae"; } -i.icon-dna:before { +.icon-dna:before { content: "\e1af"; } -i.icon-display:before { +.icon-display:before { content: "\e1b0"; } -i.icon-disk-image:before { +.icon-disk-image:before { content: "\e1b1"; } -i.icon-disc:before { +.icon-disc:before { content: "\e1b2"; } -i.icon-directions:before { +.icon-directions:before { content: "\e1b3"; } -i.icon-directions-alt:before { +.icon-directions-alt:before { content: "\e1b4"; } -i.icon-diploma:before { +.icon-diploma:before { content: "\e1b5"; } -i.icon-diploma-alt:before { +.icon-diploma-alt:before { content: "\e1b6"; } -i.icon-dice:before { +.icon-dice:before { content: "\e1b7"; } -i.icon-diamonds:before { +.icon-diamonds:before { content: "\e1b8"; } -i.icon-diamond:before { +.icon-diamond:before { content: "\e1b9"; } -i.icon-diagonal-arrow:before { +.icon-diagonal-arrow:before { content: "\e1ba"; } -i.icon-diagonal-arrow-alt:before { +.icon-diagonal-arrow-alt:before { content: "\e1bb"; } -i.icon-door-open:before { +.icon-door-open:before { content: "\e1bc"; } -i.icon-download-alt:before { +.icon-download-alt:before { content: "\e1bd"; } -i.icon-download:before { +.icon-download:before { content: "\e1be"; } -i.icon-drop:before { +.icon-drop:before { content: "\e1bf"; } -i.icon-eco:before { +.icon-eco:before { content: "\e1c0"; } -i.icon-economy:before { +.icon-economy:before { content: "\e1c1"; } -i.icon-edit:before { +.icon-edit:before { content: "\e1c2"; } -i.icon-eject:before { +.icon-eject:before { content: "\e1c3"; } -i.icon-employee:before { +.icon-employee:before { content: "\e1c4"; } -i.icon-energy-saving-bulb:before { +.icon-energy-saving-bulb:before { content: "\e1c5"; } -i.icon-enter:before { +.icon-enter:before { content: "\e1c6"; } -i.icon-equalizer:before { +.icon-equalizer:before { content: "\e1c7"; } -i.icon-escape:before { +.icon-escape:before { content: "\e1c8"; } -i.icon-ethernet:before { +.icon-ethernet:before { content: "\e1c9"; } -i.icon-euro-bag:before { +.icon-euro-bag:before { content: "\e1ca"; } -i.icon-exit-fullscreen:before { +.icon-exit-fullscreen:before { content: "\e1cb"; } -i.icon-eye:before { +.icon-eye:before { content: "\e1cc"; } -i.icon-facebook-like:before { +.icon-facebook-like:before { content: "\e1cd"; } -i.icon-factory:before { +.icon-factory:before { content: "\e1ce"; } -i.icon-font:before { +.icon-font:before { content: "\e1cf"; } -i.icon-folders:before { +.icon-folders:before { content: "\e1d0"; } -i.icon-folder:before, i.icon-folder-close:before { +.icon-folder:before, .icon-folder-close:before { content: "\e1d1"; } -i.icon-folder-outline:before { +.icon-folder-outline:before { content: "\e1d2"; } -i.icon-folder-open:before { +.icon-folder-open:before { content: "\e1d3"; } -i.icon-flowerpot:before { +.icon-flowerpot:before { content: "\e1d4"; } -i.icon-flashlight:before { +.icon-flashlight:before { content: "\e1d5"; } -i.icon-flash:before { +.icon-flash:before { content: "\e1d6"; } -i.icon-flag:before { +.icon-flag:before { content: "\e1d7"; } -i.icon-flag-alt:before { +.icon-flag-alt:before { content: "\e1d8"; } -i.icon-firewire:before { +.icon-firewire:before { content: "\e1d9"; } -i.icon-firewall:before { +.icon-firewall:before { content: "\e1da"; } -i.icon-fire:before { +.icon-fire:before { content: "\e1db"; } -i.icon-fingerprint:before { +.icon-fingerprint:before { content: "\e1dc"; } -i.icon-filter:before { +.icon-filter:before { content: "\e1dd"; } -i.icon-filter-arrows:before { +.icon-filter-arrows:before { content: "\e1de"; } -i.icon-files:before { +.icon-files:before { content: "\e1df"; } -i.icon-file-cabinet:before { +.icon-file-cabinet:before { content: "\e1e0"; } -i.icon-female-symbol:before { +.icon-female-symbol:before { content: "\e1e1"; } -i.icon-footprints:before { +.icon-footprints:before { content: "\e1e2"; } -i.icon-hammer:before { +.icon-hammer:before { content: "\e1e3"; } -i.icon-hand-active-alt:before { +.icon-hand-active-alt:before { content: "\e1e4"; } -i.icon-forking:before { +.icon-forking:before { content: "\e1e5"; } -i.icon-hand-active:before { +.icon-hand-active:before { content: "\e1e6"; } -i.icon-hand-pointer-alt:before { +.icon-hand-pointer-alt:before { content: "\e1e7"; } -i.icon-hand-pointer:before { +.icon-hand-pointer:before { content: "\e1e8"; } -i.icon-handprint:before { +.icon-handprint:before { content: "\e1e9"; } -i.icon-handshake:before { +.icon-handshake:before { content: "\e1ea"; } -i.icon-handtool:before { +.icon-handtool:before { content: "\e1eb"; } -i.icon-hard-drive:before { +.icon-hard-drive:before { content: "\e1ec"; } -i.icon-help:before { +.icon-help:before { content: "\e1ed"; } -i.icon-graduate:before { +.icon-graduate:before { content: "\e1ee"; } -i.icon-gps:before { +.icon-gps:before { content: "\e1ef"; } -i.icon-help-alt:before { +.icon-help-alt:before { content: "\e1f0"; } -i.icon-height:before { +.icon-height:before { content: "\e1f1"; } -i.icon-globe:before { +.icon-globe:before { content: "\e1f2"; } -i.icon-hearts:before { +.icon-hearts:before { content: "\e1f3"; } -i.icon-globe-inverted-europe-africa:before { +.icon-globe-inverted-europe-africa:before { content: "\e1f4"; } -i.icon-headset:before { +.icon-headset:before { content: "\e1f5"; } -i.icon-globe-inverted-asia:before { +.icon-globe-inverted-asia:before { content: "\e1f6"; } -i.icon-headphones:before { +.icon-headphones:before { content: "\e1f7"; } -i.icon-globe-inverted-america:before { +.icon-globe-inverted-america:before { content: "\e1f8"; } -i.icon-hd:before { +.icon-hd:before { content: "\e1f9"; } -i.icon-globe-europe-africa:before, -i.icon-globe-europe---africa:before { +.icon-globe-europe-africa:before, +.icon-globe-europe---africa:before { content: "\e1fa"; } -i.icon-hat:before { +.icon-hat:before { content: "\e1fb"; } -i.icon-globe-asia:before { +.icon-globe-asia:before { content: "\e1fc"; } -i.icon-globe-alt:before { +.icon-globe-alt:before { content: "\e1fd"; } -i.icon-hard-drive-alt:before { +.icon-hard-drive-alt:before { content: "\e1fe"; } -i.icon-glasses:before { +.icon-glasses:before { content: "\e1ff"; } -i.icon-gift:before { +.icon-gift:before { content: "\e200"; } -i.icon-handtool-alt:before { +.icon-handtool-alt:before { content: "\e201"; } -i.icon-geometry:before { +.icon-geometry:before { content: "\e202"; } -i.icon-game:before { +.icon-game:before { content: "\e203"; } -i.icon-fullscreen:before { +.icon-fullscreen:before { content: "\e204"; } -i.icon-fullscreen-alt:before { +.icon-fullscreen-alt:before { content: "\e205"; } -i.icon-frame:before { +.icon-frame:before { content: "\e206"; } -i.icon-frame-alt:before { +.icon-frame-alt:before { content: "\e207"; } -i.icon-camera-roll:before { +.icon-camera-roll:before { content: "\e208"; } -i.icon-bookmark:before { +.icon-bookmark:before { content: "\e209"; } -i.icon-bill:before { +.icon-bill:before { content: "\e20a"; } -i.icon-baby-stroller:before { +.icon-baby-stroller:before { content: "\e20b"; } -i.icon-alarm-clock:before { +.icon-alarm-clock:before { content: "\e20c"; } -i.icon-addressbook:before, -i.icon-adressbook:before { +.icon-addressbook:before, +.icon-adressbook:before { content: "\e20d"; } -i.icon-add:before { +.icon-add:before { content: "\e20e"; } -i.icon-activity:before { +.icon-activity:before { content: "\e20f"; } -i.icon-untitled:before { +.icon-untitled:before { content: "\e210"; } -i.icon-glasses:before { +.icon-glasses:before { content: "\e211"; } -i.icon-camcorder:before { +.icon-camcorder:before { content: "\e212"; } -i.icon-calendar:before { +.icon-calendar:before { content: "\e213"; } -i.icon-calendar-alt:before { +.icon-calendar-alt:before { content: "\e214"; } -i.icon-calculator:before { +.icon-calculator:before { content: "\e215"; } -i.icon-bus:before { +.icon-bus:before { content: "\e216"; } -i.icon-burn:before { +.icon-burn:before { content: "\e217"; } -i.icon-bulleted-list:before { +.icon-bulleted-list:before { content: "\e218"; } -i.icon-bug:before { +.icon-bug:before { content: "\e219"; } -i.icon-brush:before { +.icon-brush:before { content: "\e21a"; } -i.icon-brush-alt:before { +.icon-brush-alt:before { content: "\e21b"; } -i.icon-brush-alt-2:before { +.icon-brush-alt-2:before { content: "\e21c"; } -i.icon-browser-window:before { +.icon-browser-window:before { content: "\e21d"; } -i.icon-briefcase:before { +.icon-briefcase:before { content: "\e21e"; } -i.icon-brick:before { +.icon-brick:before { content: "\e21f"; } -i.icon-brackets:before { +.icon-brackets:before { content: "\e220"; } -i.icon-box:before { +.icon-box:before { content: "\e221"; } -i.icon-box-open:before { +.icon-box-open:before { content: "\e222"; } -i.icon-box-alt:before { +.icon-box-alt:before { content: "\e223"; } -i.icon-books:before { +.icon-books:before { content: "\e224"; } -i.icon-billboard:before { +.icon-billboard:before { content: "\e225"; } -i.icon-bills-dollar:before { +.icon-bills-dollar:before { content: "\e226"; } -i.icon-bills-euro:before { +.icon-bills-euro:before { content: "\e227"; } -i.icon-bills-pound:before { +.icon-bills-pound:before { content: "\e228"; } -i.icon-bills-yen:before { +.icon-bills-yen:before { content: "\e229"; } -i.icon-bills:before { +.icon-bills:before { content: "\e22a"; } -i.icon-binarycode:before { +.icon-binarycode:before { content: "\e22b"; } -i.icon-binoculars:before { +.icon-binoculars:before { content: "\e22c"; } -i.icon-bird:before { +.icon-bird:before { content: "\e22d"; } -i.icon-birthday-cake:before { +.icon-birthday-cake:before { content: "\e22e"; } -i.icon-blueprint:before { +.icon-blueprint:before { content: "\e22f"; } -i.icon-block:before { +.icon-block:before { content: "\e230"; } -i.icon-bluetooth:before { +.icon-bluetooth:before { content: "\e231"; } -i.icon-boat-shipping:before { +.icon-boat-shipping:before { content: "\e232"; } -i.icon-bomb:before { +.icon-bomb:before { content: "\e233"; } -i.icon-book-alt-2:before { +.icon-book-alt-2:before { content: "\e234"; } -i.icon-bones:before { +.icon-bones:before { content: "\e235"; } -i.icon-book-alt:before { +.icon-book-alt:before { content: "\e236"; } -i.icon-book:before { +.icon-book:before { content: "\e237"; } -i.icon-bill-yen:before { +.icon-bill-yen:before { content: "\e238"; } -i.icon-award:before { +.icon-award:before { content: "\e239"; } -i.icon-bill-pound:before { +.icon-bill-pound:before { content: "\e23a"; } -i.icon-autofill:before { +.icon-autofill:before { content: "\e23b"; } -i.icon-bill-euro:before { +.icon-bill-euro:before { content: "\e23c"; } -i.icon-auction-hammer:before { +.icon-auction-hammer:before { content: "\e23d"; } -i.icon-bill-dollar:before { +.icon-bill-dollar:before { content: "\e23e"; } -i.icon-attachment:before { +.icon-attachment:before { content: "\e23f"; } -i.icon-bell:before { +.icon-bell:before { content: "\e240"; } -i.icon-article:before { +.icon-article:before { content: "\e241"; } -i.icon-bell-off:before { +.icon-bell-off:before { content: "\e242"; } -i.icon-art-easel:before { +.icon-art-easel:before { content: "\e243"; } -i.icon-beer-glass:before { +.icon-beer-glass:before { content: "\e244"; } -i.icon-arrow-up:before { +.icon-arrow-up:before { content: "\e245"; } -i.icon-battery-low:before { +.icon-battery-low:before { content: "\e246"; } -i.icon-arrow-right:before { +.icon-arrow-right:before { content: "\e247"; } -i.icon-battery-full:before { +.icon-battery-full:before { content: "\e248"; } -i.icon-arrow-left:before { +.icon-arrow-left:before { content: "\e249"; } -i.icon-bars:before { +.icon-bars:before { content: "\e24a"; } -i.icon-arrow-down:before { +.icon-arrow-down:before { content: "\e24b"; } -i.icon-barcode:before { +.icon-barcode:before { content: "\e24c"; } -i.icon-arrivals:before { +.icon-arrivals:before { content: "\e24d"; } -i.icon-bar-chart:before { +.icon-bar-chart:before { content: "\e24e"; } -i.icon-application-window:before { +.icon-application-window:before { content: "\e24f"; } -i.icon-band-aid:before { +.icon-band-aid:before { content: "\e250"; } -i.icon-application-window-alt:before { +.icon-application-window-alt:before { content: "\e251"; } -i.icon-ball:before { +.icon-ball:before { content: "\e252"; } -i.icon-application-error:before { +.icon-application-error:before { content: "\e253"; } -i.icon-badge-restricted:before { +.icon-badge-restricted:before { content: "\e254"; } -i.icon-app:before { +.icon-app:before { content: "\e255"; } -i.icon-badge-remove:before { +.icon-badge-remove:before { content: "\e256"; } -i.icon-anchor:before { +.icon-anchor:before { content: "\e257"; } -i.icon-badge-count:before { +.icon-badge-count:before { content: "\e258"; } -i.icon-alt:before { +.icon-alt:before { content: "\e259"; } -i.icon-badge-add:before { +.icon-badge-add:before { content: "\e25a"; } -i.icon-alert:before { +.icon-alert:before { content: "\e25b"; } -i.icon-backspace:before { +.icon-backspace:before { content: "\e25c"; } -i.icon-alert-alt:before { +.icon-alert-alt:before { content: "\e25d"; } -i.icon-section:before { +.icon-section:before { content: "\e24f"; } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.controller.js index 5036aebe2e..44b10b852d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.controller.js @@ -6,7 +6,7 @@ * @description * The controller for the content type editor icon picker */ -function IconPickerController($scope, $http, $sce, localizationService, iconHelper) { +function IconPickerController($scope, localizationService, iconHelper) { var vm = this; @@ -42,19 +42,11 @@ function IconPickerController($scope, $http, $sce, localizationService, iconHelp vm.loading = true; setTitle(); - - iconHelper.getAllIcons() - .then(icons => { - vm.icons = icons; - vm.loading = false; - iconHelper.getLegacyIcons() - .then(icons => { - if(icons && icons.length > 0) { - vm.icons = icons.concat(vm.icons); - } - }); - }); + iconHelper.getIcons().then(function (icons) { + vm.icons = icons; + vm.loading = false; + }); // set a default color if nothing is passed in vm.color = $scope.model.color ? findColor($scope.model.color) : vm.colors.find(x => x.default); @@ -96,7 +88,7 @@ function IconPickerController($scope, $http, $sce, localizationService, iconHelp } function submit() { - if ($scope.model && $scope.model.submit) { + if ($scope.model && $scope.model.submit) { $scope.model.submit($scope.model); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html index 417e6992bd..dd2ff41efa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html @@ -45,10 +45,10 @@
    -
  • -
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html index 211c501e53..f41390bce3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html @@ -69,9 +69,9 @@ prevent-default> Last Updated - +
- +
@@ -79,15 +79,15 @@
- +
- + {{item.name}}
{{item.updateDate | date:'medium'}} -
+
From b1179ff6f1bbd59e933b48c89ef9d9f7c9f76b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 28 Sep 2020 17:57:04 +0200 Subject: [PATCH 20/53] adjust default size of umb-button-ellipsis and its apperance in umb-tree (cherry picked from commit 5d9389b37c9f4687774b9b6d7998ccbf4eba3522) --- .../src/less/components/buttons/umb-button-ellipsis.less | 9 +++++++-- .../src/less/components/tree/umb-tree-root.less | 4 +++- .../src/less/components/tree/umb-tree.less | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less index 54302ba869..7104e6478f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less @@ -4,10 +4,10 @@ margin: 0 auto; cursor: pointer; border-radius: @baseBorderRadius; - color: black; + color: @ui-action-discreet-type; position: relative; opacity: 0.8; - transition: opacity .3s ease-out; + transition: opacity 120ms, color 120ms; &--absolute { position: absolute; @@ -23,6 +23,10 @@ justify-content: center; } + &:hover { + color: @ui-action-discreet-type-hover; + } + .umb-button-ellipsis--tab, .umb-tour-is-visible .umb-tree &, &:hover, @@ -47,6 +51,7 @@ &__icon { color: inherit; flex-basis: 100%; + font-size: 12px; .umb-button-ellipsis--tab & { margin: 0 0 7px; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less index a3529d5504..ba33883b08 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less @@ -1,5 +1,7 @@ -.umb-tree-root { +.umb-tree-root { + border: 2px solid transparent; + &-link { display: flex; align-items: center; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less index d4599ea03d..bf8e7fdb70 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less @@ -95,7 +95,6 @@ body.touch .umb-tree { position: relative; width: auto; height: auto; - margin: 0 5px 0 auto; overflow: visible; clip: auto; } @@ -185,9 +184,10 @@ body.touch .umb-tree { flex: 0 0 auto; justify-content: flex-end; text-align: center; - margin: 0 5px 0 auto; + margin: 0 10px 0 auto; cursor: pointer; border-radius: @baseBorderRadius; + transition: background-color 120ms; .umb-button-ellipsis { padding: 3px 5px; @@ -207,7 +207,7 @@ body.touch .umb-tree { } &:hover { - background: rgba(255, 255, 255, .5); + background-color: rgba(255, 255, 255, .8); i { background: @ui-active-type-hover; From 0f2283e07862237d2fb62c88cb691fe533d17591 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 28 Sep 2020 20:05:08 +0200 Subject: [PATCH 21/53] Bump version to 8.8.0 --- src/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 26496aa9e6..3f512bc65a 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-rc")] +[assembly: AssemblyInformationalVersion("8.8.0")] From 05295cfef9b1c1c494a782075912419a2e030cca Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 12:49:02 +0200 Subject: [PATCH 22/53] Add hub files to Backoffice --- .../SignalR/IPreviewHub.cs | 14 ++++++ .../SignalR/PreviewHub.cs | 8 ++++ .../SignalR/PreviewHubComponent.cs | 48 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs create mode 100644 src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs create mode 100644 src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs diff --git a/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs b/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs new file mode 100644 index 0000000000..32ddb262d0 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.SignalR; + +namespace Umbraco.Web.BackOffice.SignalR +{ + public interface IPreviewHub + { + // define methods implemented by client + // ReSharper disable InconsistentNaming + + void refreshed(int id); + + // ReSharper restore InconsistentNaming + } +} diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs new file mode 100644 index 0000000000..794e38b678 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.SignalR; +using System.Threading.Tasks; + +namespace Umbraco.Web.BackOffice.SignalR +{ + public class PreviewHub : Hub + { } +} diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs new file mode 100644 index 0000000000..2805ea7e98 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs @@ -0,0 +1,48 @@ +using System; +using System.Configuration; +using Microsoft.AspNetCore.SignalR; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Sync; +using Umbraco.Web.Cache; + +namespace Umbraco.Web.BackOffice.SignalR +{ + public class PreviewHubComponent : IComponent + { + private readonly Lazy> _hubContext; + + // using a lazy arg here means that we won't create the hub until necessary + // and therefore we won't have too bad an impact on boot time + public PreviewHubComponent(Lazy> hubContext) + { + _hubContext = hubContext; + } + + public void Initialize() + { + // ContentService.Saved is too soon - the content cache is not ready yet, + // so use the content cache refresher event, because when it triggers + // the cache has already been notified of the changes + + ContentCacheRefresher.CacheUpdated += HandleCacheUpdated; + } + + public void Terminate() + { + ContentCacheRefresher.CacheUpdated -= HandleCacheUpdated; + } + + private void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) + { + if (args.MessageType != MessageType.RefreshByPayload) return; + var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject; + var hubContextInstance = _hubContext.Value; + foreach (var payload in payloads) + { + var id = payload.Id; // keep it simple for now, ignore ChangeTypes + hubContextInstance.Clients.All.refreshed(id); + } + } + } +} From aa53c625a7d56301e824529b07e8bb8f74a9a4b8 Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 12:49:32 +0200 Subject: [PATCH 23/53] Register SignalR --- .../Extensions/BackOfficeServiceCollectionExtensions.cs | 6 ++++++ .../Extensions/UmbracoBuilderExtensions.cs | 4 ++++ src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs | 6 ++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs index 4e00525c2a..be18faf4ee 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs @@ -45,6 +45,12 @@ namespace Umbraco.Extensions services.ConfigureOptions(); } + // AddUmbracoPreview -> Use in UmbracoBuilderExtensions + public static void AddUmbracoPreview(this IServiceCollection services) + { + services.AddSignalR(); + } + /// /// Adds the services required for using Umbraco back office Identity /// diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs index 71325d70d4..a1a671527a 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs @@ -16,6 +16,7 @@ namespace Umbraco.Extensions .WithMiniProfiler() .WithMvcAndRazor() .WithWebServer() + .WithPreview() .Build(); } @@ -24,5 +25,8 @@ namespace Umbraco.Extensions public static IUmbracoBuilder WithBackOfficeIdentity(this IUmbracoBuilder builder) => builder.AddWith(nameof(WithBackOfficeIdentity), () => builder.Services.AddUmbracoBackOfficeIdentity()); + + public static IUmbracoBuilder WithPreview(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithPreview), () => builder.Services.AddUmbracoPreview()); } } diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index dd3b3988c9..cd8aaabf27 100644 --- a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -1,10 +1,12 @@ -using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.SignalR; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Routing; using Umbraco.Web.WebApi; @@ -50,8 +52,8 @@ namespace Umbraco.Web.BackOffice.Routing MapMinimalBackOffice(endpoints); endpoints.MapUmbracoRoute(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, null); + endpoints.MapHub("/umbraco/previewHub"); AutoRouteBackOfficeControllers(endpoints); - break; case RuntimeLevel.BootFailed: case RuntimeLevel.Unknown: From 078ab74a8f49669b2e60f7d0b5861fa601a88466 Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 12:49:59 +0200 Subject: [PATCH 24/53] Update signalR to core version --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index e0afe1c2a7..75626a8cd6 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -10,6 +10,7 @@ "watch": "gulp watch" }, "dependencies": { + "@microsoft/signalr": "^3.1.8", "ace-builds": "1.4.2", "angular": "1.8.0", "angular-animate": "1.7.5", @@ -40,7 +41,6 @@ "ng-file-upload": "12.2.13", "nouislider": "14.6.1", "npm": "^6.14.7", - "signalr": "2.4.0", "spectrum-colorpicker2": "2.0.3", "tinymce": "4.9.11", "typeahead.js": "0.11.1", From e9cf22735d78587f9a5a64039f80d3cab675ac29 Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 13:00:39 +0200 Subject: [PATCH 25/53] Use HubConnectionBuilder in preview.controller --- .../src/preview/preview.controller.js | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 5d1047de1b..6f12027079 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -11,7 +11,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi var cultures = []; $scope.tabbingActive = false; - // There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution. + // There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution. // For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 function handleFirstTab(evt) { if (evt.keyCode === 9) { @@ -45,7 +45,9 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi function configureSignalR(iframe) { // signalr hub - var previewHub = $.connection.previewHub; + var previewHub = new signalR.HubConnectionBuilder() + .withUrl("/umbraco/previewHub") + .build(); // visibility tracking var dirtyContent = false; @@ -61,33 +63,31 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi } }); - if (previewHub && previewHub.client) { - previewHub.client.refreshed = function (message, sender) { - console.log("Notified by SignalR preview hub (" + message + ")."); - - if ($scope.pageId != message) { - console.log("Not a notification for us (" + $scope.pageId + ")."); - return; - } - - if (!visibleContent) { - console.log("Not visible, will reload."); - dirtyContent = true; - return; - } - - console.log("Reloading."); - var iframeDoc = (iframe.contentWindow || iframe.contentDocument); - iframeDoc.location.reload(); - }; - } + previewHub.on("refreshed", function (message) { + console.log('Notified by SignalR preview hub (' + message + ').'); + if ($scope.pageId != message) { + console.log('Not a notification for us (' + $scope.pageId + ').'); + return; + } + if (!visibleContent) { + console.log('Not visible, will reload.'); + dirtyContent = true; + return; + } + console.log('Reloading.'); + var iframeDoc = iframe.contentWindow || iframe.contentDocument; + iframeDoc.location.reload(); + }) try { - $.connection.hub.start() - .done(function () { console.log("Connected to SignalR preview hub (ID=" + $.connection.hub.id + ")"); }) - .fail(function () { console.log("Could not connect to SignalR preview hub."); }); + previewHub.start().then(function () { + // console.log('Connected to SignalR preview hub (ID=' + $.connection.hub.id + ')'); + console.log('SignalR is ' + previewHub.state); + }).catch(function () { + console.log('Could not connect to SignalR preview hub.'); + }); } catch (e) { - console.error("Could not establish signalr connection. Error: " + e); + console.error('Could not establish signalr connection. Error: ' + e); } } @@ -95,7 +95,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi if (isInit === "true") { //do not continue, this is the first load of this new window, if this is passed in it means it's been //initialized by the content editor and then the content editor will actually re-load this window without - //this flag. This is a required trick to get around chrome popup mgr. + //this flag. This is a required trick to get around chrome popup mgr. return; } From 2d760a77445dedcc2cbb677532b651c097ea9619 Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Tue, 29 Sep 2020 13:18:12 +0200 Subject: [PATCH 26/53] Update dependencies in gulp --- src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js index 93191dbaf5..3f1d5f21f9 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js @@ -212,8 +212,11 @@ function dependencies() { }, { "name": "signalr", - "src": ["./node_modules/signalr/jquery.signalR.js"], - "base": "./node_modules/signalr" + "src": [ + "./node_modules/@microsoft/signalr/dist/browser/signalr.js", + "./node_modules/@microsoft/signalr/dist/browser/signalr.min.js", + ], + "base": "./node_modules/@microsoft/dist/browser" }, { "name": "spectrum", From 6ced0de2c470a69b45c890f63a4a5e56ff5a5b28 Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 13:32:08 +0200 Subject: [PATCH 27/53] Fix gulp dependencies --- src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js index 3f1d5f21f9..8d0547522d 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js @@ -216,7 +216,7 @@ function dependencies() { "./node_modules/@microsoft/signalr/dist/browser/signalr.js", "./node_modules/@microsoft/signalr/dist/browser/signalr.min.js", ], - "base": "./node_modules/@microsoft/dist/browser" + "base": "./node_modules/@microsoft/signalr/dist/browser" }, { "name": "spectrum", From f9bd33dafe554ddb2ff82a4f956b4fd0a4db72ac Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 13:50:32 +0200 Subject: [PATCH 28/53] Include new SignalR in preview view --- src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js b/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js index 764e354d5f..45ee39eefc 100644 --- a/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js +++ b/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js @@ -8,7 +8,6 @@ 'js/umbraco.services.js', 'js/umbraco.interceptors.js', 'ServerVariables', - 'lib/signalr/jquery.signalR.js', - 'BackOffice/signalr/hubs', + 'lib/signalr/signalr.min.js', 'js/umbraco.preview.js' ] From ccab3d22880982d9354963ddff2ee4b452b679cb Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 14:02:27 +0200 Subject: [PATCH 29/53] Make success log notification appear as before --- src/Umbraco.Web.UI.Client/src/preview/preview.controller.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 6f12027079..e7439648fe 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -81,8 +81,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi try { previewHub.start().then(function () { - // console.log('Connected to SignalR preview hub (ID=' + $.connection.hub.id + ')'); - console.log('SignalR is ' + previewHub.state); + console.log('Connected to SignalR preview hub (ID=' + previewHub.connectionId + ')'); }).catch(function () { console.log('Could not connect to SignalR preview hub.'); }); From 2175c8e4a7e8131220797ad5d76f0618b5d857bf Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 29 Sep 2020 15:25:27 +0200 Subject: [PATCH 30/53] Register PreviewHub in composer It actually updates now \o/ --- .../SignalR/IPreviewHub.cs | 5 +++-- .../SignalR/PreviewHubComponent.cs | 4 ++-- .../SignalR/PreviewHubComposer.cs | 17 +++++++++++++++++ .../src/preview/preview.controller.js | 5 +++-- 4 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs diff --git a/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs b/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs index 32ddb262d0..96a28e5c0d 100644 --- a/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.SignalR; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; namespace Umbraco.Web.BackOffice.SignalR { @@ -7,7 +8,7 @@ namespace Umbraco.Web.BackOffice.SignalR // define methods implemented by client // ReSharper disable InconsistentNaming - void refreshed(int id); + Task refreshed(int id); // ReSharper restore InconsistentNaming } diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs index 2805ea7e98..d1f00e9911 100644 --- a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.BackOffice.SignalR ContentCacheRefresher.CacheUpdated -= HandleCacheUpdated; } - private void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) + private async void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) { if (args.MessageType != MessageType.RefreshByPayload) return; var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject; @@ -41,7 +41,7 @@ namespace Umbraco.Web.BackOffice.SignalR foreach (var payload in payloads) { var id = payload.Id; // keep it simple for now, ignore ChangeTypes - hubContextInstance.Clients.All.refreshed(id); + await hubContextInstance.Clients.All.refreshed(id); } } } diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs new file mode 100644 index 0000000000..4a6e3d30d4 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs @@ -0,0 +1,17 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Web.BackOffice.SignalR; + +namespace Umbraco.Web.SignalR +{ + [RuntimeLevel(MinLevel = RuntimeLevel.Run)] + public class PreviewHubComposer : ComponentComposer, ICoreComposer + { + public override void Compose(Composition composition) + { + base.Compose(composition); + + // composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext()); + } + } +} diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index e7439648fe..83176281b0 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -5,7 +5,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.services']) - .controller("previewController", function ($scope, $window, $location) { + .controller("previewController", function ($scope, $window, $location, umbRequestHelper) { $scope.currentCulture = { iso: '', title: '...', icon: 'icon-loading' } var cultures = []; @@ -46,7 +46,8 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi function configureSignalR(iframe) { // signalr hub var previewHub = new signalR.HubConnectionBuilder() - .withUrl("/umbraco/previewHub") + .withUrl("/umbraco/PreviewHub") + .withAutomaticReconnect() .build(); // visibility tracking From 8f5678b226e395f7b0002b81126b25451a8afa2c Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Tue, 29 Sep 2020 17:11:27 +0200 Subject: [PATCH 31/53] Fixes contents of getting-started.json, some misalignments happened when merging v8/dev --- .../BackOfficeTours/getting-started.json | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json b/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json index 7b3f2a2184..1e3c60661d 100644 --- a/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json +++ b/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json @@ -14,6 +14,10 @@ "content": "

Thank you for using Umbraco! Would you like to stay up-to-date with Umbraco product updates, security advisories, community news and special offers? Sign up for our newsletter and never miss out on the latest Umbraco news.

By signing up, you agree that we can use your info according to our privacy policy.

", "view": "emails", "type": "promotion" + }, + { + "title": "Thank you for subscribing to our mailing list", + "view": "confirm" } ] }, @@ -184,27 +188,21 @@ "event": "click" }, { - "element": "[data-element~='editor-data-type-picker']", + "element": "[ng-controller*='Umbraco.Editors.DataTypePickerController'] [data-element='editor-data-type-picker']", "elementPreventClick": true, "title": "Editor picker", - "content": "

In the editor picker dialog we can pick one of the many built-in editors.

You can choose from preconfigured data types (Reuse) or create a new configuration (Available editors).

" + "content": "

In the editor picker dialog we can pick one of the many built-in editors.

" }, { - "element": "[data-element~='editor-data-type-picker'] [data-element='editor-Textarea']", + "element": "[data-element~='editor-data-type-picker'] [data-element='datatype-Textarea']", "title": "Select editor", "content": "Select the Textarea editor. This will add a textarea to the Welcome Text property.", "event": "click" }, { - "element": "[data-element~='editor-data-type-settings']", - "elementPreventClick": true, + "element": "[data-element='editor-data-type-picker'] [data-element='datatypeconfig-Textarea']", "title": "Editor settings", - "content": "Each property editor can have individual settings. For the textarea editor you can set a character limit but in this case it is not needed." - }, - { - "element": "[data-element~='editor-data-type-settings'] [data-element='button-submit']", - "title": "Save editor", - "content": "Click Submit to save the changes.", + "content": "Each property editor can have individual settings. For the textarea editor you can set a character limit but in this case it is not needed.", "event": "click" }, { @@ -313,7 +311,8 @@ "content": "

To see all our templates click the small triangle to the left of the templates node.

", "event": "click", "eventElement": "#tree [data-element='tree-item-templates'] [data-element='tree-item-expand']", - "view": "templatetree" + "view": "templatetree", + "skipStepIfVisible": "#tree [data-element='tree-item-templates'] > div > button[data-element=tree-item-expand].icon-navigation-down" }, { "element": "#tree [data-element='tree-item-templates'] [data-element='tree-item-Home Page']", From b6b41cac5b0a4db0972ad4c9954bb4be205f5b1e Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 30 Sep 2020 09:01:08 +0200 Subject: [PATCH 32/53] Only create one instance of HubConnection --- .../src/preview/preview.controller.js | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 83176281b0..4104ac8b33 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -44,12 +44,6 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi } function configureSignalR(iframe) { - // signalr hub - var previewHub = new signalR.HubConnectionBuilder() - .withUrl("/umbraco/PreviewHub") - .withAutomaticReconnect() - .build(); - // visibility tracking var dirtyContent = false; var visibleContent = true; @@ -64,7 +58,17 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi } }); - previewHub.on("refreshed", function (message) { + // signalr hub + // If connection already exists and is connected just return + // otherwise we'll have multiple connections + if( $.connection && $.connection.connectionState === "Connected") return; + + $.connection = new signalR.HubConnectionBuilder() + .withUrl("/umbraco/PreviewHub") + .withAutomaticReconnect() + .build(); + + $.connection.on("refreshed", function (message) { console.log('Notified by SignalR preview hub (' + message + ').'); if ($scope.pageId != message) { console.log('Not a notification for us (' + $scope.pageId + ').'); @@ -81,8 +85,8 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi }) try { - previewHub.start().then(function () { - console.log('Connected to SignalR preview hub (ID=' + previewHub.connectionId + ')'); + $.connection.start().then(function () { + console.log('Connected to SignalR preview hub (ID=' + $.connection.connectionId + ')'); }).catch(function () { console.log('Could not connect to SignalR preview hub.'); }); From 8653496fd87eb6d75666481638124e696ec4d712 Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 30 Sep 2020 10:02:28 +0200 Subject: [PATCH 33/53] Move MapHub to BackOfficeAreaRoutes and get hub path from ServerVariables --- .../Controllers/BackOfficeServerVariables.cs | 13 ++++++++++--- .../Routing/BackOfficeAreaRoutes.cs | 7 ++++++- .../src/preview/preview.controller.js | 4 ++-- .../umbraco/UmbracoBackOffice/Preview.cshtml | 2 ++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs index 4f397c4a59..db787701a2 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; @@ -16,6 +16,7 @@ using Umbraco.Core.WebAssets; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Profiling; using Umbraco.Web.BackOffice.PropertyEditors; +using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Editors; using Umbraco.Web.Features; @@ -43,6 +44,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IRuntimeMinifier _runtimeMinifier; private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider; private readonly IImageUrlGenerator _imageUrlGenerator; + private readonly BackOfficeAreaRoutes _backOfficeAreaRoutes; public BackOfficeServerVariables( LinkGenerator linkGenerator, @@ -58,7 +60,8 @@ namespace Umbraco.Web.BackOffice.Controllers IOptions securitySettings, IRuntimeMinifier runtimeMinifier, IAuthenticationSchemeProvider authenticationSchemeProvider, - IImageUrlGenerator imageUrlGenerator) + IImageUrlGenerator imageUrlGenerator, + BackOfficeAreaRoutes backOfficeAreaRoutes) { _linkGenerator = linkGenerator; _runtimeState = runtimeState; @@ -74,6 +77,7 @@ namespace Umbraco.Web.BackOffice.Controllers _runtimeMinifier = runtimeMinifier; _authenticationSchemeProvider = authenticationSchemeProvider; _imageUrlGenerator = imageUrlGenerator; + _backOfficeAreaRoutes = backOfficeAreaRoutes; } /// @@ -85,7 +89,7 @@ namespace Umbraco.Web.BackOffice.Controllers //this is the filter for the keys that we'll keep based on the full version of the server vars var keepOnlyKeys = new Dictionary { - {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl"}}, + {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl", "previewHubUrl"}}, {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "canSendRequiredEmail", "usernameIsEmail"}}, {"application", new[] {"applicationPath", "cacheBuster"}}, {"isDebuggingEnabled", new string[] { }}, @@ -357,6 +361,9 @@ namespace Umbraco.Web.BackOffice.Controllers "elementTypeApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl( controller => controller.GetAll()) }, + { + "previewHubUrl", _backOfficeAreaRoutes.GetPreviewHubRoute() + }, } }, { diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index cd8aaabf27..480a7f0fc6 100644 --- a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.BackOffice.Routing MapMinimalBackOffice(endpoints); endpoints.MapUmbracoRoute(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, null); - endpoints.MapHub("/umbraco/previewHub"); + endpoints.MapHub(GetPreviewHubRoute()); AutoRouteBackOfficeControllers(endpoints); break; case RuntimeLevel.BootFailed: @@ -62,6 +62,11 @@ namespace Umbraco.Web.BackOffice.Routing } } + public string GetPreviewHubRoute() + { + return $"/{_umbracoPathSegment}/{nameof(PreviewHub)}"; + } + /// /// Map the minimal routes required to load the back office login and auth /// diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 4104ac8b33..9f5cf84c78 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -61,10 +61,10 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi // signalr hub // If connection already exists and is connected just return // otherwise we'll have multiple connections - if( $.connection && $.connection.connectionState === "Connected") return; + if( $.connection && $.connection.connectionState === signalR.HubConnectionState.Connected) return; $.connection = new signalR.HubConnectionBuilder() - .withUrl("/umbraco/PreviewHub") + .withUrl(Umbraco.Sys.ServerVariables.umbracoUrls.previewHubUrl) .withAutomaticReconnect() .build(); diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml index 212d6bddee..440f9bf28e 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml @@ -83,6 +83,8 @@ + @await Html.BareMinimumServerVariablesScriptAsync(backOfficeServerVariables) + From ab1f41edfb2997718daf4a76bedf7bae867577f9 Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 30 Sep 2020 10:05:37 +0200 Subject: [PATCH 34/53] Configure logging for signalR --- src/Umbraco.Web.UI.Client/src/preview/preview.controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 9f5cf84c78..e5d5b6c636 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -66,6 +66,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi $.connection = new signalR.HubConnectionBuilder() .withUrl(Umbraco.Sys.ServerVariables.umbracoUrls.previewHubUrl) .withAutomaticReconnect() + .configureLogging(signalR.LogLevel.Warning) .build(); $.connection.on("refreshed", function (message) { From a69d705d344a976e713c6a2873b369c2be2445c7 Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 30 Sep 2020 10:21:21 +0200 Subject: [PATCH 35/53] Clean --- .../BackOfficeServiceCollectionExtensions.cs | 1 - .../Routing/BackOfficeAreaRoutes.cs | 4 ++++ .../SignalR/PreviewHubComposer.cs | 2 -- .../src/preview/preview.controller.js | 16 ++++++++-------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs index be18faf4ee..8dc1b8c417 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs @@ -45,7 +45,6 @@ namespace Umbraco.Extensions services.ConfigureOptions(); } - // AddUmbracoPreview -> Use in UmbracoBuilderExtensions public static void AddUmbracoPreview(this IServiceCollection services) { services.AddSignalR(); diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index 480a7f0fc6..c6f453ca18 100644 --- a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -62,6 +62,10 @@ namespace Umbraco.Web.BackOffice.Routing } } + /// + /// Returns the path to the signalR hub used for preview + /// + /// Path to signalR hub public string GetPreviewHubRoute() { return $"/{_umbracoPathSegment}/{nameof(PreviewHub)}"; diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs index 4a6e3d30d4..6660d918c0 100644 --- a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs @@ -10,8 +10,6 @@ namespace Umbraco.Web.SignalR public override void Compose(Composition composition) { base.Compose(composition); - - // composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext()); } } } diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index e5d5b6c636..b312c57503 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -5,7 +5,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.services']) - .controller("previewController", function ($scope, $window, $location, umbRequestHelper) { + .controller("previewController", function ($scope, $window, $location) { $scope.currentCulture = { iso: '', title: '...', icon: 'icon-loading' } var cultures = []; @@ -70,29 +70,29 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi .build(); $.connection.on("refreshed", function (message) { - console.log('Notified by SignalR preview hub (' + message + ').'); + console.log("Notified by SignalR preview hub (" + message + ")."); if ($scope.pageId != message) { - console.log('Not a notification for us (' + $scope.pageId + ').'); + console.log("Not a notification for us (" + $scope.pageId + ")."); return; } if (!visibleContent) { - console.log('Not visible, will reload.'); + console.log("Not visible, will reload."); dirtyContent = true; return; } - console.log('Reloading.'); + console.log("Reloading."); var iframeDoc = iframe.contentWindow || iframe.contentDocument; iframeDoc.location.reload(); }) try { $.connection.start().then(function () { - console.log('Connected to SignalR preview hub (ID=' + $.connection.connectionId + ')'); + console.log("Connected to SignalR preview hub (ID=" + $.connection.connectionId + ")"); }).catch(function () { - console.log('Could not connect to SignalR preview hub.'); + console.log("Could not connect to SignalR preview hub."); }); } catch (e) { - console.error('Could not establish signalr connection. Error: ' + e); + console.error("Could not establish signalr connection. Error: " + e); } } From cbdb96dfe6e2c4e2db0071e15beab83834aaeb1c Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 30 Sep 2020 14:27:18 +0200 Subject: [PATCH 36/53] Add SignalR in integration tests --- .../TestServerTest/UmbracoTestServerTestBase.cs | 1 + src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 5fe06b8a99..c99a457c33 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -68,6 +68,7 @@ namespace Umbraco.Tests.Integration.TestServerTest builder.ConfigureServices((c, s) => { c.HostingEnvironment = TestHelper.GetWebHostEnvironment(); + s.AddSignalR(); }); // call startup diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 552bbf59ae..1dae786d01 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -230,6 +230,8 @@ namespace Umbraco.Tests.Integration.Testing CreateTestRuntime, out _); + services.AddSignalR(); + services.AddUmbracoWebComponents(); services.AddUmbracoRuntimeMinifier(Configuration); services.AddUmbracoBackOffice(); From aa3049fded334b60df69db95eb2daade8ea9fa03 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 30 Sep 2020 14:54:53 +0200 Subject: [PATCH 37/53] Migrated more tests + Aligned IHostingEnvironment.ToAbsolute implementation with expectations from old tests --- .../Views/template1.cshtml | 5 - .../Views/template2.cshtml | 5 - .../Views/test.cshtml | 5 - .../TestHelpers/TestHelper.cs | 11 +- .../Manifest/ManifestContentAppTests.cs | 0 .../Manifest/ManifestParserTests.cs | 29 ++- .../AspNetCoreHostingEnvironmentTests.cs} | 21 +- src/Umbraco.Tests/IO/FileSystemsTests.cs | 7 +- src/Umbraco.Tests/IO/ShadowFileSystemTests.cs | 242 ++++++------------ src/Umbraco.Tests/Umbraco.Tests.csproj | 11 +- .../AspNetCoreHostingEnvironment.cs | 2 +- 11 files changed, 124 insertions(+), 214 deletions(-) delete mode 100644 src/Umbraco.Tests.Integration/Views/template1.cshtml delete mode 100644 src/Umbraco.Tests.Integration/Views/template2.cshtml delete mode 100644 src/Umbraco.Tests.Integration/Views/test.cshtml rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/Manifest/ManifestContentAppTests.cs (100%) rename src/{Umbraco.Tests => Umbraco.Tests.UnitTests/Umbraco.Core}/Manifest/ManifestParserTests.cs (91%) rename src/{Umbraco.Tests/IO/IoHelperTests.cs => Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs} (61%) diff --git a/src/Umbraco.Tests.Integration/Views/template1.cshtml b/src/Umbraco.Tests.Integration/Views/template1.cshtml deleted file mode 100644 index 64a9c8d55f..0000000000 --- a/src/Umbraco.Tests.Integration/Views/template1.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using Umbraco.Web.PublishedModels; -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.Integration/Views/template2.cshtml b/src/Umbraco.Tests.Integration/Views/template2.cshtml deleted file mode 100644 index 64a9c8d55f..0000000000 --- a/src/Umbraco.Tests.Integration/Views/template2.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using Umbraco.Web.PublishedModels; -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.Integration/Views/test.cshtml b/src/Umbraco.Tests.Integration/Views/test.cshtml deleted file mode 100644 index 64a9c8d55f..0000000000 --- a/src/Umbraco.Tests.Integration/Views/test.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using Umbraco.Web.PublishedModels; -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs index a95f13562c..9c619e05de 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Threading; +using Microsoft.AspNetCore.Hosting; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -30,6 +31,8 @@ using Umbraco.Web.Routing; using File = System.IO.File; using Microsoft.Extensions.Options; using Umbraco.Core.Configuration.Models; +using Umbraco.Web.Common.AspNetCore; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Tests.TestHelpers { @@ -58,7 +61,11 @@ namespace Umbraco.Tests.TestHelpers => Mock.Of(); public override IHostingEnvironment GetHostingEnvironment() - => Mock.Of(); + { + return new AspNetCoreHostingEnvironment( + Mock.Of>(x=>x.CurrentValue == new HostingSettings()), + Mock.Of(x=>x.WebRootPath == "/")); + } public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => Mock.Of(); @@ -308,7 +315,7 @@ namespace Umbraco.Tests.TestHelpers public static IIpResolver GetIpResolver() => _testHelperInternal.GetIpResolver(); public static IRequestCache GetRequestCache() => _testHelperInternal.GetRequestCache(); - + public static IPublishedUrlProvider GetPublishedUrlProvider() => _testHelperInternal.GetPublishedUrlProvider(); } } diff --git a/src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs similarity index 100% rename from src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs similarity index 91% rename from src/Umbraco.Tests/Manifest/ManifestParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs index 661c9cff0e..f62bcd0ced 100644 --- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; using Umbraco.Core.Dashboards; +using Umbraco.Core.IO; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -22,6 +23,7 @@ namespace Umbraco.Tests.Manifest public class ManifestParserTests { private ManifestParser _parser; + private IIOHelper _ioHelper; [SetUp] public void Setup() @@ -32,7 +34,8 @@ namespace Umbraco.Tests.Manifest new RegexValidator(Mock.Of(), null), new DelimitedValueValidator(), }; - _parser = new ManifestParser(AppCaches.Disabled, new ManifestValueValidatorCollection(validators), new ManifestFilterCollection(Array.Empty()), Mock.Of(), TestHelper.IOHelper, Mock.Of(), Mock.Of(), new JsonNetSerializer(), Mock.Of(), Mock.Of()); + _ioHelper = TestHelper.IOHelper; + _parser = new ManifestParser(AppCaches.Disabled, new ManifestValueValidatorCollection(validators), new ManifestFilterCollection(Array.Empty()), Mock.Of(), _ioHelper, Mock.Of(), Mock.Of(), new JsonNetSerializer(), Mock.Of(), Mock.Of()); } [Test] @@ -125,8 +128,8 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.Scripts.Length); - Assert.AreEqual("/test.js", manifest.Scripts[0]); - Assert.AreEqual("/test2.js", manifest.Scripts[1]); + Assert.AreEqual(_ioHelper.ResolveUrl("/test.js"), manifest.Scripts[0]); + Assert.AreEqual(_ioHelper.ResolveUrl("/test2.js"), manifest.Scripts[1]); // kludge is gone - must filter before parsing json = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()) + "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js']}"; @@ -218,7 +221,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.IsFalse((editor.Type & EditorType.MacroParameter) > 0); var valueEditor = editor.GetValueEditor(); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html", valueEditor.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html"), valueEditor.View); Assert.AreEqual("int", valueEditor.ValueType); Assert.IsTrue(valueEditor.HideLabel); @@ -250,7 +253,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var f = preValueEditor.Fields[0]; Assert.AreEqual("key1", f.Key); Assert.AreEqual("Some config 1", f.Name); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html", f.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html"), f.View); var fvalidators = f.Validators; Assert.IsNotNull(fvalidators); Assert.AreEqual(1, fvalidators.Count); @@ -261,7 +264,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 f = preValueEditor.Fields[1]; Assert.AreEqual("key2", f.Key); Assert.AreEqual("Some config 2", f.Name); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val2.html", f.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val2.html"), f.View); fvalidators = f.Validators; Assert.IsNotNull(fvalidators); Assert.AreEqual(0, fvalidators.Count); @@ -303,7 +306,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("some config val", config["key1"]); var valueEditor = editor.GetValueEditor(); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html", valueEditor.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html"), valueEditor.View); editor = manifest.ParameterEditors[2]; Assert.Throws(() => @@ -353,8 +356,8 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var editor = manifest.GridEditors[0]; Assert.AreEqual("small-hero", editor.Alias); Assert.AreEqual("Small Hero", editor.Name); - Assert.AreEqual("/App_Plugins/MyPlugin/small-hero/editortemplate.html", editor.View); - Assert.AreEqual("/Views/Partials/Grid/Editors/SmallHero.cshtml", editor.Render); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPlugin/small-hero/editortemplate.html"), editor.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/Views/Partials/Grid/Editors/SmallHero.cshtml"), editor.Render); Assert.AreEqual("icon-presentation", editor.Icon); var config = editor.Config; @@ -396,14 +399,14 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("myPackageApp1", app0.Alias); Assert.AreEqual("My App1", app0.Name); Assert.AreEqual("icon-foo", app0.Icon); - Assert.AreEqual("/App_Plugins/MyPackage/ContentApps/MyApp1.html", app0.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/ContentApps/MyApp1.html"), app0.View); Assert.IsInstanceOf(manifest.ContentApps[1]); var app1 = (ManifestContentAppDefinition)manifest.ContentApps[1]; Assert.AreEqual("myPackageApp2", app1.Alias); Assert.AreEqual("My App2", app1.Name); Assert.AreEqual("icon-bar", app1.Icon); - Assert.AreEqual("/App_Plugins/MyPackage/ContentApps/MyApp2.html", app1.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/ContentApps/MyApp2.html"), app1.View); } [Test] @@ -432,7 +435,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var db0 = manifest.Dashboards[0]; Assert.AreEqual("something", db0.Alias); Assert.AreEqual(100, db0.Weight); - Assert.AreEqual("/App_Plugins/MyPackage/Dashboards/one.html", db0.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/Dashboards/one.html"), db0.View); Assert.AreEqual(1, db0.Sections.Length); Assert.AreEqual("content", db0.Sections[0]); Assert.AreEqual(2, db0.AccessRules.Length); @@ -445,7 +448,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var db1 = manifest.Dashboards[1]; Assert.AreEqual("something.else", db1.Alias); Assert.AreEqual(-1, db1.Weight); - Assert.AreEqual("/App_Plugins/MyPackage/Dashboards/two.html", db1.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/Dashboards/two.html"), db1.View); Assert.AreEqual(1, db1.Sections.Length); Assert.AreEqual("forms", db1.Sections[0]); } diff --git a/src/Umbraco.Tests/IO/IoHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs similarity index 61% rename from src/Umbraco.Tests/IO/IoHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs index 6e876c4705..1d6e619640 100644 --- a/src/Umbraco.Tests/IO/IoHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs @@ -1,29 +1,34 @@ using System; +using AutoFixture.NUnit3; +using Moq; using NUnit.Framework; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.UnitTests.AutoFixture; +using Umbraco.Web.Common.AspNetCore; namespace Umbraco.Tests.IO { [TestFixture] - public class IoHelperTests + public class AspNetCoreHostingEnvironmentTests { - private IIOHelper _ioHelper => TestHelper.IOHelper; - [TestCase("~/Scripts", "/Scripts", null)] - [TestCase("/Scripts", "/Scripts", null)] - [TestCase("../Scripts", "/Scripts", typeof(ArgumentException))] - public void IOHelper_ResolveUrl(string input, string expected, Type expectedExceptionType) + [InlineAutoMoqData("~/Scripts", "/Scripts", null)] + [InlineAutoMoqData("/Scripts", "/Scripts", null)] + [InlineAutoMoqData("../Scripts", "/Scripts", typeof(InvalidOperationException))] + public void IOHelper_ResolveUrl(string input, string expected, Type expectedExceptionType, AspNetCoreHostingEnvironment sut) { if (expectedExceptionType != null) { - Assert.Throws(expectedExceptionType, () =>_ioHelper.ResolveUrl(input)); + Assert.Throws(expectedExceptionType, () =>sut.ToAbsolute(input)); } else { - var result = _ioHelper.ResolveUrl(input); + + var result = sut.ToAbsolute(input); Assert.AreEqual(expected, result); } } diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index 67e92bd123..6f7af8e605 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -13,7 +13,6 @@ using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.IO @@ -46,9 +45,6 @@ namespace Umbraco.Tests.IO _factory = composition.CreateFactory(); - Current.Reset(); - Current.Factory = _factory; - // make sure we start clean // because some tests will create corrupt or weird filesystems FileSystems.Reset(); @@ -60,7 +56,6 @@ namespace Umbraco.Tests.IO // stay clean (see note in Setup) FileSystems.Reset(); - Current.Reset(); _register.DisposeIfDisposable(); } @@ -115,7 +110,7 @@ namespace Umbraco.Tests.IO fs.DeleteMediaFiles(new[] { virtPath }); Assert.IsFalse(File.Exists(physPath)); - var scheme = Current.Factory.GetInstance(); + var scheme = _factory.GetInstance(); if (scheme is UniqueMediaPathScheme) { // ~/media/1234 is *not* gone diff --git a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs index 472714ba0e..dfd061b3ac 100644 --- a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -11,9 +10,8 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; -using Umbraco.Core.Scoping; -using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Tests.IO { @@ -25,11 +23,15 @@ namespace Umbraco.Tests.IO // SetUp and TearDown run before/after each test // SetUp does not start before the previous TearDown returns + private readonly ILogger _logger = Mock.Of(); + private readonly IHostingEnvironment _hostingEnvironment = TestHelper.GetHostingEnvironment(); + private readonly IIOHelper _ioHelper = TestHelper.IOHelper; + [SetUp] public void SetUp() { SafeCallContext.Clear(); - ClearFiles(TestHelper.IOHelper); + ClearFiles(_ioHelper); FileSystems.ResetShadowId(); } @@ -41,10 +43,10 @@ namespace Umbraco.Tests.IO FileSystems.ResetShadowId(); } - private static void ClearFiles(IIOHelper ioHelper) + private static void ClearFiles(IIOHelper _ioHelper) { - TestHelper.DeleteDirectory(ioHelper.MapPath("FileSysTests")); - TestHelper.DeleteDirectory(ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); + TestHelper.DeleteDirectory(_ioHelper.MapPath("FileSysTests")); + TestHelper.DeleteDirectory(_ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); } private static string NormPath(string path) @@ -55,17 +57,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteDirectory() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/d1"); @@ -93,17 +91,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteDirectoryInDir() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub"); @@ -146,17 +140,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteFile() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); File.WriteAllText(path + "/ShadowTests/f1.txt", "foo"); @@ -189,18 +179,14 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteFileInDir() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub"); @@ -249,17 +235,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowCantCreateFile() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Assert.Throws(() => @@ -272,17 +254,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowCreateFile() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper,hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper,_hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); @@ -315,17 +293,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowCreateFileInDir() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) @@ -359,17 +333,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowAbort() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) @@ -385,17 +355,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowComplete() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub/sub"); @@ -425,22 +391,18 @@ namespace Umbraco.Tests.IO [Test] public void ShadowScopeComplete() { - var logger = Mock.Of(); - var ioHelper = TestHelper.IOHelper; - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); - var shadowfs = ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); + var path = _ioHelper.MapPath("FileSysTests"); + var shadowfs = _ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); Directory.CreateDirectory(shadowfs); var scopedFileSystems = false; - var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); + var phy = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path, "ignore"); var container = Mock.Of(); var globalSettings = Options.Create(new GlobalSettings()); - var fileSystems = new FileSystems(container, logger, ioHelper, globalSettings, TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; + var fileSystems = new FileSystems(container, _logger, _ioHelper, globalSettings, _hostingEnvironment) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem(phy); var sw = (ShadowWrapper) fs.InnerFileSystem; @@ -451,7 +413,7 @@ namespace Umbraco.Tests.IO string id; // explicit shadow without scope does not work - sw.Shadow(id = ShadowWrapper.CreateShadowId(ioHelper)); + sw.Shadow(id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); @@ -462,7 +424,7 @@ namespace Umbraco.Tests.IO // shadow with scope but no complete does not complete scopedFileSystems = true; // pretend we have a scope - var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f3.txt", ms); @@ -484,7 +446,7 @@ namespace Umbraco.Tests.IO // shadow with scope and complete does complete scopedFileSystems = true; // pretend we have a scope - scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f4.txt", ms); @@ -500,7 +462,7 @@ namespace Umbraco.Tests.IO // test scope for "another thread" scopedFileSystems = true; // pretend we have a scope - scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f5.txt", ms); @@ -523,21 +485,17 @@ namespace Umbraco.Tests.IO [Test] public void ShadowScopeCompleteWithFileConflict() { - var logger = Mock.Of(); - var ioHelper = TestHelper.IOHelper; - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); - var shadowfs = ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); + var path = _ioHelper.MapPath("FileSysTests"); + var shadowfs = _ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; - var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); + var phy = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path, "ignore"); var container = Mock.Of(); var globalSettings = Options.Create(new GlobalSettings()); - var fileSystems = new FileSystems(container, logger, ioHelper, globalSettings, TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; + var fileSystems = new FileSystems(container, _logger, _ioHelper, globalSettings, _hostingEnvironment) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem( phy); var sw = (ShadowWrapper) fs.InnerFileSystem; @@ -548,7 +506,7 @@ namespace Umbraco.Tests.IO string id; scopedFileSystems = true; // pretend we have a scope - var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); @@ -579,21 +537,17 @@ namespace Umbraco.Tests.IO [Test] public void ShadowScopeCompleteWithDirectoryConflict() { - var logger = Mock.Of(); - var ioHelper = TestHelper.IOHelper; - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); - var shadowfs = ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); + var path = _ioHelper.MapPath("FileSysTests"); + var shadowfs = _ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; - var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); + var phy = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path, "ignore"); var container = Mock.Of(); var globalSettings = Options.Create(new GlobalSettings()); - var fileSystems = new FileSystems(container, logger, ioHelper, globalSettings, TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; + var fileSystems = new FileSystems(container, _logger, _ioHelper, globalSettings, _hostingEnvironment) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem( phy); var sw = (ShadowWrapper)fs.InnerFileSystem; @@ -604,7 +558,7 @@ namespace Umbraco.Tests.IO string id; scopedFileSystems = true; // pretend we have a scope - var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); @@ -652,9 +606,7 @@ namespace Umbraco.Tests.IO [Test] public void GetFilesReturnsChildrenOnly() { - var ioHelper = TestHelper.IOHelper; - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); File.WriteAllText(path + "/f1.txt", "foo"); Directory.CreateDirectory(path + "/test"); @@ -676,9 +628,7 @@ namespace Umbraco.Tests.IO [Test] public void DeleteDirectoryAndFiles() { - var ioHelper = TestHelper.IOHelper; - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); File.WriteAllText(path + "/f1.txt", "foo"); Directory.CreateDirectory(path + "/test"); @@ -699,17 +649,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFiles() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -735,17 +681,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingEmptyFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -774,17 +716,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingNullFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -810,17 +748,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingWildcardFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -849,17 +783,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingSingleCharacterFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -900,17 +830,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFullPath() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -938,17 +864,13 @@ namespace Umbraco.Tests.IO public void ShadowGetRelativePath() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -981,17 +903,13 @@ namespace Umbraco.Tests.IO public void ShadowGetUrl() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "rootUrl"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "rootUrl"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "rootUrl"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "rootUrl"); var ss = new ShadowFileSystem(fs, sfs); // Act diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 70720a588a..fe5e334a93 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -118,10 +118,13 @@ + + + + - @@ -164,7 +167,6 @@ - @@ -277,7 +279,6 @@ - @@ -303,7 +304,6 @@ - @@ -372,9 +372,6 @@ - - - diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs index ede121a9f7..ad168114e0 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -100,7 +100,7 @@ namespace Umbraco.Web.Common.AspNetCore if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute)) return virtualPath; - var fullPath = ApplicationVirtualPath.EnsureEndsWith('/') + virtualPath.TrimStart("~/"); + var fullPath = ApplicationVirtualPath.EnsureEndsWith('/') + virtualPath.TrimStart("~/").TrimStart("/"); return fullPath; } From e02260c10b5b1770bac34612fbefc2a3163956ac Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 30 Sep 2020 21:23:56 +0200 Subject: [PATCH 38/53] Fixing tests Signed-off-by: Bjarke Berg --- .../AutoFixture/AutoMoqDataAttribute.cs | 10 ++++++++++ .../Routing/BackOfficeAreaRoutesTests.cs | 5 ++++- .../Umbraco.Web.Common/Routing/TestRouteBuilder.cs | 13 ++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs index 9c753b2b76..349d3e7b15 100644 --- a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs +++ b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs @@ -12,9 +12,12 @@ using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; using Umbraco.Tests.Common.Builders; using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.Common.Install; +using Umbraco.Web.WebApi; namespace Umbraco.Tests.UnitTests.AutoFixture { @@ -74,6 +77,13 @@ namespace Umbraco.Tests.UnitTests.AutoFixture u => u.FromFactory( () => new UmbracoVersion())); + fixture.Customize(u => u.FromFactory( + () => new BackOfficeAreaRoutes( + Options.Create(new GlobalSettings()), + Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), + Mock.Of(x => x.Level == RuntimeLevel.Run), + new UmbracoApiControllerTypeCollection(Array.Empty())))); + var connectionStrings = new ConnectionStrings(); fixture.Customize(x => x.FromFactory(() => connectionStrings )); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs index 54147e67b9..09e86da319 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs @@ -54,9 +54,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); - Assert.AreEqual(1, endpoints.DataSources.Count); + Assert.AreEqual(2, endpoints.DataSources.Count); // first = ControllerActionEndpointDataSource, Second = ModelEndpointDataSource (SignalR hubs) var route = endpoints.DataSources.First(); Assert.AreEqual(4, route.Endpoints.Count); + var hubs = endpoints.DataSources.Last(); + Assert.AreEqual(2, hubs.Endpoints.Count); + AssertMinimalBackOfficeRoutes(route); var endpoint3 = (RouteEndpoint)route.Endpoints[2]; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs index 6d28e8a71e..de21bc5129 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs @@ -4,6 +4,12 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using System; using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting.Internal; +using Microsoft.Extensions.Logging; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing { @@ -16,6 +22,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing var services = new ServiceCollection(); services.AddLogging(); services.AddMvc(); + services.AddSingleton(x => new ApplicationLifetime(x.GetRequiredService>())); + services.AddSignalR(); _serviceProvider = services.BuildServiceProvider(); } @@ -25,7 +33,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing public IApplicationBuilder CreateApplicationBuilder() { - return Mock.Of(); + var mock = new Mock(); + mock.Setup(x => x.Build()).Returns(httpContext => Task.CompletedTask); + return mock.Object; } + } } From 26ad4a332f1f18aa7a0c7f59c0935900071e8053 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 1 Oct 2020 07:03:31 +0200 Subject: [PATCH 39/53] Clean up - Introduced PreviewRoutes Signed-off-by: Bjarke Berg --- .../AutoFixture/AutoMoqDataAttribute.cs | 6 ++ .../Routing/BackOfficeAreaRoutesTests.cs | 4 +- .../Routing/PreviewRoutesTests.cs | 70 +++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 - .../Controllers/BackOfficeServerVariables.cs | 8 +-- .../BackOfficeApplicationBuilderExtensions.cs | 11 +++ .../Routing/BackOfficeAreaRoutes.cs | 14 +--- .../Routing/PreviewRoutes.cs | 57 +++++++++++++++ .../Runtime/BackOfficeComposer.cs | 3 +- 9 files changed, 151 insertions(+), 23 deletions(-) create mode 100644 src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs create mode 100644 src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs diff --git a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs index 349d3e7b15..29e35139b9 100644 --- a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs +++ b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs @@ -84,6 +84,12 @@ namespace Umbraco.Tests.UnitTests.AutoFixture Mock.Of(x => x.Level == RuntimeLevel.Run), new UmbracoApiControllerTypeCollection(Array.Empty())))); + fixture.Customize(u => u.FromFactory( + () => new PreviewRoutes( + Options.Create(new GlobalSettings()), + Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), + Mock.Of(x => x.Level == RuntimeLevel.Run)))); + var connectionStrings = new ConnectionStrings(); fixture.Customize(x => x.FromFactory(() => connectionStrings )); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs index 09e86da319..a3a9e79e20 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs @@ -54,11 +54,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); - Assert.AreEqual(2, endpoints.DataSources.Count); // first = ControllerActionEndpointDataSource, Second = ModelEndpointDataSource (SignalR hubs) + Assert.AreEqual(1, endpoints.DataSources.Count); var route = endpoints.DataSources.First(); Assert.AreEqual(4, route.Endpoints.Count); - var hubs = endpoints.DataSources.Last(); - Assert.AreEqual(2, hubs.Endpoints.Count); AssertMinimalBackOfficeRoutes(route); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs new file mode 100644 index 0000000000..1d85ca554f --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs @@ -0,0 +1,70 @@ +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Routing; +using Umbraco.Web.BackOffice.SignalR; +using Umbraco.Web.Common.Attributes; +using Umbraco.Web.Common.Controllers; +using Umbraco.Web.WebApi; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing +{ + + [TestFixture] + public class PreviewRoutesTests + { + [TestCase(RuntimeLevel.Install)] + [TestCase(RuntimeLevel.BootFailed)] + [TestCase(RuntimeLevel.Unknown)] + [TestCase(RuntimeLevel.Boot)] + [TestCase(RuntimeLevel.Upgrade)] + public void RuntimeState_No_Routes(RuntimeLevel level) + { + var routes = GetRoutes(level); + var endpoints = new TestRouteBuilder(); + routes.CreateRoutes(endpoints); + + Assert.AreEqual(0, endpoints.DataSources.Count); + } + + + [Test] + public void RuntimeState_Run() + { + var routes = GetRoutes(RuntimeLevel.Run); + var endpoints = new TestRouteBuilder(); + routes.CreateRoutes(endpoints); + + Assert.AreEqual(1, endpoints.DataSources.Count); + var route = endpoints.DataSources.First(); + Assert.AreEqual(2, route.Endpoints.Count); + + var endpoint0 = (RouteEndpoint) route.Endpoints[0]; + Assert.AreEqual($"{routes.GetPreviewHubRoute()}/negotiate", endpoint0.RoutePattern.RawText); + var endpoint1 = (RouteEndpoint) route.Endpoints[1]; + Assert.AreEqual($"{routes.GetPreviewHubRoute()}", endpoint1.RoutePattern.RawText); + + + } + private PreviewRoutes GetRoutes(RuntimeLevel level) + { + var globalSettings = new GlobalSettings(); + var routes = new PreviewRoutes( + Options.Create(globalSettings), + Mock.Of(x => + x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), + Mock.Of(x => x.Level == level)); + + return routes; + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 70720a588a..e2670c85a7 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -112,7 +112,6 @@ - diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs index db787701a2..9f109d7bbf 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs @@ -44,7 +44,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IRuntimeMinifier _runtimeMinifier; private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider; private readonly IImageUrlGenerator _imageUrlGenerator; - private readonly BackOfficeAreaRoutes _backOfficeAreaRoutes; + private readonly PreviewRoutes _previewRoutes; public BackOfficeServerVariables( LinkGenerator linkGenerator, @@ -61,7 +61,7 @@ namespace Umbraco.Web.BackOffice.Controllers IRuntimeMinifier runtimeMinifier, IAuthenticationSchemeProvider authenticationSchemeProvider, IImageUrlGenerator imageUrlGenerator, - BackOfficeAreaRoutes backOfficeAreaRoutes) + PreviewRoutes previewRoutes) { _linkGenerator = linkGenerator; _runtimeState = runtimeState; @@ -77,7 +77,7 @@ namespace Umbraco.Web.BackOffice.Controllers _runtimeMinifier = runtimeMinifier; _authenticationSchemeProvider = authenticationSchemeProvider; _imageUrlGenerator = imageUrlGenerator; - _backOfficeAreaRoutes = backOfficeAreaRoutes; + _previewRoutes = previewRoutes; } /// @@ -362,7 +362,7 @@ namespace Umbraco.Web.BackOffice.Controllers controller => controller.GetAll()) }, { - "previewHubUrl", _backOfficeAreaRoutes.GetPreviewHubRoute() + "previewHubUrl", _previewRoutes.GetPreviewHubRoute() }, } }, diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs index 3cba66812e..471aed51e1 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs @@ -20,6 +20,7 @@ namespace Umbraco.Extensions app.UseRequestLocalization(); app.UseUmbracoRequestLogging(); app.UseUmbracoBackOffice(); + app.UseUmbracoPreview(); app.UseUmbracoInstaller(); return app; @@ -49,5 +50,15 @@ namespace Umbraco.Extensions return app; } + public static IApplicationBuilder UseUmbracoPreview(this IApplicationBuilder app) + { + app.UseEndpoints(endpoints => + { + var previewRoutes = app.ApplicationServices.GetRequiredService(); + previewRoutes.CreateRoutes(endpoints); + }); + + return app; + } } } diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index c6f453ca18..7922b6a46d 100644 --- a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -1,12 +1,10 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Web.BackOffice.Controllers; -using Umbraco.Web.BackOffice.SignalR; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Routing; using Umbraco.Web.WebApi; @@ -52,7 +50,6 @@ namespace Umbraco.Web.BackOffice.Routing MapMinimalBackOffice(endpoints); endpoints.MapUmbracoRoute(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, null); - endpoints.MapHub(GetPreviewHubRoute()); AutoRouteBackOfficeControllers(endpoints); break; case RuntimeLevel.BootFailed: @@ -62,15 +59,6 @@ namespace Umbraco.Web.BackOffice.Routing } } - /// - /// Returns the path to the signalR hub used for preview - /// - /// Path to signalR hub - public string GetPreviewHubRoute() - { - return $"/{_umbracoPathSegment}/{nameof(PreviewHub)}"; - } - /// /// Map the minimal routes required to load the back office login and auth /// diff --git a/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs new file mode 100644 index 0000000000..210b0ffddb --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Web.BackOffice.SignalR; +using Umbraco.Web.Common.Routing; + +namespace Umbraco.Web.BackOffice.Routing +{ + /// + /// Creates routes for the preview hub + /// + public class PreviewRoutes : IAreaRoutes + { + private readonly IRuntimeState _runtimeState; + private readonly string _umbracoPathSegment; + + public PreviewRoutes( + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IRuntimeState runtimeState) + { + _runtimeState = runtimeState; + _umbracoPathSegment = globalSettings.Value.GetUmbracoMvcArea(hostingEnvironment); + } + + public void CreateRoutes(IEndpointRouteBuilder endpoints) + { + switch (_runtimeState.Level) + { + case RuntimeLevel.Install: + break; + case RuntimeLevel.Upgrade: + break; + case RuntimeLevel.Run: + endpoints.MapHub(GetPreviewHubRoute()); + break; + case RuntimeLevel.BootFailed: + case RuntimeLevel.Unknown: + case RuntimeLevel.Boot: + break; + } + } + + /// + /// Returns the path to the signalR hub used for preview + /// + /// Path to signalR hub + public string GetPreviewHubRoute() + { + return $"/{_umbracoPathSegment}/{nameof(PreviewHub)}"; + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs index aed4cbdbb5..177465bcde 100644 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs @@ -22,9 +22,8 @@ namespace Umbraco.Web.BackOffice.Runtime { public void Compose(Composition composition) { - - composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(); composition.Register(Lifetime.Request); composition.Register(Lifetime.Request); From 3607dd14f1eaf97fad46eae9414be7defab526a9 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 1 Oct 2020 07:09:54 +0200 Subject: [PATCH 40/53] Clean up + Removed old SignalR code Signed-off-by: Bjarke Berg --- .../UmbracoTestServerTestBase.cs | 2 +- .../Views/template1.cshtml | 5 -- .../Views/template2.cshtml | 5 -- .../Views/test.cshtml | 5 -- src/Umbraco.Web/SignalR/IPreviewHub.cs | 12 ----- src/Umbraco.Web/SignalR/PreviewHub.cs | 7 --- .../SignalR/PreviewHubComponent.cs | 47 ------------------- src/Umbraco.Web/SignalR/PreviewHubComposer.cs | 17 ------- src/Umbraco.Web/Umbraco.Web.csproj | 4 -- 9 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 src/Umbraco.Tests.Integration/Views/template1.cshtml delete mode 100644 src/Umbraco.Tests.Integration/Views/template2.cshtml delete mode 100644 src/Umbraco.Tests.Integration/Views/test.cshtml delete mode 100644 src/Umbraco.Web/SignalR/IPreviewHub.cs delete mode 100644 src/Umbraco.Web/SignalR/PreviewHub.cs delete mode 100644 src/Umbraco.Web/SignalR/PreviewHubComponent.cs delete mode 100644 src/Umbraco.Web/SignalR/PreviewHubComposer.cs diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index c99a457c33..9f10ce968e 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -68,7 +68,6 @@ namespace Umbraco.Tests.Integration.TestServerTest builder.ConfigureServices((c, s) => { c.HostingEnvironment = TestHelper.GetWebHostEnvironment(); - s.AddSignalR(); }); // call startup @@ -142,6 +141,7 @@ namespace Umbraco.Tests.Integration.TestServerTest .WithRuntimeMinifier() .WithBackOffice() .WithBackOfficeIdentity() + .WithPreview() //.WithMiniProfiler() // we don't want this running in tests .WithMvcAndRazor(mvcBuilding: mvcBuilder => { diff --git a/src/Umbraco.Tests.Integration/Views/template1.cshtml b/src/Umbraco.Tests.Integration/Views/template1.cshtml deleted file mode 100644 index 64a9c8d55f..0000000000 --- a/src/Umbraco.Tests.Integration/Views/template1.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using Umbraco.Web.PublishedModels; -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.Integration/Views/template2.cshtml b/src/Umbraco.Tests.Integration/Views/template2.cshtml deleted file mode 100644 index 64a9c8d55f..0000000000 --- a/src/Umbraco.Tests.Integration/Views/template2.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using Umbraco.Web.PublishedModels; -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.Integration/Views/test.cshtml b/src/Umbraco.Tests.Integration/Views/test.cshtml deleted file mode 100644 index 64a9c8d55f..0000000000 --- a/src/Umbraco.Tests.Integration/Views/test.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using Umbraco.Web.PublishedModels; -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Web/SignalR/IPreviewHub.cs b/src/Umbraco.Web/SignalR/IPreviewHub.cs deleted file mode 100644 index 2eb722c40d..0000000000 --- a/src/Umbraco.Web/SignalR/IPreviewHub.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Umbraco.Web.SignalR -{ - public interface IPreviewHub - { - // define methods implemented by client - // ReSharper disable InconsistentNaming - - void refreshed(int id); - - // ReSharper restore InconsistentNaming - } -} diff --git a/src/Umbraco.Web/SignalR/PreviewHub.cs b/src/Umbraco.Web/SignalR/PreviewHub.cs deleted file mode 100644 index 3fc3225fb8..0000000000 --- a/src/Umbraco.Web/SignalR/PreviewHub.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Microsoft.AspNet.SignalR; - -namespace Umbraco.Web.SignalR -{ - public class PreviewHub : Hub - { } -} diff --git a/src/Umbraco.Web/SignalR/PreviewHubComponent.cs b/src/Umbraco.Web/SignalR/PreviewHubComponent.cs deleted file mode 100644 index 1d8a10118b..0000000000 --- a/src/Umbraco.Web/SignalR/PreviewHubComponent.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Microsoft.AspNet.SignalR; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Sync; -using Umbraco.Web.Cache; - -namespace Umbraco.Web.SignalR -{ - public class PreviewHubComponent : IComponent - { - private readonly Lazy> _hubContext; - - // using a lazy arg here means that we won't create the hub until necessary - // and therefore we won't have too bad an impact on boot time - public PreviewHubComponent(Lazy> hubContext) - { - _hubContext = hubContext; - } - - public void Initialize() - { - // ContentService.Saved is too soon - the content cache is not ready yet, - // so use the content cache refresher event, because when it triggers - // the cache has already been notified of the changes - - ContentCacheRefresher.CacheUpdated += HandleCacheUpdated; - } - - public void Terminate() - { - ContentCacheRefresher.CacheUpdated -= HandleCacheUpdated; - } - - private void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) - { - if (args.MessageType != MessageType.RefreshByPayload) return; - var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject; - var hubContextInstance = _hubContext.Value; - foreach (var payload in payloads) - { - var id = payload.Id; // keep it simple for now, ignore ChangeTypes - hubContextInstance.Clients.All.refreshed(id); - } - } - } -} diff --git a/src/Umbraco.Web/SignalR/PreviewHubComposer.cs b/src/Umbraco.Web/SignalR/PreviewHubComposer.cs deleted file mode 100644 index cef1e166c2..0000000000 --- a/src/Umbraco.Web/SignalR/PreviewHubComposer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.AspNet.SignalR; -using Umbraco.Core; -using Umbraco.Core.Composing; - -namespace Umbraco.Web.SignalR -{ - [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - public class PreviewHubComposer : ComponentComposer, ICoreComposer - { - public override void Compose(Composition composition) - { - base.Compose(composition); - - composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext()); - } - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 7a0f584baa..af9f9f76f6 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -214,7 +214,6 @@ - @@ -233,9 +232,6 @@ - - - From 4181e2639c877af0dde1cbffe5b152370f27b2fe Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 1 Oct 2020 07:13:16 +0200 Subject: [PATCH 41/53] Clean up - Only add signalr once as dependency Signed-off-by: Bjarke Berg --- src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js index 8d0547522d..bf5fe6b4fb 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js @@ -213,7 +213,6 @@ function dependencies() { { "name": "signalr", "src": [ - "./node_modules/@microsoft/signalr/dist/browser/signalr.js", "./node_modules/@microsoft/signalr/dist/browser/signalr.min.js", ], "base": "./node_modules/@microsoft/signalr/dist/browser" From 3b1f7ad042d1806ce06f01fd1a768a0a1967e132 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 1 Oct 2020 07:41:23 +0200 Subject: [PATCH 42/53] Clean up Signed-off-by: Bjarke Berg --- src/Umbraco.Web/Runtime/WebInitialComposer.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index f6629ad5fd..90706f346f 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -13,8 +13,6 @@ using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; -using Umbraco.Web.SignalR; -using Umbraco.Web.Services; namespace Umbraco.Web.Runtime { @@ -73,9 +71,6 @@ namespace Umbraco.Web.Runtime // auto-register views composition.RegisterAuto(typeof(UmbracoViewPage<>)); - - // register preview SignalR hub - composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext()); } } } From dd2dad15d91196733cca26d05e05b850bbda5032 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 1 Oct 2020 08:19:49 +0200 Subject: [PATCH 43/53] Updated System.Threading.Tasks.Extensions Signed-off-by: Bjarke Berg --- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e2670c85a7..ea022b1321 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -111,6 +111,7 @@ + From f0dbeab654828fb97e574e72611ebcde05025f6d Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 1 Oct 2020 09:04:47 +0200 Subject: [PATCH 44/53] revert update of System.Threading.Tasks.Extensions Signed-off-by: Bjarke Berg --- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index ea022b1321..e0858d485b 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -111,7 +111,7 @@ - + From 88b707db36c0ee580161f31657f8b69004d21c83 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Thu, 1 Oct 2020 11:36:00 +0200 Subject: [PATCH 45/53] Adds missing value that is passed on --- .../umbraco/UmbracoBackOffice/Default.cshtml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml index 65baa96890..094d1e4b69 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml @@ -96,6 +96,7 @@ model="overlay" position="{{overlay.position}}" view="overlay.view" + name="overlay.name" parent-scope="overlay.parentScope"> From 8dfa73be4c1fb9a77542900b871b3d6f39d060e7 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Thu, 1 Oct 2020 14:23:17 +0200 Subject: [PATCH 46/53] Migrating TagServiceTests --- .../Services/TagServiceTests.cs | 39 ++++++++++--------- .../Umbraco.Tests.Integration.csproj | 1 - src/Umbraco.Tests/Umbraco.Tests.csproj | 1 - 3 files changed, 20 insertions(+), 21 deletions(-) rename src/{Umbraco.Tests => Umbraco.Tests.Integration}/Services/TagServiceTests.cs (76%) diff --git a/src/Umbraco.Tests/Services/TagServiceTests.cs b/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs similarity index 76% rename from src/Umbraco.Tests/Services/TagServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/TagServiceTests.cs index f4916168d4..09cbafd550 100644 --- a/src/Umbraco.Tests/Services/TagServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs @@ -2,16 +2,15 @@ using System.Threading; using Newtonsoft.Json; using NUnit.Framework; -using NUnit.Framework.Internal; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering methods in the TagService class. @@ -21,16 +20,17 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class TagServiceTests : TestWithSomeContentBase + public class TagServiceTests : UmbracoIntegrationTest { - public PropertyEditorCollection PropertyEditorCollection => Factory.GetInstance(); + public PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); [Test] public void TagApiConsistencyTest() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; + var contentService = GetRequiredService(); + var contentTypeService = GetRequiredService(); + var tagService = GetRequiredService(); + var dataTypeService = GetRequiredService(); var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); contentType.PropertyGroups.First().PropertyTypes.Add( new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") @@ -40,18 +40,18 @@ namespace Umbraco.Tests.Services contentTypeService.Save(contentType); IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); + content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow", "pig", "goat" }); contentService.SaveAndPublish(content1); // change - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "elephant" }, true); - content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); + content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "elephant" }, true); + content1.RemoveTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow" }); contentService.SaveAndPublish(content1); // more changes - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }, true); + content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "mouse" }, true); contentService.SaveAndPublish(content1); - content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }); + content1.RemoveTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "mouse" }); contentService.SaveAndPublish(content1); // get it back @@ -76,9 +76,10 @@ namespace Umbraco.Tests.Services [Test] public void TagList_Contains_NodeCount() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; + var contentService = GetRequiredService(); + var contentTypeService = GetRequiredService(); + var tagService = GetRequiredService(); + var dataTypeService = GetRequiredService(); var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); contentType.PropertyGroups.First().PropertyTypes.Add( new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext, "tags") @@ -88,15 +89,15 @@ namespace Umbraco.Tests.Services contentTypeService.Save(contentType); var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); + content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow", "pig", "goat" }); contentService.SaveAndPublish(content1); var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig" }); + content2.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow", "pig" }); contentService.SaveAndPublish(content2); var content3 = MockedContent.CreateSimpleContent(contentType, "Tagged content 3", -1); - content3.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); + content3.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow" }); contentService.SaveAndPublish(content3); // Act diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index b72f1d2612..8ddeb42b81 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -24,7 +24,6 @@ - all diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2395542d62..70c0e917cb 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -268,7 +268,6 @@ - From e8e965c46ae2fc8e1949a7e7345163e9ea1a3f36 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Thu, 1 Oct 2020 14:47:34 +0200 Subject: [PATCH 47/53] Makes required services private and available to all test methods --- .../Services/TagServiceTests.cs | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs b/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs index 09cbafd550..db2c8196e7 100644 --- a/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs @@ -22,40 +22,40 @@ namespace Umbraco.Tests.Integration.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class TagServiceTests : UmbracoIntegrationTest { + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private ITagService TagService => GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); public PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); [Test] public void TagApiConsistencyTest() { - var contentService = GetRequiredService(); - var contentTypeService = GetRequiredService(); - var tagService = GetRequiredService(); - var dataTypeService = GetRequiredService(); var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); contentType.PropertyGroups.First().PropertyTypes.Add( new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") { DataTypeId = 1041 }); - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow", "pig", "goat" }); - contentService.SaveAndPublish(content1); + content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); + ContentService.SaveAndPublish(content1); // change - content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "elephant" }, true); - content1.RemoveTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow" }); - contentService.SaveAndPublish(content1); + content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "elephant" }, true); + content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); + ContentService.SaveAndPublish(content1); // more changes - content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "mouse" }, true); - contentService.SaveAndPublish(content1); - content1.RemoveTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "mouse" }); - contentService.SaveAndPublish(content1); + content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }, true); + ContentService.SaveAndPublish(content1); + content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }); + ContentService.SaveAndPublish(content1); // get it back - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); var tagsValue = content1.GetValue("tags").ToString(); var tagsValues = JsonConvert.DeserializeObject(tagsValue); Assert.AreEqual(3, tagsValues.Length); @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Integration.Services Assert.Contains("goat", tagsValues); Assert.Contains("elephant", tagsValues); - var tags = tagService.GetTagsForProperty(content1.Id, "tags").ToArray(); + var tags = TagService.GetTagsForProperty(content1.Id, "tags").ToArray(); Assert.IsTrue(tags.All(x => x.Group == "default")); tagsValues = tags.Select(x => x.Text).ToArray(); @@ -76,32 +76,28 @@ namespace Umbraco.Tests.Integration.Services [Test] public void TagList_Contains_NodeCount() { - var contentService = GetRequiredService(); - var contentTypeService = GetRequiredService(); - var tagService = GetRequiredService(); - var dataTypeService = GetRequiredService(); var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); contentType.PropertyGroups.First().PropertyTypes.Add( new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext, "tags") { DataTypeId = Constants.DataTypes.Tags }); - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow", "pig", "goat" }); - contentService.SaveAndPublish(content1); + content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); + ContentService.SaveAndPublish(content1); var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow", "pig" }); - contentService.SaveAndPublish(content2); + content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig" }); + ContentService.SaveAndPublish(content2); var content3 = MockedContent.CreateSimpleContent(contentType, "Tagged content 3", -1); - content3.AssignTags(PropertyEditorCollection, dataTypeService, "tags", new[] { "cow" }); - contentService.SaveAndPublish(content3); + content3.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); + ContentService.SaveAndPublish(content3); // Act - var tags = tagService.GetAllContentTags() + var tags = TagService.GetAllContentTags() .OrderByDescending(x => x.NodeCount) .ToList(); From e1170b8f12410b56400df301d6559089793627c8 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Sun, 4 Oct 2020 21:19:40 +0200 Subject: [PATCH 48/53] Migrates more service tests and other required implementation changes --- .../Services/Implement/UserService.cs | 4 +- .../TestHelpers/Entities/MockedUser.cs | 37 ++ .../Services/LocalizationServiceTests.cs | 170 ++++---- .../Services/MediaServiceTests.cs | 143 ++++--- .../Services/PublicAccessServiceTests.cs | 79 ++-- .../Services/UserServiceTests.cs | 384 +++++++++--------- src/Umbraco.Tests/Umbraco.Tests.csproj | 4 - 7 files changed, 403 insertions(+), 418 deletions(-) rename src/{Umbraco.Tests => Umbraco.Tests.Integration}/Services/LocalizationServiceTests.cs (64%) rename src/{Umbraco.Tests => Umbraco.Tests.Integration}/Services/MediaServiceTests.cs (66%) rename src/{Umbraco.Tests => Umbraco.Tests.Integration}/Services/PublicAccessServiceTests.cs (63%) rename src/{Umbraco.Tests => Umbraco.Tests.Integration}/Services/UserServiceTests.cs (67%) diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index 65fb235054..1928ea3c12 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -998,7 +998,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - internal static EntityPermissionSet CalculatePermissionsForPathForUser( + public static EntityPermissionSet CalculatePermissionsForPathForUser( EntityPermission[] groupPermissions, int[] pathIds) { @@ -1075,7 +1075,7 @@ namespace Umbraco.Core.Services.Implement /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set /// /// - internal static EntityPermission GetPermissionsForPathForGroup( + public static EntityPermission GetPermissionsForPathForGroup( IEnumerable pathPermissions, int[] pathIds, bool fallbackToDefaultPermissions = false) diff --git a/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs index 7488fc1a88..5b77909fec 100644 --- a/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs @@ -1,6 +1,7 @@ using Moq; using System; using System.Collections.Generic; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; namespace Umbraco.Tests.Common.TestHelpers.Entities @@ -21,5 +22,41 @@ namespace Umbraco.Tests.Common.TestHelpers.Entities return userMock; } + public static User CreateUser(string suffix = "") + { + var globalSettings = new GlobalSettings(); + var user = new User(globalSettings) + { + Language = "en", + IsApproved = true, + Name = "TestUser" + suffix, + RawPasswordValue = "testing", + IsLockedOut = false, + Email = "test" + suffix + "@test.com", + Username = "TestUser" + suffix + }; + + return user; + } + + public static IEnumerable CreateMulipleUsers(int amount, Action onCreating = null) + { + var list = new List(); + + var globalSettings = new GlobalSettings(); + for (var i = 0; i < amount; i++) + { + var name = "Member No-" + i; + var user = new User(globalSettings, name, "test" + i + "@test.com", "test" + i, "test" + i); + + onCreating?.Invoke(i, user); + + user.ResetDirtyProperties(false); + + list.Add(user); + } + + return list; + } } } diff --git a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs similarity index 64% rename from src/Umbraco.Tests/Services/LocalizationServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs index 4d3c5fdddc..83d3476324 100644 --- a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs @@ -4,15 +4,14 @@ using System.Diagnostics; using System.Linq; using System.Threading; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Core.Persistence; using Umbraco.Core.Configuration.Models; -using Umbraco.Tests.Common.Builders; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering all methods in the LocalizationService class. @@ -22,7 +21,7 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class LocalizationServiceTests : TestWithSomeContentBase + public class LocalizationServiceTests : UmbracoIntegrationTest { private Guid _parentItemGuidId; private int _parentItemIntId; @@ -32,17 +31,19 @@ namespace Umbraco.Tests.Services private int _englishLangId; private GlobalSettings _globalSettings; + private ILocalizationService LocalizationService => GetRequiredService(); - public override void SetUp() + [SetUp] + public void SetUp() { - base.SetUp(); _globalSettings = new GlobalSettings(); + CreateTestData(); } [Test] public void Can_Get_Root_Dictionary_Items() { - var rootItems = ServiceContext.LocalizationService.GetRootDictionaryItems(); + var rootItems = LocalizationService.GetRootDictionaryItems(); Assert.NotNull(rootItems); Assert.IsTrue(rootItems.Any()); @@ -51,14 +52,14 @@ namespace Umbraco.Tests.Services [Test] public void Can_Determint_If_DictionaryItem_Exists() { - var exists = ServiceContext.LocalizationService.DictionaryItemExists("Parent"); + var exists = LocalizationService.DictionaryItemExists("Parent"); Assert.IsTrue(exists); } [Test] public void Can_Get_All_Languages() { - var languages = ServiceContext.LocalizationService.GetAllLanguages(); + var languages = LocalizationService.GetAllLanguages(); Assert.NotNull(languages); Assert.IsTrue(languages.Any()); Assert.That(languages.Count(), Is.EqualTo(3)); @@ -67,37 +68,37 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Dictionary_Item_By_Int_Id() { - var parentItem = ServiceContext.LocalizationService.GetDictionaryItemById(_parentItemIntId); + var parentItem = LocalizationService.GetDictionaryItemById(_parentItemIntId); Assert.NotNull(parentItem); - var childItem = ServiceContext.LocalizationService.GetDictionaryItemById(_childItemIntId); + var childItem = LocalizationService.GetDictionaryItemById(_childItemIntId); Assert.NotNull(childItem); } [Test] public void Can_Get_Dictionary_Item_By_Guid_Id() { - var parentItem = ServiceContext.LocalizationService.GetDictionaryItemById(_parentItemGuidId); + var parentItem = LocalizationService.GetDictionaryItemById(_parentItemGuidId); Assert.NotNull(parentItem); - var childItem = ServiceContext.LocalizationService.GetDictionaryItemById(_childItemGuidId); + var childItem = LocalizationService.GetDictionaryItemById(_childItemGuidId); Assert.NotNull(childItem); } [Test] public void Can_Get_Dictionary_Item_By_Key() { - var parentItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Parent"); + var parentItem = LocalizationService.GetDictionaryItemByKey("Parent"); Assert.NotNull(parentItem); - var childItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var childItem = LocalizationService.GetDictionaryItemByKey("Child"); Assert.NotNull(childItem); } [Test] public void Can_Get_Dictionary_Item_Children() { - var item = ServiceContext.LocalizationService.GetDictionaryItemChildren(_parentItemGuidId); + var item = LocalizationService.GetDictionaryItemChildren(_parentItemGuidId); Assert.NotNull(item); Assert.That(item.Count(), Is.EqualTo(1)); @@ -113,11 +114,11 @@ namespace Umbraco.Tests.Services { using (var scope = ScopeProvider.CreateScope()) { - var en = ServiceContext.LocalizationService.GetLanguageById(_englishLangId); - var dk = ServiceContext.LocalizationService.GetLanguageById(_danishLangId); + var en = LocalizationService.GetLanguageById(_englishLangId); + var dk = LocalizationService.GetLanguageById(_danishLangId); var currParentId = _childItemGuidId; - for (int i = 0; i < 25; i++) + for (var i = 0; i < 25; i++) { //Create 2 per level var desc1 = new DictionaryItem(currParentId, "D1" + i) @@ -136,8 +137,8 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(dk, "BørnVærdi2 " + i) } }; - ServiceContext.LocalizationService.Save(desc1); - ServiceContext.LocalizationService.Save(desc2); + LocalizationService.Save(desc1); + LocalizationService.Save(desc2); currParentId = desc1.Key; } @@ -145,8 +146,7 @@ namespace Umbraco.Tests.Services scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; scope.Database.AsUmbracoDatabase().EnableSqlCount = true; - var items = ServiceContext.LocalizationService.GetDictionaryItemDescendants(_parentItemGuidId) - .ToArray(); + var items = LocalizationService.GetDictionaryItemDescendants(_parentItemGuidId).ToArray(); Debug.WriteLine("SQL CALLS: " + scope.Database.AsUmbracoDatabase().SqlCount); @@ -159,8 +159,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_GetLanguageById() { - var danish = ServiceContext.LocalizationService.GetLanguageById(_danishLangId); - var english = ServiceContext.LocalizationService.GetLanguageById(_englishLangId); + var danish = LocalizationService.GetLanguageById(_danishLangId); + var english = LocalizationService.GetLanguageById(_englishLangId); Assert.NotNull(danish); Assert.NotNull(english); } @@ -168,8 +168,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_GetLanguageByIsoCode() { - var danish = ServiceContext.LocalizationService.GetLanguageByIsoCode("da-DK"); - var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-GB"); + var danish = LocalizationService.GetLanguageByIsoCode("da-DK"); + var english = LocalizationService.GetLanguageByIsoCode("en-GB"); Assert.NotNull(danish); Assert.NotNull(english); } @@ -177,14 +177,14 @@ namespace Umbraco.Tests.Services [Test] public void Does_Not_Fail_When_Language_Doesnt_Exist() { - var language = ServiceContext.LocalizationService.GetLanguageByIsoCode("sv-SE"); + var language = LocalizationService.GetLanguageByIsoCode("sv-SE"); Assert.Null(language); } [Test] public void Does_Not_Fail_When_DictionaryItem_Doesnt_Exist() { - var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("RandomKey"); + var item = LocalizationService.GetDictionaryItemByKey("RandomKey"); Assert.Null(item); } @@ -192,34 +192,34 @@ namespace Umbraco.Tests.Services public void Can_Delete_Language() { var norwegian = new Language(_globalSettings, "nb-NO") { CultureName = "Norwegian" }; - ServiceContext.LocalizationService.Save(norwegian, 0); + LocalizationService.Save(norwegian, 0); Assert.That(norwegian.HasIdentity, Is.True); var languageId = norwegian.Id; - ServiceContext.LocalizationService.Delete(norwegian); + LocalizationService.Delete(norwegian); - var language = ServiceContext.LocalizationService.GetLanguageById(languageId); + var language = LocalizationService.GetLanguageById(languageId); Assert.Null(language); } [Test] public void Can_Delete_Language_Used_As_Fallback() { - var danish = ServiceContext.LocalizationService.GetLanguageByIsoCode("da-DK"); + var danish = LocalizationService.GetLanguageByIsoCode("da-DK"); var norwegian = new Language(_globalSettings, "nb-NO") { CultureName = "Norwegian", FallbackLanguageId = danish.Id }; - ServiceContext.LocalizationService.Save(norwegian, 0); + LocalizationService.Save(norwegian, 0); var languageId = danish.Id; - ServiceContext.LocalizationService.Delete(danish); + LocalizationService.Delete(danish); - var language = ServiceContext.LocalizationService.GetLanguageById(languageId); + var language = LocalizationService.GetLanguageById(languageId); Assert.Null(language); } [Test] public void Can_Create_DictionaryItem_At_Root() { - var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-US"); + var english = LocalizationService.GetLanguageByIsoCode("en-US"); var item = (IDictionaryItem)new DictionaryItem("Testing123") { @@ -228,10 +228,10 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(english, "Hello world") } }; - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); Assert.Greater(item.Id, 0); Assert.IsTrue(item.HasIdentity); @@ -243,44 +243,42 @@ namespace Umbraco.Tests.Services [Test] public void Can_Create_DictionaryItem_At_Root_With_Identity() { - - var item = ServiceContext.LocalizationService.CreateDictionaryItemWithIdentity( + var item = LocalizationService.CreateDictionaryItemWithIdentity( "Testing12345", null, "Hellooooo"); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); Assert.IsNotNull(item); Assert.Greater(item.Id, 0); Assert.IsTrue(item.HasIdentity); Assert.IsFalse(item.ParentId.HasValue); Assert.AreEqual("Testing12345", item.ItemKey); - var allLangs = ServiceContext.LocalizationService.GetAllLanguages(); + var allLangs = LocalizationService.GetAllLanguages(); Assert.Greater(allLangs.Count(), 0); foreach (var language in allLangs) { Assert.AreEqual("Hellooooo", item.Translations.Single(x => x.Language.CultureName == language.CultureName).Value); } - } [Test] public void Can_Add_Translation_To_Existing_Dictionary_Item() { - var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-US"); + var english = LocalizationService.GetLanguageByIsoCode("en-US"); var item = (IDictionaryItem) new DictionaryItem("Testing123"); - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); item.Translations = new List { new DictionaryTranslation(english, "Hello world") }; - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); Assert.AreEqual(1, item.Translations.Count()); foreach (var translation in item.Translations) @@ -291,14 +289,14 @@ namespace Umbraco.Tests.Services item.Translations = new List(item.Translations) { new DictionaryTranslation( - ServiceContext.LocalizationService.GetLanguageByIsoCode("en-GB"), + LocalizationService.GetLanguageByIsoCode("en-GB"), "My new value") }; - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); Assert.AreEqual(2, item.Translations.Count()); Assert.AreEqual("Hello world", item.Translations.First().Value); @@ -308,27 +306,27 @@ namespace Umbraco.Tests.Services [Test] public void Can_Delete_DictionaryItem() { - var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var item = LocalizationService.GetDictionaryItemByKey("Child"); Assert.NotNull(item); - ServiceContext.LocalizationService.Delete(item); + LocalizationService.Delete(item); - var deletedItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var deletedItem = LocalizationService.GetDictionaryItemByKey("Child"); Assert.Null(deletedItem); } [Test] public void Can_Update_Existing_DictionaryItem() { - var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var item = LocalizationService.GetDictionaryItemByKey("Child"); foreach (var translation in item.Translations) { translation.Value = translation.Value + "UPDATED"; } - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); - var updatedItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var updatedItem = LocalizationService.GetDictionaryItemByKey("Child"); Assert.NotNull(updatedItem); foreach (var translation in updatedItem.Translations) @@ -340,11 +338,8 @@ namespace Umbraco.Tests.Services [Test] public void Find_BaseData_Language() { - // Arrange - var localizationService = ServiceContext.LocalizationService; - // Act - var languages = localizationService.GetAllLanguages(); + var languages = LocalizationService.GetAllLanguages(); // Assert Assert.That(3, Is.EqualTo(languages.Count())); @@ -354,13 +349,12 @@ namespace Umbraco.Tests.Services public void Save_Language_And_GetLanguageByIsoCode() { // Arrange - var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; var language = new Core.Models.Language(_globalSettings, isoCode); // Act - localizationService.Save(language); - var result = localizationService.GetLanguageByIsoCode(isoCode); + LocalizationService.Save(language); + var result = LocalizationService.GetLanguageByIsoCode(isoCode); // Assert Assert.NotNull(result); @@ -369,13 +363,12 @@ namespace Umbraco.Tests.Services [Test] public void Save_Language_And_GetLanguageById() { - var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; var language = new Core.Models.Language(_globalSettings, isoCode); // Act - localizationService.Save(language); - var result = localizationService.GetLanguageById(language.Id); + LocalizationService.Save(language); + var result = LocalizationService.GetLanguageById(language.Id); // Assert Assert.NotNull(result); @@ -384,20 +377,17 @@ namespace Umbraco.Tests.Services [Test] public void Set_Default_Language() { - var localizationService = ServiceContext.LocalizationService; - var language = new Core.Models.Language(_globalSettings, "en-AU"); - language.IsDefault = true; - localizationService.Save(language); - var result = localizationService.GetLanguageById(language.Id); + var language = new Language(_globalSettings, "en-AU") {IsDefault = true}; + LocalizationService.Save(language); + var result = LocalizationService.GetLanguageById(language.Id); Assert.IsTrue(result.IsDefault); - var language2 = new Core.Models.Language(_globalSettings, "en-NZ"); - language2.IsDefault = true; - localizationService.Save(language2); - var result2 = localizationService.GetLanguageById(language2.Id); + var language2 = new Language(_globalSettings, "en-NZ") {IsDefault = true}; + LocalizationService.Save(language2); + var result2 = LocalizationService.GetLanguageById(language2.Id); //re-get - result = localizationService.GetLanguageById(language.Id); + result = LocalizationService.GetLanguageById(language.Id); Assert.IsTrue(result2.IsDefault); Assert.IsFalse(result.IsDefault); @@ -406,25 +396,24 @@ namespace Umbraco.Tests.Services [Test] public void Deleted_Language_Should_Not_Exist() { - var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; var language = new Core.Models.Language(_globalSettings, isoCode); - localizationService.Save(language); + LocalizationService.Save(language); // Act - localizationService.Delete(language); - var result = localizationService.GetLanguageByIsoCode(isoCode); + LocalizationService.Delete(language); + var result = LocalizationService.GetLanguageByIsoCode(isoCode); // Assert Assert.Null(result); } - public override void CreateTestData() + public void CreateTestData() { var danish = new Language(_globalSettings, "da-DK") { CultureName = "Danish" }; var english = new Language(_globalSettings, "en-GB") { CultureName = "English" }; - ServiceContext.LocalizationService.Save(danish, 0); - ServiceContext.LocalizationService.Save(english, 0); + LocalizationService.Save(danish, 0); + LocalizationService.Save(english, 0); _danishLangId = danish.Id; _englishLangId = english.Id; @@ -436,7 +425,7 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(danish, "ForældreVærdi") } }; - ServiceContext.LocalizationService.Save(parentItem); + LocalizationService.Save(parentItem); _parentItemGuidId = parentItem.Key; _parentItemIntId = parentItem.Id; @@ -448,10 +437,9 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(danish, "BørnVærdi") } }; - ServiceContext.LocalizationService.Save(childItem); + LocalizationService.Save(childItem); _childItemGuidId = childItem.Key; _childItemIntId = childItem.Id; } - } } diff --git a/src/Umbraco.Tests/Services/MediaServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs similarity index 66% rename from src/Umbraco.Tests/Services/MediaServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs index b3dc274c5e..a43f21d061 100644 --- a/src/Umbraco.Tests/Services/MediaServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs @@ -1,38 +1,34 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Text; using System.Threading; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Events; using Umbraco.Core.Models; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] - public class MediaServiceTests : TestWithSomeContentBase + public class MediaServiceTests : UmbracoIntegrationTest { + private IMediaService MediaService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + /// /// Used to list out all ambiguous events that will require dispatching with a name /// [Test, Explicit] public void List_Ambiguous_Events() { - var events = ServiceContext.MediaService.GetType().GetEvents(BindingFlags.Static | BindingFlags.Public); + var events = MediaService.GetType().GetEvents(BindingFlags.Static | BindingFlags.Public); var typedEventHandler = typeof(TypedEventHandler<,>); foreach (var e in events) { @@ -55,32 +51,37 @@ namespace Umbraco.Tests.Services [Test] public void Get_Paged_Children_With_Media_Type_Filter() { - var mediaService = ServiceContext.MediaService; var mediaType1 = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType1); + MediaTypeService.Save(mediaType1); var mediaType2 = MockedContentTypes.CreateImageMediaType("Image3"); - ServiceContext.MediaTypeService.Save(mediaType2); + MediaTypeService.Save(mediaType2); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { var m1 = MockedMedia.CreateMediaImage(mediaType1, -1); - mediaService.Save(m1); + MediaService.Save(m1); var m2 = MockedMedia.CreateMediaImage(mediaType2, -1); - mediaService.Save(m2); + MediaService.Save(m2); } long total; - var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total, - SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), - Ordering.By("SortOrder", Direction.Ascending)); - Assert.AreEqual(11, result.Count()); - Assert.AreEqual(20, total); + var provider = ScopeProvider; + using (provider.CreateScope()) + { + var result = MediaService.GetPagedChildren(-1, 0, 11, out total, + provider.SqlContext.Query() + .Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), + Ordering.By("SortOrder", Direction.Ascending)); + Assert.AreEqual(11, result.Count()); + Assert.AreEqual(20, total); - result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total, - SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), - Ordering.By("SortOrder", Direction.Ascending)); - Assert.AreEqual(9, result.Count()); - Assert.AreEqual(20, total); + result = MediaService.GetPagedChildren(-1, 1, 11, out total, + provider.SqlContext.Query() + .Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), + Ordering.By("SortOrder", Direction.Ascending)); + Assert.AreEqual(9, result.Count()); + Assert.AreEqual(20, total); + } } [Test] @@ -88,11 +89,10 @@ namespace Umbraco.Tests.Services { // Arrange var mediaItems = CreateTrashedTestMedia(); - var mediaService = ServiceContext.MediaService; - var media = mediaService.GetById(mediaItems.Item3.Id); + var media = MediaService.GetById(mediaItems.Item3.Id); // Act - mediaService.Move(media, mediaItems.Item2.Id); + MediaService.Move(media, mediaItems.Item2.Id); // Assert Assert.That(media.ParentId, Is.EqualTo(mediaItems.Item2.Id)); @@ -104,11 +104,10 @@ namespace Umbraco.Tests.Services { // Arrange var mediaItems = CreateTrashedTestMedia(); - var mediaService = ServiceContext.MediaService; - var media = mediaService.GetById(mediaItems.Item1.Id); + var media = MediaService.GetById(mediaItems.Item1.Id); // Act - mediaService.MoveToRecycleBin(media); + MediaService.MoveToRecycleBin(media); // Assert Assert.That(media.ParentId, Is.EqualTo(-21)); @@ -120,12 +119,11 @@ namespace Umbraco.Tests.Services { // Arrange var mediaItems = CreateTrashedTestMedia(); - var mediaService = ServiceContext.MediaService; - var media = mediaService.GetById(mediaItems.Item4.Id); + var media = MediaService.GetById(mediaItems.Item4.Id); // Act - moving out of recycle bin - mediaService.Move(media, mediaItems.Item1.Id); - var mediaChild = mediaService.GetById(mediaItems.Item5.Id); + MediaService.Move(media, mediaItems.Item1.Id); + var mediaChild = MediaService.GetById(mediaItems.Item5.Id); // Assert Assert.That(media.ParentId, Is.EqualTo(mediaItems.Item1.Id)); @@ -138,43 +136,40 @@ namespace Umbraco.Tests.Services public void Cannot_Save_Media_With_Empty_Name() { // Arrange - var mediaService = ServiceContext.MediaService; var mediaType = MockedContentTypes.CreateVideoMediaType(); - ServiceContext.MediaTypeService.Save(mediaType); - var media = mediaService.CreateMedia(string.Empty, -1, "video"); + MediaTypeService.Save(mediaType); + var media = MediaService.CreateMedia(string.Empty, -1, "video"); // Act & Assert - Assert.Throws(() => mediaService.Save(media)); + Assert.Throws(() => MediaService.Save(media)); } - + /* [Test] public void Ensure_Content_Xml_Created() { - var mediaService = ServiceContext.MediaService; var mediaType = MockedContentTypes.CreateVideoMediaType(); - ServiceContext.MediaTypeService.Save(mediaType); - var media = mediaService.CreateMedia("Test", -1, "video"); + MediaTypeService.Save(mediaType); + var media = MediaService.CreateMedia("Test", -1, "video"); - mediaService.Save(media); + MediaService.Save(media); using (var scope = ScopeProvider.CreateScope()) { Assert.IsTrue(scope.Database.Exists(media.Id)); } - } + }*/ [Test] public void Can_Get_Media_By_Path() { - var mediaService = ServiceContext.MediaService; var mediaType = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); + MediaTypeService.Save(mediaType); var media = MockedMedia.CreateMediaImage(mediaType, -1); - mediaService.Save(media); + MediaService.Save(media); var mediaPath = "/media/test-image.png"; - var resolvedMedia = mediaService.GetMediaByPath(mediaPath); + var resolvedMedia = MediaService.GetMediaByPath(mediaPath); Assert.IsNotNull(resolvedMedia); Assert.That(resolvedMedia.GetValue(Constants.Conventions.Media.File).ToString() == mediaPath); @@ -183,15 +178,14 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Media_With_Crop_By_Path() { - var mediaService = ServiceContext.MediaService; var mediaType = MockedContentTypes.CreateImageMediaTypeWithCrop("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); + MediaTypeService.Save(mediaType); var media = MockedMedia.CreateMediaImageWithCrop(mediaType, -1); - mediaService.Save(media); + MediaService.Save(media); var mediaPath = "/media/test-image.png"; - var resolvedMedia = mediaService.GetMediaByPath(mediaPath); + var resolvedMedia = MediaService.GetMediaByPath(mediaPath); Assert.IsNotNull(resolvedMedia); Assert.That(resolvedMedia.GetValue(Constants.Conventions.Media.File).ToString().Contains(mediaPath)); @@ -201,14 +195,14 @@ namespace Umbraco.Tests.Services public void Can_Get_Paged_Children() { var mediaType = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); - for (int i = 0; i < 10; i++) + MediaTypeService.Save(mediaType); + for (var i = 0; i < 10; i++) { var c1 = MockedMedia.CreateMediaImage(mediaType, -1); - ServiceContext.MediaService.Save(c1); + MediaService.Save(c1); } - var service = ServiceContext.MediaService; + var service = MediaService; long total; var entities = service.GetPagedChildren(-1, 0, 6, out total).ToArray(); @@ -223,25 +217,25 @@ namespace Umbraco.Tests.Services public void Can_Get_Paged_Children_Dont_Get_Descendants() { var mediaType = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); + MediaTypeService.Save(mediaType); // only add 9 as we also add a folder with children - for (int i = 0; i < 9; i++) + for (var i = 0; i < 9; i++) { var m1 = MockedMedia.CreateMediaImage(mediaType, -1); - ServiceContext.MediaService.Save(m1); + MediaService.Save(m1); } var mediaTypeForFolder = MockedContentTypes.CreateImageMediaType("Folder2"); - ServiceContext.MediaTypeService.Save(mediaTypeForFolder); + MediaTypeService.Save(mediaTypeForFolder); var mediaFolder = MockedMedia.CreateMediaFolder(mediaTypeForFolder, -1); - ServiceContext.MediaService.Save(mediaFolder); - for (int i = 0; i < 10; i++) + MediaService.Save(mediaFolder); + for (var i = 0; i < 10; i++) { var m1 = MockedMedia.CreateMediaImage(mediaType, mediaFolder.Id); - ServiceContext.MediaService.Save(m1); + MediaService.Save(m1); } - var service = ServiceContext.MediaService; + var service = MediaService; long total; // children in root including the folder - not the descendants in the folder @@ -264,29 +258,28 @@ namespace Umbraco.Tests.Services private Tuple CreateTrashedTestMedia() { //Create and Save folder-Media -> 1050 - var folderMediaType = ServiceContext.MediaTypeService.Get(1031); + var folderMediaType = MediaTypeService.Get(1031); var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); - ServiceContext.MediaService.Save(folder); + MediaService.Save(folder); //Create and Save folder-Media -> 1051 var folder2 = MockedMedia.CreateMediaFolder(folderMediaType, -1); - ServiceContext.MediaService.Save(folder2); + MediaService.Save(folder2); //Create and Save image-Media -> 1052 - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); + var imageMediaType = MediaTypeService.Get(1032); var image = (Media)MockedMedia.CreateMediaImage(imageMediaType, 1050); - ServiceContext.MediaService.Save(image); + MediaService.Save(image); //Create and Save folder-Media that is trashed -> 1053 var folderTrashed = (Media)MockedMedia.CreateMediaFolder(folderMediaType, -21); folderTrashed.Trashed = true; - ServiceContext.MediaService.Save(folderTrashed); + MediaService.Save(folderTrashed); //Create and Save image-Media child of folderTrashed -> 1054 var imageTrashed = (Media)MockedMedia.CreateMediaImage(imageMediaType, folderTrashed.Id); imageTrashed.Trashed = true; - ServiceContext.MediaService.Save(imageTrashed); - + MediaService.Save(imageTrashed); return new Tuple(folder, folder2, image, folderTrashed, imageTrashed); } diff --git a/src/Umbraco.Tests/Services/PublicAccessServiceTests.cs b/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs similarity index 63% rename from src/Umbraco.Tests/Services/PublicAccessServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs index 8434aad332..5294e8015b 100644 --- a/src/Umbraco.Tests/Services/PublicAccessServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs @@ -4,41 +4,42 @@ using System.Threading; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PublicAccessServiceTests : TestWithSomeContentBase + public class PublicAccessServiceTests : UmbracoIntegrationTest { + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private IPublicAccessService PublicAccessService => GetRequiredService(); + [Test] public void Can_Add_New_Entry() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); + FileService.SaveTemplate(ct.DefaultTemplate); + ContentTypeService.Save(ct); var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; - + ContentService.Save(c); // Act var entry = new PublicAccessEntry(c, c, c, new[] - { + { new PublicAccessRule() { RuleType = "TestType", RuleValue = "TestVal" }, }); - var result = publicAccessService.Save(entry); + var result = PublicAccessService.Save(entry); // Assert Assert.IsTrue(result.Success); @@ -54,28 +55,25 @@ namespace Umbraco.Tests.Services public void Can_Add_Rule() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); + FileService.SaveTemplate(ct.DefaultTemplate); + ContentTypeService.Save(ct); var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; + ContentService.Save(c); var entry = new PublicAccessEntry(c, c, c, new[] - { + { new PublicAccessRule() { RuleType = "TestType", RuleValue = "TestVal" }, }); - publicAccessService.Save(entry); + PublicAccessService.Save(entry); // Act - var updated = publicAccessService.AddRule(c, "TestType2", "AnotherVal"); + var updated = PublicAccessService.AddRule(c, "TestType2", "AnotherVal"); //re-get - entry = publicAccessService.GetEntryForContent(c); + entry = PublicAccessService.GetEntryForContent(c); // Assert Assert.IsTrue(updated.Success); @@ -87,30 +85,27 @@ namespace Umbraco.Tests.Services public void Can_Add_Multiple_Value_For_Same_Rule_Type() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); + FileService.SaveTemplate(ct.DefaultTemplate); + ContentTypeService.Save(ct); var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; + ContentService.Save(c); var entry = new PublicAccessEntry(c, c, c, new[] - { + { new PublicAccessRule() { RuleType = "TestType", RuleValue = "TestVal" }, }); - publicAccessService.Save(entry); + PublicAccessService.Save(entry); // Act - var updated1 = publicAccessService.AddRule(c, "TestType", "AnotherVal1"); - var updated2 = publicAccessService.AddRule(c, "TestType", "AnotherVal2"); + var updated1 = PublicAccessService.AddRule(c, "TestType", "AnotherVal1"); + var updated2 = PublicAccessService.AddRule(c, "TestType", "AnotherVal2"); //re-get - entry = publicAccessService.GetEntryForContent(c); + entry = PublicAccessService.GetEntryForContent(c); // Assert Assert.IsTrue(updated1.Success); @@ -124,16 +119,13 @@ namespace Umbraco.Tests.Services public void Can_Remove_Rule() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); + FileService.SaveTemplate(ct.DefaultTemplate); + ContentTypeService.Save(ct); var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; + ContentService.Save(c); var entry = new PublicAccessEntry(c, c, c, new[] - { + { new PublicAccessRule() { RuleType = "TestType", @@ -145,12 +137,12 @@ namespace Umbraco.Tests.Services RuleValue = "TestValue2" }, }); - publicAccessService.Save(entry); + PublicAccessService.Save(entry); // Act - var removed = publicAccessService.RemoveRule(c, "TestType", "TestValue1"); + var removed = PublicAccessService.RemoveRule(c, "TestType", "TestValue1"); //re-get - entry = publicAccessService.GetEntryForContent(c); + entry = PublicAccessService.GetEntryForContent(c); // Assert Assert.IsTrue(removed.Success); @@ -158,6 +150,5 @@ namespace Umbraco.Tests.Services Assert.AreEqual(1, entry.Rules.Count()); Assert.AreEqual("TestValue2", entry.Rules.ElementAt(0).RuleValue); } - } } diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests.Integration/Services/UserServiceTests.cs similarity index 67% rename from src/Umbraco.Tests/Services/UserServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/UserServiceTests.cs index 76eda054bc..64bd89c8f8 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/UserServiceTests.cs @@ -12,43 +12,45 @@ using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Actions; -using MockedUser = Umbraco.Tests.TestHelpers.Entities.MockedUser; +using MockedUser = Umbraco.Tests.Common.TestHelpers.Entities.MockedUser; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering the UserService /// [TestFixture] [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] - public class UserServiceTests : TestWithSomeContentBase + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class UserServiceTests : UmbracoIntegrationTest { + private UserService UserService => (UserService) GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + [Test] public void Get_User_Permissions_For_Unassigned_Permission_Nodes() { // Arrange - var userService = ServiceContext.UserService; - var user = CreateTestUser(out var userGroup); + var user = CreateTestUser(out _); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content = new[] { MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); // Act - var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id) - .ToArray(); + var permissions = UserService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(17, permissions[0].AssignedPermissions.Length); Assert.AreEqual(17, permissions[1].AssignedPermissions.Length); @@ -59,30 +61,28 @@ namespace Umbraco.Tests.Services public void Get_User_Permissions_For_Assigned_Permission_Nodes() { // Arrange - var userService = ServiceContext.UserService; - IUserGroup userGroup; - var user = CreateTestUser(out userGroup); + var user = CreateTestUser(out var userGroup); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content = new[] { MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[2], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); + var permissions = UserService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(3, permissions[0].AssignedPermissions.Length); Assert.AreEqual(2, permissions[1].AssignedPermissions.Length); @@ -93,29 +93,28 @@ namespace Umbraco.Tests.Services public void Get_UserGroup_Assigned_Permissions() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content = new[] { MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(2), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content.ElementAt(0), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(0), ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(0), ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(1), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(1), ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(2), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissions(userGroup, false, content[0].Id, content[1].Id, content[2].Id).ToArray(); + var permissions = UserService.GetPermissions(userGroup, false, content[0].Id, content[1].Id, content[2].Id).ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(3, permissions[0].AssignedPermissions.Length); Assert.AreEqual(2, permissions[1].AssignedPermissions.Length); @@ -126,29 +125,28 @@ namespace Umbraco.Tests.Services public void Get_UserGroup_Assigned_And_Default_Permissions() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content = new[] { MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissions(userGroup, true, content[0].Id, content[1].Id, content[2].Id) + var permissions = UserService.GetPermissions(userGroup, true, content[0].Id, content[1].Id, content[2].Id) .ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(3, permissions[0].AssignedPermissions.Length); Assert.AreEqual(2, permissions[1].AssignedPermissions.Length); @@ -159,44 +157,43 @@ namespace Umbraco.Tests.Services public void Get_All_User_Permissions_For_All_Nodes_With_Explicit_Permission() { // Arrange - var userService = ServiceContext.UserService; var userGroup1 = CreateTestUserGroup(); var userGroup2 = CreateTestUserGroup("test2", "Test 2"); var userGroup3 = CreateTestUserGroup("test3", "Test 3"); - var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); var defaultPermissionCount = userGroup3.Permissions.Count(); user.AddGroup(userGroup1); user.AddGroup(userGroup2); user.AddGroup(userGroup3); - userService.Save(user); + UserService.Save(user); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content = new[] { MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); //assign permissions - we aren't assigning anything explicit for group3 and nothing explicit for content[2] /w group2 - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup2.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup2.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup2.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup2.Id }); + ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); // Act //we don't pass in any nodes so it will return all of them - var result = userService.GetPermissions(user).ToArray(); + var result = UserService.GetPermissions(user).ToArray(); var permissions = result .GroupBy(x => x.EntityId) .ToDictionary(x => x.Key, x => x.GroupBy(a => a.UserGroupId).ToDictionary(a => a.Key, a => a.ToArray())); - //assert + // Assert //there will be 3 since that is how many content items there are Assert.AreEqual(3, permissions.Count); @@ -239,32 +236,31 @@ namespace Umbraco.Tests.Services public void Get_All_User_Group_Permissions_For_All_Nodes() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var content = new[] { MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType), MockedContent.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act //we don't pass in any nodes so it will return all of them - var permissions = userService.GetPermissions(userGroup, true) + var permissions = UserService.GetPermissions(userGroup, true) .GroupBy(x => x.EntityId) .ToDictionary(x => x.Key, x => x); - //assert + // Assert Assert.AreEqual(3, permissions.Count); Assert.IsTrue(permissions.ContainsKey(content[0].Id)); Assert.AreEqual(3, permissions[content[0].Id].SelectMany(x => x.AssignedPermissions).Count()); @@ -339,7 +335,6 @@ namespace Umbraco.Tests.Services allPermissions = result.GetAllPermissions().ToArray(); Assert.AreEqual(5, allPermissions.Length, string.Join(",", allPermissions)); Assert.IsTrue(allPermissions.ContainsAll(new[] { "S", "D", "F", "G", "K" })); - } [Test] @@ -402,28 +397,27 @@ namespace Umbraco.Tests.Services public void Get_User_Implicit_Permissions() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var parent = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(parent); + ContentService.Save(parent); var child1 = MockedContent.CreateSimpleContent(contentType, "child1", parent); - ServiceContext.ContentService.Save(child1); + ContentService.Save(child1); var child2 = MockedContent.CreateSimpleContent(contentType, "child2", child1); - ServiceContext.ContentService.Save(child2); + ContentService.Save(child2); - ServiceContext.ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissionsForPath(userGroup, child2.Path); + var permissions = UserService.GetPermissionsForPath(userGroup, child2.Path); - //assert + // Assert var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(3, allPermissions.Length); } @@ -431,10 +425,10 @@ namespace Umbraco.Tests.Services [Test] public void Can_Delete_User() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - ServiceContext.UserService.Delete(user, true); - var deleted = ServiceContext.UserService.GetUserById(user.Id); + UserService.Delete(user, true); + var deleted = UserService.GetUserById(user.Id); // Assert Assert.That(deleted, Is.Null); @@ -443,10 +437,10 @@ namespace Umbraco.Tests.Services [Test] public void Disables_User_Instead_Of_Deleting_If_Flag_Not_Set() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - ServiceContext.UserService.Delete(user); - var deleted = ServiceContext.UserService.GetUserById(user.Id); + UserService.Delete(user); + var deleted = UserService.GetUserById(user.Id); // Assert Assert.That(deleted, Is.Not.Null); @@ -455,60 +449,60 @@ namespace Umbraco.Tests.Services [Test] public void Exists_By_Username() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - var user2 = ServiceContext.UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io"); - Assert.IsTrue(ServiceContext.UserService.Exists("JohnDoe")); - Assert.IsFalse(ServiceContext.UserService.Exists("notFound")); - Assert.IsTrue(ServiceContext.UserService.Exists("john2@umbraco.io")); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user2 = UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io"); + Assert.IsTrue(UserService.Exists("JohnDoe")); + Assert.IsFalse(UserService.Exists("notFound")); + Assert.IsTrue(UserService.Exists("john2@umbraco.io")); } [Test] public void Get_By_Email() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetByEmail(user.Email)); - Assert.IsNull(ServiceContext.UserService.GetByEmail("do@not.find")); + Assert.IsNotNull(UserService.GetByEmail(user.Email)); + Assert.IsNull(UserService.GetByEmail("do@not.find")); } [Test] public void Get_By_Username() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); - Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); + Assert.IsNotNull(UserService.GetByUsername(user.Username)); + Assert.IsNull(UserService.GetByUsername("notFound")); } [Test] public void Get_By_Username_With_Backslash() { - var user = ServiceContext.UserService.CreateUserWithIdentity("mydomain\\JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("mydomain\\JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); - Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); + Assert.IsNotNull(UserService.GetByUsername(user.Username)); + Assert.IsNull(UserService.GetByUsername("notFound")); } [Test] public void Get_By_Object_Id() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetUserById(user.Id)); - Assert.IsNull(ServiceContext.UserService.GetUserById(9876)); + Assert.IsNotNull(UserService.GetUserById(user.Id)); + Assert.IsNull(UserService.GetUserById(9876)); } [Test] public void Find_By_Email_Starts_With() { var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + UserService.Save(users); //don't find this var customUser = MockedUser.CreateUser(); customUser.Email = "hello@hello.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("tes", 0, 100, out _, StringPropertyMatchType.StartsWith); + var found = UserService.FindByEmail("tes", 0, 100, out _, StringPropertyMatchType.StartsWith); Assert.AreEqual(10, found.Count()); } @@ -517,13 +511,13 @@ namespace Umbraco.Tests.Services public void Find_By_Email_Ends_With() { var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + UserService.Save(users); //include this var customUser = MockedUser.CreateUser(); customUser.Email = "hello@test.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("test.com", 0, 100, out _, StringPropertyMatchType.EndsWith); + var found = UserService.FindByEmail("test.com", 0, 100, out _, StringPropertyMatchType.EndsWith); Assert.AreEqual(11, found.Count()); } @@ -532,13 +526,13 @@ namespace Umbraco.Tests.Services public void Find_By_Email_Contains() { var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + UserService.Save(users); //include this var customUser = MockedUser.CreateUser(); customUser.Email = "hello@test.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("test", 0, 100, out _, StringPropertyMatchType.Contains); + var found = UserService.FindByEmail("test", 0, 100, out _, StringPropertyMatchType.Contains); Assert.AreEqual(11, found.Count()); } @@ -547,13 +541,13 @@ namespace Umbraco.Tests.Services public void Find_By_Email_Exact() { var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + UserService.Save(users); //include this var customUser = MockedUser.CreateUser(); customUser.Email = "hello@test.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("hello@test.com", 0, 100, out _, StringPropertyMatchType.Exact); + var found = UserService.FindByEmail("hello@test.com", 0, 100, out _, StringPropertyMatchType.Exact); Assert.AreEqual(1, found.Count()); } @@ -562,9 +556,9 @@ namespace Umbraco.Tests.Services public void Get_All_Paged_Users() { var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + UserService.Save(users); - var found = ServiceContext.UserService.GetAll(0, 2, out var totalRecs); + var found = UserService.GetAll(0, 2, out var totalRecs); Assert.AreEqual(2, found.Count()); // + 1 because of the built in admin user @@ -577,9 +571,9 @@ namespace Umbraco.Tests.Services public void Get_All_Paged_Users_With_Filter() { var users = MockedUser.CreateMulipleUsers(10).ToArray(); - ServiceContext.UserService.Save(users); + UserService.Save(users); - var found = ServiceContext.UserService.GetAll(0, 2, out var totalRecs, "username", Direction.Ascending, filter: "test"); + var found = UserService.GetAll(0, 2, out var totalRecs, "username", Direction.Ascending, filter: "test"); Assert.AreEqual(2, found.Count()); Assert.AreEqual(10, totalRecs); @@ -591,7 +585,7 @@ namespace Umbraco.Tests.Services public void Get_All_Paged_Users_For_Group() { var userGroup = MockedUserGroup.CreateUserGroup(); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); var users = MockedUser.CreateMulipleUsers(10).ToArray(); for (var i = 0; i < 10;) @@ -599,10 +593,10 @@ namespace Umbraco.Tests.Services users[i].AddGroup(userGroup.ToReadOnlyGroup()); i = i + 2; } - ServiceContext.UserService.Save(users); + UserService.Save(users); long totalRecs; - var found = ServiceContext.UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, includeUserGroups: new[] {userGroup.Alias}); + var found = UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, includeUserGroups: new[] { userGroup.Alias }); Assert.AreEqual(2, found.Count()); Assert.AreEqual(5, totalRecs); @@ -614,7 +608,7 @@ namespace Umbraco.Tests.Services public void Get_All_Paged_Users_For_Group_With_Filter() { var userGroup = MockedUserGroup.CreateUserGroup(); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); var users = MockedUser.CreateMulipleUsers(10).ToArray(); for (var i = 0; i < 10;) @@ -627,10 +621,10 @@ namespace Umbraco.Tests.Services users[i].Name = "blah" + users[i].Name; i = i + 3; } - ServiceContext.UserService.Save(users); + UserService.Save(users); long totalRecs; - var found = ServiceContext.UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, userGroups: new[] { userGroup.Alias }, filter: "blah"); + var found = UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, userGroups: new[] { userGroup.Alias }, filter: "blah"); Assert.AreEqual(2, found.Count()); Assert.AreEqual(2, totalRecs); @@ -642,11 +636,11 @@ namespace Umbraco.Tests.Services public void Count_All_Users() { var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + UserService.Save(users); var customUser = MockedUser.CreateUser(); - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.GetCount(MemberCountType.All); + var found = UserService.GetCount(MemberCountType.All); // + 1 because of the built in admin user Assert.AreEqual(12, found); @@ -657,7 +651,7 @@ namespace Umbraco.Tests.Services public void Count_All_Online_Users() { var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.LastLoginDate = DateTime.Now.AddMinutes(i * -2)); - ServiceContext.UserService.Save(users); + UserService.Save(users); var customUser = MockedUser.CreateUser(); throw new NotImplementedException(); @@ -667,13 +661,13 @@ namespace Umbraco.Tests.Services public void Count_All_Locked_Users() { var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.IsLockedOut = i % 2 == 0); - ServiceContext.UserService.Save(users); + UserService.Save(users); var customUser = MockedUser.CreateUser(); customUser.IsLockedOut = true; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.GetCount(MemberCountType.LockedOut); + var found = UserService.GetCount(MemberCountType.LockedOut); Assert.AreEqual(6, found); } @@ -682,13 +676,13 @@ namespace Umbraco.Tests.Services public void Count_All_Approved_Users() { var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.IsApproved = i % 2 == 0); - ServiceContext.UserService.Save(users); + UserService.Save(users); var customUser = MockedUser.CreateUser(); customUser.IsApproved = false; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.GetCount(MemberCountType.Approved); + var found = UserService.GetCount(MemberCountType.Approved); // + 1 because of the built in admin user Assert.AreEqual(6, found); @@ -697,11 +691,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_Persist_New_User() { - // Arrange - var userService = ServiceContext.UserService; - // Act - var membershipUser = userService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var membershipUser = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); // Assert Assert.That(membershipUser.HasIdentity, Is.True); @@ -713,9 +704,6 @@ namespace Umbraco.Tests.Services [Test] public void Can_Persist_New_User_With_Hashed_Password() { - // Arrange - var userService = ServiceContext.UserService; - // Act // NOTE: Normally the hash'ing would be handled in the membership provider, so the service just saves the password var password = "123456"; @@ -724,7 +712,7 @@ namespace Umbraco.Tests.Services var encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password))); var globalSettings = new GlobalSettings(); var membershipUser = new User(globalSettings, "JohnDoe", "john@umbraco.io", encodedPassword, encodedPassword); - userService.Save(membershipUser); + UserService.Save(membershipUser); // Assert Assert.That(membershipUser.HasIdentity, Is.True); @@ -744,9 +732,9 @@ namespace Umbraco.Tests.Services }; userGroup.AddAllowedSection("content"); userGroup.AddAllowedSection("mediat"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); - var result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); + var result1 = UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(2, result1.AllowedSections.Count()); @@ -755,9 +743,9 @@ namespace Umbraco.Tests.Services userGroup.AddAllowedSection("test2"); userGroup.AddAllowedSection("test3"); userGroup.AddAllowedSection("test4"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); - result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); + result1 = UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(6, result1.AllowedSections.Count()); @@ -770,11 +758,11 @@ namespace Umbraco.Tests.Services //now just re-add a couple result1.AddAllowedSection("test3"); result1.AddAllowedSection("test4"); - ServiceContext.UserService.Save(result1); + UserService.Save(result1); - //assert + // Assert //re-get - result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); + result1 = UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(2, result1.AllowedSections.Count()); } @@ -791,21 +779,21 @@ namespace Umbraco.Tests.Services Alias = "Group2", Name = "Group 2" }; - ServiceContext.UserService.Save(userGroup1); - ServiceContext.UserService.Save(userGroup2); + UserService.Save(userGroup1); + UserService.Save(userGroup2); //adds some allowed sections userGroup1.AddAllowedSection("test"); userGroup2.AddAllowedSection("test"); - ServiceContext.UserService.Save(userGroup1); - ServiceContext.UserService.Save(userGroup2); + UserService.Save(userGroup1); + UserService.Save(userGroup2); //now clear the section from all users - ServiceContext.UserService.DeleteSectionFromAllUserGroups("test"); + UserService.DeleteSectionFromAllUserGroups("test"); - //assert - var result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); - var result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); + // Assert + var result1 = UserService.GetUserGroupById(userGroup1.Id); + var result2 = UserService.GetUserGroupById(userGroup2.Id); Assert.IsFalse(result1.AllowedSections.Contains("test")); Assert.IsFalse(result2.AllowedSections.Contains("test")); } @@ -832,14 +820,14 @@ namespace Umbraco.Tests.Services Alias = "Group3", Name = "Group 3" }; - ServiceContext.UserService.Save(userGroup1); - ServiceContext.UserService.Save(userGroup2); - ServiceContext.UserService.Save(userGroup3); + UserService.Save(userGroup1); + UserService.Save(userGroup2); + UserService.Save(userGroup3); - //assert - var result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); - var result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); - var result3 = ServiceContext.UserService.GetUserGroupById(userGroup3.Id); + // Assert + var result1 = UserService.GetUserGroupById(userGroup1.Id); + var result2 = UserService.GetUserGroupById(userGroup2.Id); + var result3 = UserService.GetUserGroupById(userGroup3.Id); Assert.IsTrue(result1.AllowedSections.Contains("test")); Assert.IsTrue(result2.AllowedSections.Contains("test")); Assert.IsFalse(result3.AllowedSections.Contains("test")); @@ -848,13 +836,13 @@ namespace Umbraco.Tests.Services foreach (var userGroup in new[] { userGroup1, userGroup2, userGroup3 }) { userGroup.AddAllowedSection("test"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); } - //assert - result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); - result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); - result3 = ServiceContext.UserService.GetUserGroupById(userGroup3.Id); + // Assert + result1 = UserService.GetUserGroupById(userGroup1.Id); + result2 = UserService.GetUserGroupById(userGroup2.Id); + result3 = UserService.GetUserGroupById(userGroup3.Id); Assert.IsTrue(result1.AllowedSections.Contains("test")); Assert.IsTrue(result2.AllowedSections.Contains("test")); Assert.IsTrue(result3.AllowedSections.Contains("test")); @@ -863,46 +851,40 @@ namespace Umbraco.Tests.Services [Test] public void Cannot_Create_User_With_Empty_Username() { - // Arrange - var userService = ServiceContext.UserService; - // Act & Assert - Assert.Throws(() => userService.CreateUserWithIdentity(string.Empty, "john@umbraco.io")); + Assert.Throws(() => UserService.CreateUserWithIdentity(string.Empty, "john@umbraco.io")); } [Test] public void Cannot_Save_User_With_Empty_Username() { // Arrange - var userService = ServiceContext.UserService; - var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); user.Username = string.Empty; // Act & Assert - Assert.Throws(() => userService.Save(user)); + Assert.Throws(() => UserService.Save(user)); } [Test] public void Cannot_Save_User_With_Empty_Name() { // Arrange - var userService = ServiceContext.UserService; - var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); user.Name = string.Empty; // Act & Assert - Assert.Throws(() => userService.Save(user)); + Assert.Throws(() => UserService.Save(user)); } [Test] public void Get_By_Profile_Username() { // Arrange - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + var user = UserService.CreateUserWithIdentity("test1", "test1@test.com"); // Act - - var profile = ServiceContext.UserService.GetProfileByUserName(user.Username); + var profile = UserService.GetProfileByUserName(user.Username); // Assert Assert.IsNotNull(profile); @@ -914,11 +896,10 @@ namespace Umbraco.Tests.Services public void Get_By_Profile_Id() { // Arrange - var user = (IUser)ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + var user = (IUser)UserService.CreateUserWithIdentity("test1", "test1@test.com"); // Act - - var profile = ServiceContext.UserService.GetProfileById((int)user.Id); + var profile = UserService.GetProfileById((int)user.Id); // Assert Assert.IsNotNull(profile); @@ -929,7 +910,7 @@ namespace Umbraco.Tests.Services [Test] public void Get_By_Profile_Id_Must_return_null_if_user_not_exists() { - var profile = ServiceContext.UserService.GetProfileById(42); + var profile = UserService.GetProfileById(42); // Assert Assert.IsNull(profile); @@ -938,7 +919,7 @@ namespace Umbraco.Tests.Services [Test] public void GetProfilesById_Must_empty_if_users_not_exists() { - var profiles = ServiceContext.UserService.GetProfilesById(42); + var profiles = UserService.GetProfilesById(42); // Assert CollectionAssert.IsEmpty(profiles); @@ -948,12 +929,11 @@ namespace Umbraco.Tests.Services public void Get_User_By_Username() { // Arrange - IUserGroup userGroup; - var originalUser = CreateTestUser(out userGroup); + var originalUser = CreateTestUser(out _); // Act - var updatedItem = (User) ServiceContext.UserService.GetByUsername(originalUser.Username); + var updatedItem = (User)UserService.GetByUsername(originalUser.Username); // Assert Assert.IsNotNull(updatedItem); @@ -981,7 +961,7 @@ namespace Umbraco.Tests.Services CreateTestUsers(startContentItems.Select(x => x.Id).ToArray(), testUserGroup, 3); - var usersInGroup = ServiceContext.UserService.GetAllInGroup(userGroupId); + var usersInGroup = UserService.GetAllInGroup(userGroupId); foreach (var user in usersInGroup) Assert.AreEqual(user.StartContentIds.Length, startContentItems.Length); @@ -991,14 +971,14 @@ namespace Umbraco.Tests.Services { var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var startContentItems = new List(); for (var i = 0; i < numberToCreate; i++) startContentItems.Add(MockedContent.CreateSimpleContent(contentType)); - ServiceContext.ContentService.Save(startContentItems); + ContentService.Save(startContentItems); return startContentItems.ToArray(); } @@ -1007,11 +987,11 @@ namespace Umbraco.Tests.Services { userGroup = CreateTestUserGroup(); - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + var user = UserService.CreateUserWithIdentity("test1", "test1@test.com"); user.AddGroup(userGroup.ToReadOnlyGroup()); - ServiceContext.UserService.Save(user); + UserService.Save(user); return user; } @@ -1022,13 +1002,13 @@ namespace Umbraco.Tests.Services for (var i = 0; i < numberToCreate; i++) { - var user = ServiceContext.UserService.CreateUserWithIdentity($"test{i}", $"test{i}@test.com"); + var user = UserService.CreateUserWithIdentity($"test{i}", $"test{i}@test.com"); user.AddGroup(userGroup.ToReadOnlyGroup()); var updateable = (User)user; updateable.StartContentIds = startContentIds; - ServiceContext.UserService.Save(user); + UserService.Save(user); users.Add(user); } @@ -1048,7 +1028,7 @@ namespace Umbraco.Tests.Services userGroup.AddAllowedSection("content"); userGroup.AddAllowedSection("media"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); return userGroup; } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 70c0e917cb..197e928e1f 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -230,7 +230,6 @@ - @@ -268,16 +267,13 @@ - - - From 4dc26a9f043c999d27be96a693cf9d8bdb1b7e14 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 5 Oct 2020 07:45:28 +0200 Subject: [PATCH 49/53] Fix double nuget reference Signed-off-by: Bjarke Berg --- src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index b72f1d2612..8ddeb42b81 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -24,7 +24,6 @@ - all From 9524aefb9007c1f5ecab962cdbdfd95f8e01ce1b Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 5 Oct 2020 07:49:39 +0200 Subject: [PATCH 50/53] Delete getting-started.json from new project Signed-off-by: Bjarke Berg --- .../Umbraco.Web.UI.NetCore.csproj | 1 + .../BackOfficeTours/getting-started.json | 474 ------------------ 2 files changed, 1 insertion(+), 474 deletions(-) delete mode 100644 src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json 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 1af278cbc3..e68bab7db8 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json b/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json deleted file mode 100644 index 1e3c60661d..0000000000 --- a/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json +++ /dev/null @@ -1,474 +0,0 @@ -[ - { - "name": "Email Marketing", - "alias": "umbEmailMarketing", - "group": "Email Marketing", - "groupOrder": 10, - "hidden": true, - "requiredSections": [ - "content" - ], - "steps": [ - { - "title": "Do you want to stay updated on everything Umbraco?", - "content": "

Thank you for using Umbraco! Would you like to stay up-to-date with Umbraco product updates, security advisories, community news and special offers? Sign up for our newsletter and never miss out on the latest Umbraco news.

By signing up, you agree that we can use your info according to our privacy policy.

", - "view": "emails", - "type": "promotion" - }, - { - "title": "Thank you for subscribing to our mailing list", - "view": "confirm" - } - ] - }, - { - "name": "Introduction", - "alias": "umbIntroIntroduction", - "group": "Getting Started", - "groupOrder": 100, - "allowDisable": true, - "requiredSections": [ - "content" - ], - "steps": [ - { - "title": "Welcome to Umbraco - The Friendly CMS", - "content": "

Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible.

In this quick tour we will introduce you to the main areas of Umbraco and show you how to best get started.

If you don't want to take the tour now you can always start it by opening the Help drawer in the top right corner.

", - "type": "intro" - }, - { - "element": "[data-element='sections']", - "elementPreventClick": true, - "title": "Main Menu", - "content": "This is the main menu in Umbraco backoffice. Here you can navigate between the different sections, search for items, see your user profile and open the help drawer.", - "backdropOpacity": 0.6 - }, - { - "element": "[data-element='section-content']", - "elementPreventClick": true, - "title": "Sections", - "content": "Each area in Umbraco is called a Section. Right now you are in the Content section, when you want to go to another section simply click on the appropriate name in the main menu and you'll be there in no time.", - "backdropOpacity": 0.6 - }, - { - "element": "#tree", - "elementPreventClick": true, - "title": "The Tree", - "content": "

This is the Tree and it is the main navigation inside a section.

In the Content section the tree is called the Content tree and here you can navigate the content of your website.

" - }, - { - "element": "[data-element='dashboard']", - "elementPreventClick": true, - "title": "Dashboards", - "content": "

A dashboard is the main view you are presented with when entering a section within the backoffice, and can be used to show valuable information to the users of the system.

Notice that some sections have multiple dashboards.

" - }, - { - "element": "[data-element='global-search']", - "title": "Search", - "content": "The search allows you to quickly find whatever you're looking for across sections within Umbraco." - }, - { - "element": "[data-element='global-user']", - "title": "User profile", - "content": "Now click on your user avatar to open the user profile dialog.", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "[data-element~='overlay-user']", - "elementPreventClick": true, - "title": "User profile", - "content": "

Here you can see details about your user, change your password and log out of Umbraco.

In the User section you will be able to do more advanced user management.

" - }, - { - "element": "[data-element~='overlay-user'] [data-element='button-overlayClose']", - "title": "User profile", - "content": "Let's close the user profile again.", - "event": "click" - }, - { - "element": "[data-element='global-help']", - "title": "Help", - "content": "If you ever find yourself in trouble click here to open the Help drawer.", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "[data-element='drawer']", - "elementPreventClick": true, - "title": "Help", - "content": "

In the help drawer you will find articles and videos related to the section you are using.

This is also where you will find the next tour on how to get started with Umbraco.

", - "backdropOpacity": 0.6 - }, - { - "element": "[data-element='drawer'] [data-element='help-tours']", - "title": "Tours", - "content": "To continue your journey on getting started with Umbraco, you can find more tours right here." - } - ] - }, - { - "name": "Create document type", - "alias": "umbIntroCreateDocType", - "group": "Getting Started", - "groupOrder": 100, - "requiredSections": [ - "settings" - ], - "steps": [ - { - "title": "Create your first Document Type", - "content": "

Step 1 of any site is to create a Document Type.
A Document Type is a template for content. For each type of content you want to create you'll create a Document Type. This will define where content based on this Document Type can be created, how many properties it holds and what the input method should be for these properties.

When you have at least one Document Type in place you can start creating content and this content can then be used in a template.

In this tour you will learn how to set up a basic Document Type with a property to enter a short text.

", - "type": "intro" - }, - { - "element": "#applications [data-element='section-settings']", - "title": "Navigate to the Settings sections", - "content": "In the Settings section you can create and manage Document types.", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "#tree [data-element='tree-item-documentTypes']", - "title": "Create Document Type", - "content": "

Hover over the Document Type tree and click the three small dots to open the context menu.

", - "event": "click", - "eventElement": "#tree [data-element='tree-item-documentTypes'] [data-element='tree-item-options']" - }, - { - "element": "#dialog [data-element='action-documentType']", - "title": "Create Document Type", - "content": "

Click Document Type to create a new document type with a template. The template will be automatically created and set as the default template for this Document Type.

You will use the template in a later tour to render content.

", - "event": "click" - }, - { - "element": "[data-element='editor-name-field']", - "title": "Enter a name", - "content": "

Your Document Type needs a name. Enter Home Page in the field and click Next.", - "view": "doctypename" - }, - { - "element": "[data-element='editor-description']", - "title": "Enter a description", - "content": "

A description helps to pick the right document type when creating content.

Write a description for our Home page. It could be:

The home page of the website

" - }, - { - "element": "[data-element='group-add']", - "title": "Add group", - "content": "Group are used to organize properties on content in the Content section. Click Add Group to add a group.", - "event": "click" - }, - { - "element": "[data-element='group-name-field']", - "title": "Name the group", - "content": "

Enter Home in the group name.

You can name a group anything you want and if you have a lot of properties it can be useful to add multiple groups.

", - "view": "tabName" - }, - { - "element": "[data-element='property-add']", - "title": "Add a property", - "content": "

Properties are the different input fields on a content page.

On our Home Page we want to add a welcome text.

Click Add property to open the property dialog.

", - "event": "click" - }, - { - "element": "[data-element='editor-property-settings'] [data-element='property-name']", - "title": "Name the property", - "content": "Enter Welcome Text as the name for the property.", - "view": "propertyname" - }, - { - "element": "[data-element~='editor-property-settings'] [data-element='property-description']", - "title": "Enter a description", - "content": "

A description will help your editor fill in the right content.

Enter a description for the property editor. It could be:

Write a nice introduction text so the visitors feel welcome

" - }, - { - "element": "[data-element~='editor-property-settings'] [data-element='editor-add']", - "title": "Add editor", - "content": "When you add an editor you choose what the input method for this property will be. Click Add editor to open the editor picker dialog.", - "event": "click" - }, - { - "element": "[ng-controller*='Umbraco.Editors.DataTypePickerController'] [data-element='editor-data-type-picker']", - "elementPreventClick": true, - "title": "Editor picker", - "content": "

In the editor picker dialog we can pick one of the many built-in editors.

" - }, - { - "element": "[data-element~='editor-data-type-picker'] [data-element='datatype-Textarea']", - "title": "Select editor", - "content": "Select the Textarea editor. This will add a textarea to the Welcome Text property.", - "event": "click" - }, - { - "element": "[data-element='editor-data-type-picker'] [data-element='datatypeconfig-Textarea']", - "title": "Editor settings", - "content": "Each property editor can have individual settings. For the textarea editor you can set a character limit but in this case it is not needed.", - "event": "click" - }, - { - "element": "[data-element~='editor-property-settings'] [data-element='button-submit']", - "title": "Add property to document type", - "content": "Click Submit to add the property to the document type.", - "event": "click" - }, - { - "element": "[data-element~='sub-view-permissions']", - "title": "Check the document type permissions", - "content": "Click Permissions to view the permissions page.", - "event": "click" - }, - { - "element": "[data-element~='permissions-allow-as-root']", - "title": "Allow this document type to work at the root of your site", - "content": "Toggle the switch Allow as root to allow new content pages based on this document type to be created at the root of your site", - "event": "click" - }, - { - "element": "[data-element='button-save']", - "title": "Save the document type", - "content": "All we need now is to save the document type. Click Save to create and save your new document type.", - "event": "click" - } - ] - }, - { - "name": "Create Content", - "alias": "umbIntroCreateContent", - "group": "Getting Started", - "groupOrder": 100, - "requiredSections": [ - "content" - ], - "steps": [ - { - "title": "Creating your first content node", - "content": "

In this tour you will learn how to create the home page for your website. It will use the Home Page Document type you created in the previous tour.

", - "type": "intro" - }, - { - "element": "#applications [data-element='section-content']", - "title": "Navigate to the Content section", - "content": "

In the Content section you can create and manage the content of the website.

The Content section contains the content of your website. Content is displayed as nodes in the content tree.

", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "[data-element='tree-root']", - "title": "Open context menu", - "content": "

Open the context menu by hovering over the root of the content section.

Now click the three small dots to the right.

", - "event": "click", - "eventElement": "#tree [data-element='tree-root'] [data-element='tree-item-options']" - }, - { - "element": "[data-element='action-create-homePage']", - "title": "Create Home page", - "content": "

The context menu shows you all the actions that are available on a node

Click on Home Page to create a new page of type Home Page.

", - "event": "click" - }, - { - "element": "[data-element='editor-content'] [data-element='editor-name-field']", - "title": "Give your new page a name", - "content": "

Our new page needs a name. Enter Home in the field and click Next.

", - "view": "nodename" - }, - { - "element": "[data-element='editor-content'] [data-element='property-welcomeText']", - "title": "Add a welcome text", - "content": "

Add content to the Welcome Text field.

If you don't have any ideas here is a start:

I am learning Umbraco. High Five I Rock #H5IR
.

" - }, - { - "element": "[data-element='editor-content'] [data-element='button-saveAndPublish']", - "title": "Publish", - "content": "

Now click the Publish button to publish your changes.

", - "event": "click" - } - ] - }, - { - "name": "Render in template", - "alias": "umbIntroRenderInTemplate", - "group": "Getting Started", - "groupOrder": 100, - "requiredSections": [ - "settings" - ], - "steps": [ - { - "title": "Render your content in a template", - "content": "

Templating in Umbraco builds on the concept of Razor Views from ASP.NET MVC. This tour is a sneak peak on how to write templates in Umbraco.

In this tour you will learn how to render content from the Home Page document type so you can see the content added to our Home content page.

", - "type": "intro" - }, - { - "element": "#applications [data-element='section-settings']", - "title": "Navigate to the Settings section", - "content": "

In the Settings section you will find all the templates.

It is of course also possible to edit all your code files in your favorite code editor.

", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "#tree [data-element='tree-item-templates']", - "title": "Expand the Templates node", - "content": "

To see all our templates click the small triangle to the left of the templates node.

", - "event": "click", - "eventElement": "#tree [data-element='tree-item-templates'] [data-element='tree-item-expand']", - "view": "templatetree", - "skipStepIfVisible": "#tree [data-element='tree-item-templates'] > div > button[data-element=tree-item-expand].icon-navigation-down" - }, - { - "element": "#tree [data-element='tree-item-templates'] [data-element='tree-item-Home Page']", - "title": "Open Home template", - "content": "

Click the Home Page template to open and edit it.

", - "eventElement": "#tree [data-element='tree-item-templates'] [data-element='tree-item-Home Page'] a.umb-tree-item__label", - "event": "click" - }, - { - "element": "[data-element='editor-templates'] [data-element='code-editor']", - "title": "Edit template", - "content": "

The template can be edited here or in your favorite code editor.

To render the field from the document type add the following to the template:

<h1>@Model.Name</h1>
<p>@Model.WelcomeText</p>

" - }, - { - "element": "[data-element='editor-templates'] [data-element='button-save']", - "title": "Save the template", - "content": "Click the Save button and your template will be saved.", - "event": "click" - } - ] - }, - { - "name": "View Home page", - "alias": "umbIntroViewHomePage", - "group": "Getting Started", - "groupOrder": 100, - "requiredSections": [ - "content" - ], - "steps": [ - { - "title": "View your Umbraco site", - "content": "

Our three main components for a page are done: Document type, Template, and Content. It is now time to see the result.

In this tour you will learn how to see your published website.

", - "type": "intro" - }, - { - "element": "#applications [data-element='section-content']", - "title": "Navigate to the content sections", - "content": "In the Content section you will find the content of our website.", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "#tree [data-element='tree-item-Home']", - "title": "Open the Home page", - "content": "

Click the Home page to open it.

", - "event": "click", - "eventElement": "#tree [data-element='tree-item-Home'] a.umb-tree-item__label" - }, - { - "element": "[data-element='editor-content'] [data-element='sub-view-umbInfo']", - "title": "Info", - "content": "

Under the Info-app you will find the default information about a content item.

", - "event": "click" - }, - { - "element": "[data-element='editor-content'] [data-element='node-info-urls']", - "title": "Open page", - "content": "

Click the Link to document to view your page.

Tip: Click the preview button in the bottom right corner to preview changes without publishing them.

", - "event": "click", - "eventElement": "[data-element='editor-content'] [data-element='node-info-urls'] a[target='_blank']" - } - ] - }, - { - "name": "The Media library", - "alias": "umbIntroMediaSection", - "group": "Getting Started", - "groupOrder": 100, - "requiredSections": [ - "media" - ], - "steps": [ - { - "title": "How to use the media library", - "content": "

A website would be boring without media content. In Umbraco you can manage all your images, documents, videos etc. in the Media section. Here you can upload and organise your media items and see details about each item.

In this tour you will learn how to upload and organise your Media library in Umbraco. It will also show you how to view details about a specific media item.

", - "type": "intro" - }, - { - "element": "#applications [data-element='section-media']", - "title": "Navigate to the Media section", - "content": "The media section is where you manage all your media items.", - "event": "click", - "backdropOpacity": 0.6 - }, - { - "element": "#tree [data-element='tree-root']", - "title": "Create a new folder", - "content": "

First create a folder for your images. Hover over the media root node and click the three small dots on the right side of the item.

", - "event": "click", - "eventElement": "#tree [data-element='tree-root'] [data-element='tree-item-options']" - }, - { - "element": "#dialog [data-element='action-Folder']", - "title": "Create a new folder", - "content": "

Select the Folder option to select the type folder.

", - "event": "click" - }, - { - "element": "[data-element='editor-media'] [data-element='editor-name-field']", - "title": "Enter a name", - "content": "

Enter My Images in the field.

", - "view": "foldername" - }, - { - "element": "[data-element='editor-media'] [data-element='button-save']", - "title": "Save the folder", - "content": "

Click the Save button to create the new folder.

", - "event": "click" - }, - { - "element": "[data-element='editor-media'] [data-element='dropzone']", - "title": "Upload images", - "content": "

In the upload area you can upload your media items.

Click the Click here to choose files button and select a couple of images on your computer and upload them.

", - "view": "uploadimages" - }, - { - "element": "[data-element='editor-media'] [data-element='media-grid-item-0']", - "title": "View media item details", - "content": "Hover over the media item and Click the white bar to view details about the media item.", - "event": "click", - "eventElement": "[data-element='editor-media'] [data-element='media-grid-item-0'] [data-element='media-grid-item-edit']" - }, - { - "element": "[data-element='editor-media'] [data-element='property-umbracoFile']", - "elementPreventClick": true, - "title": "The uploaded image", - "content": "

Here you can see the image you have uploaded.

" - }, - { - "element": "[data-element='editor-media'] [data-element='property-umbracoBytes']", - "title": "Image size", - "content": "

You will also find other details about the image, like the size.

Media items work in much the same way as content. So you can add extra properties to an image by creating or editing the Media types in the Settings section.

" - }, - { - "element": "[data-element='editor-media'] [data-element='sub-view-umbInfo']", - "title": "Info", - "content": "Like the content section you can also find default information about the media item. You will find these under the info app.", - "event": "click" - }, - { - "element": "[data-element='editor-media'] [data-element='node-info-urls']", - "title": "Link to media", - "content": "The path to the media item..." - }, - { - "element": "[data-element='editor-media'] [data-element='node-info-update-date']", - "title": "Last edited", - "content": "...and information about when the media item has been created and edited." - }, - { - "element": "[data-element='editor-container']", - "elementPreventClick": true, - "title": "Using media items", - "content": "You can reference a media item directly in a template by using the path or try adding a Media Picker to a document type property so you can select media items from the content section." - } - ] - } -] From 586c61f2827d233ead054fae6c2fc8e6f0d70274 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 5 Oct 2020 07:50:55 +0200 Subject: [PATCH 51/53] moved getting-started.json from old to new project Signed-off-by: Bjarke Berg --- src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj | 1 - .../config/BackOfficeTours/getting-started.json | 0 2 files changed, 1 deletion(-) rename src/{Umbraco.Web.UI => Umbraco.Web.UI.NetCore}/config/BackOfficeTours/getting-started.json (100%) 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 e68bab7db8..1af278cbc3 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -22,7 +22,6 @@
- diff --git a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json b/src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json similarity index 100% rename from src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json rename to src/Umbraco.Web.UI.NetCore/config/BackOfficeTours/getting-started.json From 375a85903fd4cabe744bc08dc1e2429d9c91c991 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 5 Oct 2020 10:02:11 +0200 Subject: [PATCH 52/53] Changed the UmbracoIntegrationTest setup to be sync, to avoid issue with AsyncLocal Signed-off-by: Bjarke Berg --- src/Umbraco.Core/Scoping/CallContext.cs | 10 +++++++++- .../Services/Implement/UserService.cs | 4 ++-- .../TestServerTest/UmbracoTestServerTestBase.cs | 4 +--- .../Testing/UmbracoIntegrationTest.cs | 5 +++-- src/Umbraco.Web.Common/Security/BackofficeSecurity.cs | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/Scoping/CallContext.cs b/src/Umbraco.Core/Scoping/CallContext.cs index 2937990eab..cc8bf7cc7e 100644 --- a/src/Umbraco.Core/Scoping/CallContext.cs +++ b/src/Umbraco.Core/Scoping/CallContext.cs @@ -20,7 +20,15 @@ namespace Umbraco.Core.Scoping /// The name with which to associate the new item in the call context. /// The object to store in the call context. public static void SetData(string name, T data) => _state.GetOrAdd(name, _ => new AsyncLocal()).Value = data; - + + //Replace the SetData with the following when you need to debug AsyncLocal. The args.ThreadContextChanged can be usefull + //public static void SetData(string name, T data) => _state.GetOrAdd(name, _ => new AsyncLocal(OnValueChanged)).Value = data; + // public static void OnValueChanged(AsyncLocalValueChangedArgs args) + // { + // var typeName = typeof(T).ToString(); + // Console.WriteLine($"OnValueChanged!, Type: {typeName} Prev: #{args.PreviousValue} Current: #{args.CurrentValue}"); + // } + /// /// Retrieves an object with the specified name from the . /// diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index 1928ea3c12..65fb235054 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -998,7 +998,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - public static EntityPermissionSet CalculatePermissionsForPathForUser( + internal static EntityPermissionSet CalculatePermissionsForPathForUser( EntityPermission[] groupPermissions, int[] pathIds) { @@ -1075,7 +1075,7 @@ namespace Umbraco.Core.Services.Implement /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set /// /// - public static EntityPermission GetPermissionsForPathForGroup( + internal static EntityPermission GetPermissionsForPathForGroup( IEnumerable pathPermissions, int[] pathIds, bool fallbackToDefaultPermissions = false) diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 9f10ce968e..2aacd7b8fb 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -31,7 +31,7 @@ namespace Umbraco.Tests.Integration.TestServerTest public abstract class UmbracoTestServerTestBase : UmbracoIntegrationTest { [SetUp] - public override Task Setup() + public override void Setup() { InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = null; InMemoryConfiguration["Umbraco:CMS:Hosting:Debug"] = "true"; @@ -55,8 +55,6 @@ namespace Umbraco.Tests.Integration.TestServerTest }); LinkGenerator = Factory.Services.GetRequiredService(); - - return Task.CompletedTask; } public override IHostBuilder CreateHostBuilder() diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 1dae786d01..4448308a2e 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -46,6 +46,7 @@ namespace Umbraco.Tests.Integration.Testing [NonParallelizable] public abstract class UmbracoIntegrationTest { + public static LightInjectContainer CreateUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory) { var container = UmbracoServiceProviderFactory.CreateServiceContainer(); @@ -80,10 +81,10 @@ namespace Umbraco.Tests.Integration.Testing } [SetUp] - public virtual async Task Setup() + public virtual void Setup() { var hostBuilder = CreateHostBuilder(); - var host = await hostBuilder.StartAsync(); + var host = hostBuilder.StartAsync().GetAwaiter().GetResult(); Services = host.Services; var app = new ApplicationBuilder(host.Services); Configure(app); diff --git a/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs index 6587501be7..c16071b68a 100644 --- a/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs +++ b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs @@ -66,7 +66,7 @@ namespace Umbraco.Web.Common.Security /// public Attempt GetUserId() { - var identity = _httpContextAccessor.GetRequiredHttpContext().GetCurrentIdentity(); + var identity = _httpContextAccessor.HttpContext?.GetCurrentIdentity(); return identity == null ? Attempt.Fail() : Attempt.Succeed(identity.Id); } From 74f7a2784cfe3ed4ed376d1b212400b9c7a0cf83 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 5 Oct 2020 10:44:28 +0200 Subject: [PATCH 53/53] Handle null user in GetPermissionsForPath Signed-off-by: Bjarke Berg --- src/Umbraco.Infrastructure/Services/Implement/UserService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index 65fb235054..5ad543dcba 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -948,7 +948,7 @@ namespace Umbraco.Core.Services.Implement { var nodeIds = path.GetIdsFromPathReversed(); - if (nodeIds.Length == 0) + if (nodeIds.Length == 0 || user is null) return EntityPermissionSet.Empty(); //collect all permissions structures for all nodes for all groups belonging to the user